diff options
author | Willem Jan Palenstijn <WillemJan.Palenstijn@uantwerpen.be> | 2013-07-01 22:34:11 +0000 |
---|---|---|
committer | wpalenst <WillemJan.Palenstijn@uantwerpen.be> | 2013-07-01 22:34:11 +0000 |
commit | b2fc6c70434674d74551c3a6c01ffb3233499312 (patch) | |
tree | b17f080ebc504ab85ebb7c3d89f917fd87ce9e00 | |
download | astra-b2fc6c70434674d74551c3a6c01ffb3233499312.tar.gz astra-b2fc6c70434674d74551c3a6c01ffb3233499312.tar.bz2 astra-b2fc6c70434674d74551c3a6c01ffb3233499312.tar.xz astra-b2fc6c70434674d74551c3a6c01ffb3233499312.zip |
Update version to 1.3
388 files changed, 89656 insertions, 0 deletions
@@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/NEWS.txt b/NEWS.txt new file mode 100644 index 0000000..d11238f --- /dev/null +++ b/NEWS.txt @@ -0,0 +1,23 @@ +----------------------------------------------------------------------- +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox") + +Copyright: iMinds-Vision Lab, University of Antwerp +License: Open Source under GPLv3 +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + http://code.google.com/p/astra-toolbox/ +----------------------------------------------------------------------- + +1.3 (2013-07-02) + * various consistency and bug fixes + * add a version of the DART algorithm (written by Wim van Aarle) + +1.2 (2013-03-01) + * various consistency and bug fixes + +1.1 (2012-10-24) + * add support for matlab single arrays in mex interface + +1.0 (2012-08-22) + * first public release diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..67a673b --- /dev/null +++ b/README.txt @@ -0,0 +1,100 @@ +----------------------------------------------------------------------- +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox") + +Copyright: iMinds-Vision Lab, University of Antwerp +License: Open Source under GPLv3 +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + http://code.google.com/p/astra-toolbox/ +----------------------------------------------------------------------- + + +The ASTRA Toolbox is a MATLAB toolbox of high-performance GPU primitives +for 2D and 3D tomography. + +We support 2D parallel and fan beam geometries, and 3D parallel and cone beam. +All of them have highly flexible source/detector positioning. + +A large number of 2D and 3D algorithms are available, including FBP, SIRT, +SART, CGLS. + +The basic forward and backward projection operations are GPU-accelerated, +and directly callable from MATLAB to enable building new algorithms. + + + + +Documentation / samples: +------------------------- + +See the matlab code samples in samples/ and on +http://code.google.com/p/astra-toolbox/ . + + + + + +Installation instructions: +--------------------------- + + +Windows, binary: +----------------- + +Add the mex and tools subdirectories to your matlab path. + + + +Linux, from source: +-------------------- + +Requirements: g++, boost, CUDA (driver+toolkit), matlab + +cd build/linux +./configure --with-cuda=/usr/local/cuda \ + --with-matlab=/usr/local/MATLAB/R2012a \ + --prefix=/usr/local/astra +make +make install +Add /usr/local/astra/lib to your LD_LIBRARY_PATH. +Add /usr/local/astra/matlab and its subdirectories (tools, mex) + to your matlab path. + + +NB: Each matlab version only supports a specific range of g++ versions. +Despite this, if you have a newer g++ and if you get errors related to missing +GLIBCXX_3.4.xx symbols, it is often possible to work around this requirement +by deleting the version of libstdc++ supplied by matlab in +MATLAB_PATH/bin/glnx86 or MATLAB_PATH/bin/glnxa64 (at your own risk). + + +Windows, from source using Visual Studio 2008: +----------------------------------------------- + +Requirements: Visual Studio 2008, boost, CUDA (driver+toolkit), matlab. +Note that a .zip with all required (and precompiled) boost files is + available from our website. + +Set the environment variable MATLAB_ROOT to your matlab install location. +Open astra_vc08.sln in Visual Studio. +Select the appropriate solution configuration. + (typically Release_CUDA|win32 or Release_CUDA|x64) +Build the solution. +Install by copying AstraCuda32.dll or AstraCuda64.dll from bin/ and + all .mexw32 or .mexw64 files from bin/Release_CUDA or bin/Debug_CUDA + and the entire matlab/tools directory to a directory to be added to + your matlab path. + + +References: +------------ + +If you use parallel beam GPU code for your research, we would appreciate it if +you would refer to the following paper: + +W. J. Palenstijn, K J. Batenburg, and J. Sijbers, "Performance improvements +for iterative electron tomography reconstruction using graphics processing +units (GPUs)", Journal of Structural Biology, vol. 176, issue 2, pp. 250-253, +2011 + diff --git a/astra_vc08.sln b/astra_vc08.sln new file mode 100644 index 0000000..60f2e25 --- /dev/null +++ b/astra_vc08.sln @@ -0,0 +1,215 @@ +
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "astra_mex", "astra_mex", "{33EF0AC5-B475-40BF-BAE5-67075B204D10}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_matrix", "matlab\mex\astra_mex_matrix_vc08.vcproj", "{9D041710-2119-4230-BCF2-5FBE753FDE49}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra", "astra_vc08.vcproj", "{12926444-6723-46A8-B388-12E65E0577FA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests\tests_vc08.vcproj", "{32C1BDD3-38C2-4C80-A03C-2129782F59B5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_projector", "matlab\mex\astra_mex_projector_vc08.vcproj", "{4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_projector3d", "matlab\mex\astra_mex_projector3d_vc08.vcproj", "{F94CCD79-AA11-42DF-AC8A-6C9D2238A883}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_data3d", "matlab\mex\astra_mex_data3d_vc08.vcproj", "{0BEC029B-0929-4BF9-BD8B-9C9806A52065}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_data2d", "matlab\mex\astra_mex_data2d_vc08.vcproj", "{E4092269-B19C-46F7-A84E-4F146CC70E44}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_algorithm", "matlab\mex\astra_mex_algorithm_vc08.vcproj", "{056BF7A9-294D-487C-8CC3-BE629077CA94}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex", "matlab\mex\astra_mex_vc08.vcproj", "{3FDA35E0-0D54-4663-A3E6-5ABA96F32221}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_CUDA|Win32 = Debug_CUDA|Win32
+ Debug_CUDA|x64 = Debug_CUDA|x64
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release_CUDA|Win32 = Release_CUDA|Win32
+ Release_CUDA|x64 = Release_CUDA|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|Win32.Build.0 = Debug|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|x64.ActiveCfg = Debug|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|x64.Build.0 = Debug|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|Win32.ActiveCfg = Release|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|Win32.Build.0 = Release|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|x64.ActiveCfg = Release|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|x64.Build.0 = Release|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|Win32.Build.0 = Debug|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|x64.ActiveCfg = Debug|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|x64.Build.0 = Debug|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|Win32.ActiveCfg = Release|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|Win32.Build.0 = Release|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|x64.ActiveCfg = Release|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|x64.Build.0 = Release|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|Win32.Build.0 = Debug|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|x64.ActiveCfg = Debug|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|x64.Build.0 = Debug|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release|Win32.ActiveCfg = Release|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release|Win32.Build.0 = Release|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release|x64.ActiveCfg = Release|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|Win32.Build.0 = Debug|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|x64.ActiveCfg = Debug|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|x64.Build.0 = Debug|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|Win32.ActiveCfg = Release|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|Win32.Build.0 = Release|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|x64.ActiveCfg = Release|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|x64.Build.0 = Release|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|Win32.Build.0 = Debug|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|x64.ActiveCfg = Debug|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|x64.Build.0 = Debug|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|Win32.ActiveCfg = Release|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|Win32.Build.0 = Release|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|x64.ActiveCfg = Release|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|x64.Build.0 = Release|x64
+
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|Win32.Build.0 = Debug|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|x64.ActiveCfg = Debug|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|x64.Build.0 = Debug|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|Win32.ActiveCfg = Release|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|Win32.Build.0 = Release|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|x64.ActiveCfg = Release|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|x64.Build.0 = Release|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|Win32.Build.0 = Debug|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|x64.ActiveCfg = Debug|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|x64.Build.0 = Debug|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|Win32.ActiveCfg = Release|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|Win32.Build.0 = Release|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|x64.ActiveCfg = Release|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|x64.Build.0 = Release|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|Win32.ActiveCfg = Debug|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|Win32.Build.0 = Debug|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|x64.ActiveCfg = Debug|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|x64.Build.0 = Debug|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|Win32.ActiveCfg = Release|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|Win32.Build.0 = Release|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|x64.ActiveCfg = Release|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|x64.Build.0 = Release|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|Win32.Build.0 = Debug|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|x64.ActiveCfg = Debug|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|x64.Build.0 = Debug|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|Win32.ActiveCfg = Release|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|Win32.Build.0 = Release|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|x64.ActiveCfg = Release|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9D041710-2119-4230-BCF2-5FBE753FDE49} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {E4092269-B19C-46F7-A84E-4F146CC70E44} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {056BF7A9-294D-487C-8CC3-BE629077CA94} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ EndGlobalSection
+EndGlobal
diff --git a/astra_vc08.vcproj b/astra_vc08.vcproj new file mode 100644 index 0000000..441262f --- /dev/null +++ b/astra_vc08.vcproj @@ -0,0 +1,3146 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="astra"
+ ProjectGUID="{12926444-6723-46A8-B388-12E65E0577FA}"
+ RootNamespace="astra"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ <ToolFile
+ RelativePath=".\build\Cuda.rules"
+ />
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="DLL_EXPORTS"
+ ExceptionHandling="1"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\win32\Astra32.dll"
+ AdditionalLibraryDirectories="".\lib\win32""
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="DLL_EXPORTS"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\x64\Astra64.dll"
+ AdditionalLibraryDirectories="".\lib\x64""
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Runtime="2"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS"
+ ExceptionHandling="1"
+ RuntimeLibrary="2"
+ CallingConvention="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cudart.lib cufft.lib"
+ OutputFile="bin\win32\AstraCuda32.dll"
+ AdditionalLibraryDirectories="".\lib\win32";"$(CUDA_LIB_PATH)";"$(NVSDKCOMPUTE_ROOT)"/C/common/lib"
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Runtime="2"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cudart.lib cufft.lib"
+ OutputFile="bin\x64\AstraCuda64.dll"
+ AdditionalLibraryDirectories="".\lib\x64";"$(CUDA_LIB_PATH)";"$(NVSDKCOMPUTE_ROOT)"/C/common/lib"
+ GenerateManifest="true"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Debug="true"
+ Defines="-DDLL_EXPORTS"
+ Optimization="0"
+ Runtime="3"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="0"
+ OmitFramePointers="false"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS;_DEBUG"
+ ExceptionHandling="1"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ CallingConvention="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cufft.lib cudart.lib"
+ OutputFile="bin\win32\AstraCuda32D.dll"
+ AdditionalLibraryDirectories="".\lib\win32";"$(CUDA_LIB_PATH)";"$(NVSDKCOMPUTE_ROOT)"/C/common/lib"
+ GenerateManifest="true"
+ IgnoreAllDefaultLibraries="false"
+ IgnoreDefaultLibraryNames=""
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda;include;lib\include"
+ Debug="true"
+ Defines="-DDLL_EXPORTS"
+ Optimization="0"
+ Runtime="3"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS;_DEBUG"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cudart.lib cufft.lib"
+ OutputFile="bin\x64\AstraCuda64D.dll"
+ AdditionalLibraryDirectories="".\lib\x64";"$(CUDA_LIB_PATH)";"$(NVSDKCOMPUTE_ROOT)"/C/common/lib"
+ GenerateManifest="true"
+ IgnoreAllDefaultLibraries="false"
+ IgnoreDefaultLibraryNames=""
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ FavorSizeOrSpeed="0"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="_DEBUG;DLL_EXPORTS"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ EnablePREfast="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\win32\Astra32D.dll"
+ AdditionalLibraryDirectories="".\lib\win32""
+ GenerateManifest="true"
+ DelayLoadDLLs=""
+ GenerateDebugInformation="true"
+ GenerateMapFile="false"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="_DEBUG;DLL_EXPORTS"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\x64\Astra64D.dll"
+ AdditionalLibraryDirectories="".\lib\x64""
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\src\astra.def"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Algorithms"
+ >
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\Algorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\AlgorithmTypelist.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ArtAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\AsyncAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\BackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CglsAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FilteredBackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ForwardProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Fourier.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ReconstructionAlgorithm2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ReconstructionAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SartAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SirtAlgorithm.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\Algorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ArtAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\AsyncAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\BackProjectionAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\CglsAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FilteredBackProjectionAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ForwardProjectionAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Fourier.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ReconstructionAlgorithm2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ReconstructionAlgorithm3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SartAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SirtAlgorithm.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Projectors"
+ >
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\DataProjector.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\DataProjectorPolicies.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamLineKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamStripKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamBlobKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLinearKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLineKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamStripKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Projector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Projector3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ProjectorTypelist.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrixProjector2D.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\DataProjector.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\DataProjectorPolicies.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatBeamLineKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatBeamStripKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamBlobKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamLinearKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamLineKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamStripKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Projector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Projector3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SparseMatrixProjector2D.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Inline Files"
+ >
+ <File
+ RelativePath=".\include\astra\DataProjectorPolicies.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamLineKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamStripKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLinearKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLineKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamStripKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Projector2DImpl.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrixProjector2D.inl"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Global & Other"
+ >
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\AstraObjectFactory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\AstraObjectManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Config.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Globals.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Logger.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\PlatformDepSystemCode.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Utilities.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\XMLDocument.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\XMLNode.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\AstraObjectFactory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\AstraObjectManager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Globals.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Logger.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\PlatformDepSystemCode.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Singleton.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\TypeList.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\XMLDocument.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\XMLNode.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="CUDA"
+ >
+ <Filter
+ Name="CUDA source"
+ >
+ <File
+ RelativePath=".\cuda\2d\algo.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\algo3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\arith.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\arith3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\astra.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\astra3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\cgls.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cgls3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\darthelper.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\darthelper3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\em.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\fdk.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fft.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sart.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sirt.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\sirt3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\util.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\util3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="headers"
+ >
+ <File
+ RelativePath=".\cuda\2d\algo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\algo3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\arith.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\arith3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\astra.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\astra3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\cgls.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cgls3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\darthelper.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\darthelper3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\dims.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\dims3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\em.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fbp_filters.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fft.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sart.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sirt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\sirt3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\util.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\util3d.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="astra code"
+ >
+ <Filter
+ Name="headers"
+ >
+ <File
+ RelativePath=".\include\astra\CudaBackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaBackProjectionAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaCglsAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaCglsAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartMaskAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartMaskAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartSmoothingAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartSmoothingAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaEMAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaFDKAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaFilteredBackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaForwardProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaForwardProjectionAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaProjector3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaReconstructionAlgorithm2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaSartAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaSirtAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaSirtAlgorithm3D.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="source"
+ >
+ <File
+ RelativePath=".\src\CudaBackProjectionAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaBackProjectionAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaCglsAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaCglsAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartMaskAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartMaskAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartSmoothingAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartSmoothingAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDataOperationAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaEMAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaFDKAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaFilteredBackProjectionAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaForwardProjectionAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaForwardProjectionAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaProjector2D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaProjector3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaReconstructionAlgorithm2D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaRoiSelectAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaSartAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaSirtAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaSirtAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Data & Geometry Objects"
+ >
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\ConeProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ConeVecProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatVecProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data3DMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32ProjectionData2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32ProjectionData3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32ProjectionData3DMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32VolumeData2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32VolumeData3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32VolumeData3DMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelVecProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrix.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrixProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Vector3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\VolumeGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\VolumeGeometry3D.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\ConeProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ConeVecProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatVecProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data3DMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32ProjectionData2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32ProjectionData3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32ProjectionData3DMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32VolumeData2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32VolumeData3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32VolumeData3DMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelVecProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SparseMatrix.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SparseMatrixProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Vector3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\VolumeGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\VolumeGeometry3D.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/build/Cuda.rules b/build/Cuda.rules new file mode 100644 index 0000000..733aa1f --- /dev/null +++ b/build/Cuda.rules @@ -0,0 +1,358 @@ +<?xml version="1.0" encoding="utf-8"?> +<VisualStudioToolFile + Name="CUDA Build Rule v2.1.0" + Version="8,00" + > + <Rules> + <CustomBuildRule + Name="CUDA Build Rule" + DisplayName="CUDA Build Rule v2.1.0" + CommandLine="echo [CompilerPath] [Keep] [ExtraNvccOptions] [Platform] [Arch] -ccbin "$(VCInstallDir)bin" [Emulation] [FastMath] [Defines] -Xcompiler "/EHsc [Warning] /nologo [Optimization] /Zi [RuntimeChecks] [Runtime] [TypeInfo] [ExtraCppOptions]" [Include] [MaxRegCount] [PtxAsOptionV] [NvccCompilation] "$(InputPath)" 
 [CompilerPath] [Keep] [ExtraNvccOptions] [Platform] [Arch] -ccbin "$(VCInstallDir)bin" [Emulation] [FastMath] [Defines] -Xcompiler "/EHsc [Warning] /nologo [Optimization] /Zi [RuntimeChecks] [Runtime] [TypeInfo] [ExtraCppOptions]" [Include] [MaxRegCount] [ptxasoptionv] [NvccCompilation] "$(InputPath)" " + Outputs="[compileout]" + AdditionalDependencies="[AddedDependencies]" + FileExtensions="*.cu" + ExecutionDescription="Compiling with CUDA Build Rule..." + > + <Properties> + <StringProperty + Name="Include" + DisplayName="Additional Include Directories" + Description="Specifies one or more directories to add to the include path; use semi-colon delimited list if more than one. (/I[path])" + Switch="-I[value]" + DefaultValue=""$(CUDA_INC_PATH)"" + Delimited="true" + Delimiters=";" + Inheritable="true" + /> + <BooleanProperty + Name="Debug" + DisplayName="Generate Debug Information" + Description="Specifies whether or not debugging information is generated by the CUDA compiler. (-D_DEBUG)" + Switch="-D_DEBUG" + /> + <EnumProperty + Name="NvccCompilation" + DisplayName="NVCC Compilation Type" + Description="Select desired output of NVCC compilation (-c/-compile, -cuda, -gpu, -cubin, -ptx)" + > + <Values> + <EnumValue + Value="0" + Switch="--compile -o "$(IntDir)\$(InputName).cu.obj"" + DisplayName="Generate hybrid object file (--compile / -c)" + /> + <EnumValue + Value="1" + Switch="-cuda -o "$(IntDir)\$(InputName).cu.c"" + DisplayName="Generate hybrid .c file (-cuda)" + /> + <EnumValue + Value="2" + Switch="-gpu -o "$(IntDir)\$(InputName).gpu"" + DisplayName="Generate .gpu file (-gpu)" + /> + <EnumValue + Value="3" + Switch="-m32 -cubin -o "data\$(InputName).cubin"" + DisplayName="Generate .cubin file (-cubin)" + /> + <EnumValue + Value="4" + Switch="-ptx -o "$(IntDir)\$(InputName).ptx"" + DisplayName="Generate .ptx file (-ptx)" + /> + </Values> + </EnumProperty> + <EnumProperty + Name="compileout" + DisplayName="Compiler Output (obj/cubin)" + Description="Sets output as an OBJ or cubin file" + > + <Values> + <EnumValue + Value="0" + Switch=""$(IntDir)/$(InputName).cu.obj"" + DisplayName=""$(IntDir)/$(InputName).cu.obj"" + /> + <EnumValue + Value="1" + Switch=""data/$(InputName).cubin"" + DisplayName=""data/$(InputName).cubin"" + /> + </Values> + </EnumProperty> + <EnumProperty + Name="Arch" + DisplayName="GPU Architecture" + Description="Select option for the GPU architecture to use on the command line (-arch sm_10, sm_11, sm_12, sm_13)" + DefaultValue="10" + > + <Values> + <EnumValue + Value="10" + Switch="-arch sm_10" + DisplayName="sm_10" + /> + <EnumValue + Value="11" + Switch="-arch sm_11" + DisplayName="sm_11" + /> + <EnumValue + Value="12" + Switch="-arch sm_12" + DisplayName="sm_12" + /> + <EnumValue + Value="13" + Switch="-arch sm_13" + DisplayName="sm_13" + /> + </Values> + </EnumProperty> + <EnumProperty + Name="CompilerPath" + DisplayName="Path to nvcc.exe" + Description="Specifies the path to the CUDA compiler, nvcc.exe " + > + <Values> + <EnumValue + Value="0" + Switch=""$(CUDA_BIN_PATH)\nvcc.exe"" + DisplayName="Installed Toolkit (uses CUDA_BIN_PATH environment varible)" + /> + <EnumValue + Value="1" + Switch=""[AlternateNvccPath]"" + DisplayName="Use Alternate path to CUDA, specified below" + /> + </Values> + </EnumProperty> + <StringProperty + Name="AlternateNvccPath" + DisplayName="Alternate path to nvcc.exe (non-standard installation)" + Switch="[value]\nvcc.exe" + /> + <BooleanProperty + Name="Emulation" + DisplayName="Emulation Mode" + Description="Whether or not to generate emulated code." + Switch="-deviceemu -D_DEVICEEMU" + /> + <BooleanProperty + Name="FastMath" + DisplayName="Use Fast Math" + Category="Default" + Description="Make use of the fast math library." + Switch="-use_fast_math" + /> + <IntegerProperty + Name="MaxRegCount" + DisplayName="maxrregcount" + Switch="-maxrregcount=[Value]" + DefaultValue="32" + /> + <BooleanProperty + Name="PtxAsOptionV" + DisplayName="PtxAsOptionV" + Switch="--ptxas-options=-v" + /> + <StringProperty + Name="ExtraNvccOptions" + DisplayName="Extra Options" + Description="Supply any additional command line options to NVCC" + Switch="[value]" + /> + <StringProperty + Name="Defines" + DisplayName="Preprocessor Definitions" + PropertyPageName="Preprocessor" + Description="Specifies one or more preprocessor defines. (-D[macro])" + Switch="-D[value]" + Delimited="true" + Inheritable="true" + /> + <BooleanProperty + Name="Keep" + DisplayName="Keep preprocessed files (.ptx, .cubin, cudafe1.c, cudafe1.cpp, cudafe1.gpu, etc.)" + PropertyPageName="Preprocessor" + Description="Specifies that preprocessor files generated by the CUDA compiler are not deleted." + Switch="--keep" + /> + <EnumProperty + Name="Warning" + DisplayName="Warning Level" + PropertyPageName="Hybrid CUDA/C++ Options" + Description="Select how strict you want the compiler to be about checking for potentially suspect constructs. (/W0 - /W4)" + DefaultValue="3" + > + <Values> + <EnumValue + Value="0" + Switch="/W0" + DisplayName="Off: Turn Off All Warnings (/W0)" + /> + <EnumValue + Value="1" + Switch="/W1" + DisplayName="Level 1 (/W1)" + /> + <EnumValue + Value="2" + Switch="/W2" + DisplayName="Level 2 (/W2)" + /> + <EnumValue + Value="3" + Switch="/W3" + DisplayName="Level 3 (/W3)" + /> + <EnumValue + Value="4" + Switch="/W4" + DisplayName="Level 4 (/W4)" + /> + </Values> + </EnumProperty> + <EnumProperty + Name="Optimization" + DisplayName="Optimization" + Description="Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox)" + DefaultValue="2" + > + <Values> + <EnumValue + Value="0" + Switch="/Od" + DisplayName="Disabled (/Od)" + /> + <EnumValue + Value="1" + Switch="/O1" + DisplayName="Minimize Size (/O1)" + /> + <EnumValue + Value="2" + Switch="/O2" + DisplayName="Maximize Speed (/O2)" + /> + <EnumValue + Value="3" + Switch="/Ox" + DisplayName="Full Optimization (/Ox)" + /> + </Values> + </EnumProperty> + <StringProperty + Name="AddedDependencies" + DisplayName="Source Dependencies" + Description="Add additional CUDA file dependencies" + Switch="[value]" + /> + <EnumProperty + Name="RuntimeChecks" + DisplayName="Basic Runtime Checks" + PropertyPageName="Hybrid CUDA/C++ Options" + Description="Perform basic runtime error checks, incompatible with any optimization type other than debug. (/RTCs, /RTCu, /RTC1)" + > + <Values> + <EnumValue + Value="0" + Switch=" " + DisplayName="Default" + /> + <EnumValue + Value="1" + Switch="/RTCs" + DisplayName="Stack Frames (/RTCs)" + /> + <EnumValue + Value="2" + Switch="/RTCu" + DisplayName="Uninitialized Variables (/RTCu)" + /> + <EnumValue + Value="3" + Switch="/RTC1" + DisplayName="Both (/RTC1, equiv. to /RTCsu)" + /> + </Values> + </EnumProperty> + <EnumProperty + Name="Runtime" + DisplayName="Runtime Library" + PropertyPageName="Hybrid CUDA/C++ Options" + Description="Specify runtime library for linking. (/MT, /MTd, /MD, /MDd, /ML, /MLd)" + > + <Values> + <EnumValue + Value="0" + Switch="/MT" + DisplayName="Multi-Threaded (/MT)" + /> + <EnumValue + Value="1" + Switch="/MTd" + DisplayName="Multi-Threaded Debug (/MTd)" + /> + <EnumValue + Value="2" + Switch="/MD" + DisplayName="Multi-Threaded DLL (/MD)" + /> + <EnumValue + Value="3" + Switch="/MDd" + DisplayName="Multi-Threaded Debug DLL (/MDd)" + /> + <EnumValue + Value="4" + Switch="/ML" + DisplayName="Single-Threaded (/ML)" + /> + <EnumValue + Value="5" + Switch="/MLd" + DisplayName="Single-Threaded Debug (/MLd)" + /> + </Values> + </EnumProperty> + <BooleanProperty + Name="TypeInfo" + DisplayName="Enable Run-Time Type Info" + PropertyPageName="Hybrid CUDA/C++ Options" + Description="Adds code for checking C++ object types at run time (runtime type information). (/GR)" + Switch="/GR" + /> + <StringProperty + Name="ExtraCppOptions" + DisplayName="Extra C++ Options" + PropertyPageName="Hybrid CUDA/C++ Options" + Description="Supply any additional command line options to the host C++ compiler" + Switch="[value]" + /> + <EnumProperty + Name="Platform" + DisplayName="Platform" + > + <Values> + <EnumValue + Value="0" + DisplayName="Default" + /> + <EnumValue + Value="1" + Switch="-m32" + DisplayName="Win32" + /> + <EnumValue + Value="2" + Switch="-m64" + DisplayName="x64" + /> + </Values> + </EnumProperty> + </Properties> + </CustomBuildRule> + </Rules> +</VisualStudioToolFile> diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in new file mode 100644 index 0000000..943e10c --- /dev/null +++ b/build/linux/Makefile.in @@ -0,0 +1,314 @@ +cuda=@HAVECUDA@ +matlab=@HAVEMATLAB@ + +MATLAB_ROOT=@MATLAB_ROOT@ + +TARGETS=libastra.la + +ifeq ($(matlab),yes) +TARGETS+=mex +endif + +all: $(TARGETS) + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +VPATH=../.. + +CPPFLAGS=@SAVED_CPPFLAGS@ +CXXFLAGS=@SAVED_CXXFLAGS@ +LDFLAGS=@SAVED_LDFLAGS@ + +CPPFLAGS+=-I../.. -I../../include -I../../lib/include/rapidxml +CXXFLAGS+=-g -O3 -Wall -Wshadow +LIBS=-lpthread -lrt +LDFLAGS+=-g + +ifeq ($(cuda),yes) +CPPFLAGS += @CPPFLAGS_CUDA@ -DASTRA_CUDA +NVCCFLAGS = @NVCCFLAGS@ @CPPFLAGS_CUDA@ -I../.. -I../../include -DASTRA_CUDA +LDFLAGS += @LDFLAGS_CUDA@ +LIBS += -lcudart -lcufft +NVCC = @NVCC@ +endif + +ifeq ($(matlab),yes) +CPPFLAGS+=-I$(MATLAB_ROOT)/extern/include -DMATLAB_MEX_FILE +endif + +TNT_CPPFLAGS=@TNT_CPPFLAGS@ +BOOST_CPPFLAGS= +BOOST_LDFLAGS= + + +CPPFLAGS+=$(TNT_CPPFLAGS) $(BOOST_CPPFLAGS) +LDFLAGS+=$(BOOST_LDFLAGS) + + +MKDIR=mkdir -p +CXX=g++ +LD=g++ +SHELL=@SHELL@ + +ifeq ($(matlab),yes) +MEXFLAGS = -cxx +MEXLDFLAGS='$$LDFLAGS $(LDFLAGS) -L.libs -lut' +MEXSUFFIX = @MEXSUFFIX@ +MEX = @MEX@ +endif + +LIBDIR=/usr/local/lib + +DEPDIR=.deps + +BASE_OBJECTS=\ + src/Algorithm.lo \ + src/AsyncAlgorithm.lo \ + src/ReconstructionAlgorithm2D.lo \ + src/ReconstructionAlgorithm3D.lo \ + src/ArtAlgorithm.lo \ + src/AstraObjectFactory.lo \ + src/AstraObjectManager.lo \ + src/BackProjectionAlgorithm.lo \ + src/CglsAlgorithm.lo \ + src/ConeProjectionGeometry3D.lo \ + src/ConeVecProjectionGeometry3D.lo \ + src/Config.lo \ + src/DataProjector.lo \ + src/DataProjectorPolicies.lo \ + src/FanFlatBeamLineKernelProjector2D.lo \ + src/FanFlatBeamStripKernelProjector2D.lo \ + src/FanFlatProjectionGeometry2D.lo \ + src/FanFlatVecProjectionGeometry2D.lo \ + src/FilteredBackProjectionAlgorithm.lo \ + src/Float32Data2D.lo \ + src/Float32Data3D.lo \ + src/Float32Data3DMemory.lo \ + src/Float32Data.lo \ + src/Float32ProjectionData2D.lo \ + src/Float32ProjectionData3D.lo \ + src/Float32ProjectionData3DMemory.lo \ + src/Float32VolumeData2D.lo \ + src/Float32VolumeData3D.lo \ + src/Float32VolumeData3DMemory.lo \ + src/ForwardProjectionAlgorithm.lo \ + src/Fourier.lo \ + src/Globals.lo \ + src/Logger.lo \ + src/ParallelBeamBlobKernelProjector2D.lo \ + src/ParallelBeamLinearKernelProjector2D.lo \ + src/ParallelBeamLineKernelProjector2D.lo \ + src/ParallelBeamStripKernelProjector2D.lo \ + src/ParallelProjectionGeometry2D.lo \ + src/ParallelProjectionGeometry3D.lo \ + src/ParallelVecProjectionGeometry3D.lo \ + src/PlatformDepSystemCode.lo \ + src/ProjectionGeometry2D.lo \ + src/ProjectionGeometry3D.lo \ + src/Projector2D.lo \ + src/Projector3D.lo \ + src/SartAlgorithm.lo \ + src/SirtAlgorithm.lo \ + src/SparseMatrixProjectionGeometry2D.lo \ + src/SparseMatrixProjector2D.lo \ + src/SparseMatrix.lo \ + src/Utilities.lo \ + src/VolumeGeometry2D.lo \ + src/VolumeGeometry3D.lo \ + src/XMLDocument.lo \ + src/XMLNode.lo \ + src/swrap.lo + +CUDA_CXX_OBJECTS=\ + src/CudaProjector2D.lo \ + src/CudaProjector3D.lo \ + src/CudaReconstructionAlgorithm2D.lo \ + src/CudaBackProjectionAlgorithm.lo \ + src/CudaDartMaskAlgorithm.lo \ + src/CudaDartMaskAlgorithm3D.lo \ + src/CudaDataOperationAlgorithm.lo \ + src/CudaRoiSelectAlgorithm.lo \ + src/CudaDartSmoothingAlgorithm.lo \ + src/CudaDartSmoothingAlgorithm3D.lo \ + src/CudaFilteredBackProjectionAlgorithm.lo \ + src/CudaForwardProjectionAlgorithm.lo \ + src/CudaSartAlgorithm.lo \ + src/CudaSirtAlgorithm.lo \ + src/CudaCglsAlgorithm.lo \ + src/CudaCglsAlgorithm3D.lo \ + src/CudaEMAlgorithm.lo \ + src/CudaFDKAlgorithm3D.lo \ + src/CudaSirtAlgorithm3D.lo \ + src/CudaBackProjectionAlgorithm3D.lo \ + src/CudaForwardProjectionAlgorithm3D.lo + +CUDA_OBJECTS=\ + cuda/2d/algo.lo \ + cuda/2d/par_fp.lo \ + cuda/2d/par_bp.lo \ + cuda/2d/fan_fp.lo \ + cuda/2d/fan_bp.lo \ + cuda/2d/sirt.lo \ + cuda/2d/sart.lo \ + cuda/2d/cgls.lo \ + cuda/2d/em.lo \ + cuda/2d/astra.lo \ + cuda/2d/util.lo \ + cuda/2d/arith.lo \ + cuda/2d/fft.lo \ + cuda/2d/darthelper.lo \ + cuda/3d/darthelper3d.lo \ + cuda/3d/algo3d.lo \ + cuda/3d/cgls3d.lo \ + cuda/3d/cone_fp.lo \ + cuda/3d/cone_bp.lo \ + cuda/3d/fdk.lo \ + cuda/3d/par3d_fp.lo \ + cuda/3d/par3d_bp.lo \ + cuda/3d/sirt3d.lo \ + cuda/3d/astra3d.lo \ + cuda/3d/util3d.lo \ + cuda/3d/arith3d.lo + +ALL_OBJECTS=$(BASE_OBJECTS) +ifeq ($(cuda),yes) +ALL_OBJECTS+=$(CUDA_CXX_OBJECTS) $(CUDA_OBJECTS) +endif + +TEST_OBJECTS=\ + tests/main.o \ + tests/test_AstraObjectManager.o \ + tests/test_ParallelBeamLineKernelProjector2D.o \ + tests/test_ParallelBeamLinearKernelProjector2D.o \ + tests/test_Float32Data2D.o \ + tests/test_VolumeGeometry2D.o \ + tests/test_ParallelProjectionGeometry2D.o \ + tests/test_FanFlatProjectionGeometry2D.o \ + tests/test_Float32VolumeData2D.o \ + tests/test_Float32ProjectionData2D.o \ + tests/test_Fourier.o \ + tests/test_XMLDocument.o + +MATLAB_CXX_OBJECTS=\ + matlab/mex/mexHelpFunctions.o + +MATLAB_MEX=\ + matlab/mex/astra_mex_algorithm_c.$(MEXSUFFIX) \ + matlab/mex/astra_mex_data2d_c.$(MEXSUFFIX) \ + matlab/mex/astra_mex_c.$(MEXSUFFIX) \ + matlab/mex/astra_mex_matrix_c.$(MEXSUFFIX) \ + matlab/mex/astra_mex_projector_c.$(MEXSUFFIX) \ + matlab/mex/astra_mex_projector3d_c.$(MEXSUFFIX) \ + matlab/mex/astra_mex_data3d_c.$(MEXSUFFIX) + + +OBJECT_DIRS = src/ tests/ cuda/2d/ cuda/3d/ matlab/mex/ ./ +DEPDIRS = $(addsuffix $(DEPDIR),$(OBJECT_DIRS)) +-include $(wildcard $(addsuffix /*.d,$(DEPDIRS))) +LIBDIRS = $(addsuffix .libs,./ src/ cuda/2d/old/ cuda/2d) + + +ifeq ($(matlab),yes) +mex: $(MATLAB_MEX) + +%.$(MEXSUFFIX): %.o $(MATLAB_CXX_OBJECTS) libastra.la + $(MEX) LDFLAGS=$(MEXLDFLAGS) $(MEXFLAGS) $(LIBS) -lastra -output $* $*.o $(MATLAB_CXX_OBJECTS) +endif + +libastra.la: $(ALL_OBJECTS) + ./libtool --mode=link --tag=CXX $(LD) -rpath $(LIBDIR) -o $@ $(LDFLAGS) $(LIBS) $+ + +%.o: %.cpp + $(MKDIR) $(*D)/$(DEPDIR) + $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) -fPIC -DPIC $(CPPFLAGS) -c $(<) -o $*.o + +%.lo: %.cpp + $(MKDIR) $(*D)/$(DEPDIR) + ./libtool --mode=compile --tag=CXX $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o + +ifeq ($(cuda),yes) +%.lo: %.cu + @# Behave like libtool: compile both a PIC and a non-PIC object file + @$(MKDIR) $(*D) + $(NVCC) $(NVCCFLAGS) -c $(<) -o $*.o + @$(MKDIR) $(*D)/.libs + @$(MKDIR) $(*D)/$(DEPDIR) + @$(NVCC) $(NVCCFLAGS) -c $(<) -Xcompiler -fPIC -DPIC -o $(*D)/.libs/$(*F).o >/dev/null 2>&1 + @# Generate a .d file, and change the target name in it from .o to .lo + @$(NVCC) $(NVCCFLAGS) -M $(<) -odir $(*D) -o $(*D)/$(DEPDIR)/$(*F).d2 + @sed '1s/\.o :/.lo :/' < $(*D)/$(DEPDIR)/$(*F).d2 > $(*D)/$(DEPDIR)/$(*F).d + @rm -f $(*D)/$(DEPDIR)/$(*F).d2 + @# Generate a fake libtool .lo file + @echo "# $*.lo - a libtool object file" > $*.lo + @echo "# Generated by" `./libtool --version | head -n 1` >> $*.lo + @echo "#" >> $*.lo + @echo "# Please DO NOT delete this file!" >> $*.lo + @echo "# It is necessary for linking the library." >> $*.lo + @echo >> $*.lo + @echo "# Name of the PIC object." >> $*.lo + @echo "pic_object='.libs/$(*F).o'" >> $*.lo + @echo >> $*.lo + @echo "# Name of the non-PIC object." >> $*.lo + @echo "non_pic_object='$(*F).o'" >> $*.lo + @# Remove generated .linkinfo file + @rm -f $(*F).linkinfo +endif + +test.bin: $(ALL_OBJECTS) $(TEST_OBJECTS) + ./libtool --mode=link $(LD) -o $@ $(LDFLAGS) $(LIBS) $+ -lboost_unit_test_framework + +test: test.bin + ./test.bin + +clean: + rm -f $(MATLAB_MEX) libastra.la + rm -f $(addsuffix /*.lo,$(OBJECT_DIRS)) + rm -f $(addsuffix /*.o,$(OBJECT_DIRS)) + rm -f $(addsuffix /*.d,$(DEPDIRS)) + rm -f $(addsuffix /*,$(LIBDIRS)) + rm -f $(TEST_OBJECTS) test.bin + +distclean: clean + rm -f config.guess config.sub ltmain.sh libtool install-sh + rm -f config.log config.status + rm -f aclocal.m4 + rm -rf autom4te.cache + rm -f configure Makefile + +install: install-libraries install-matlab + +install-libraries: libastra.la + ./install-sh -m 755 -d @libdir@ + ./libtool --mode=install ./install-sh -m 644 libastra.la @libdir@ + ./libtool --mode=finish @libdir@ + +ifeq ($(matlab),yes) +# TODO: This install location doesn't work well for /usr or /usr/local +install-matlab: $(MATLAB_MEX) + ./install-sh -m 755 -d @prefix@/matlab + ./install-sh -m 755 -d @prefix@/matlab/mex + ./install-sh -m 755 -d @prefix@/matlab/tools + ./install-sh -m 644 $(MATLAB_MEX) @prefix@/matlab/mex + ./install-sh -m 644 ../../matlab/tools/*.m @prefix@/matlab/tools +# TODO: docs +else +install-matlab: +endif + + +Makefile: Makefile.in config.status + CONFIG_HEADERS= CONFIG_LINKS= CONFIG_FILES=$@ $(SHELL) ./config.status + +config.status: configure + @echo "configure script has changed. Re-running it with last parameters" + $(SHELL) ./config.status --recheck + +configure: configure.ac + @echo "configure.ac has been changed. Regenerating configure script" + $(SHELL) ./autogen.sh + +.PHONY: all mex test clean distclean install install-libraries + +# don't remove intermediate files: +.SECONDARY: diff --git a/build/linux/README.txt b/build/linux/README.txt new file mode 100644 index 0000000..9dd7a7a --- /dev/null +++ b/build/linux/README.txt @@ -0,0 +1,20 @@ +Requirements: g++, boost, CUDA (driver+toolkit), +matlab + +cd build/linux +./configure --with-cuda=/usr/local/cuda \ + --with-matlab=/usr/local/MATLAB/R2012a \ + --prefix=/usr/local/astra +make +make install +Add /usr/local/astra/lib to your LD_LIBRARY_PATH. +Add /usr/local/astra/matlab and its subdirectories (tools, mex) + to your matlab path. + + +NB: Each matlab version only supports a specific range of g++ versions. +Despite this, if you have a newer g++ and if you get errors related to missing +GLIBCXX_3.4.xx symbols, it is often possible to work around this requirement +by deleting the version of libstdc++ supplied by matlab in +MATLAB_PATH/bin/glnx86 or MATLAB_PATH/bin/glnxa64 (at your own risk). + diff --git a/build/linux/acinclude.m4 b/build/linux/acinclude.m4 new file mode 100644 index 0000000..5027e85 --- /dev/null +++ b/build/linux/acinclude.m4 @@ -0,0 +1,74 @@ +AC_DEFUN([ASTRA_CHECK_BOOST_THREAD],[ +BOOST_BACKUP_LIBS="$LIBS" +LIBS="$LIBS $1" +AC_LINK_IFELSE([AC_LANG_SOURCE([ +#include <boost/thread.hpp> +int main() +{ + boost::thread t; + boost::posix_time::milliseconds m(1); + t.timed_join(m); + return 0; +} +])],[$2],[$3]) +LIBS="$BOOST_BACKUP_LIBS" +unset BOOST_BACKUP_LIBS +]) + +AC_DEFUN([ASTRA_CHECK_BOOST_UNIT_TEST_FRAMEWORK],[ +BOOST_BACKUP_LIBS="$LIBS" +LIBS="$LIBS $1" +AC_LINK_IFELSE([AC_LANG_SOURCE([ +#define BOOST_TEST_DYN_LINK + +#define BOOST_AUTO_TEST_MAIN + +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/floating_point_comparison.hpp> +])],[$2],[$3]) +LIBS="$BOOST_BACKUP_LIBS" +unset BOOST_BACKUP_LIBS +]) + +dnl ASTRA_CHECK_MEX_SUFFIX(list-of-suffices, variable-to-set) +AC_DEFUN([ASTRA_CHECK_MEX_SUFFIX],[ +cat >conftest.cc <<_ACEOF +extern "C" void mexFunction() { +} +_ACEOF +$CXX -fPIC -c -o conftest.o conftest.cc +$MEX -cxx -output conftest conftest.o +$2="" +for suffix in $1; do + if test -f "conftest.$suffix"; then + $2="$suffix" + rm -f "conftest.$suffix" + fi +done +rm -f conftest.cc conftest.o +]) + +dnl ASTRA_CHECK_NVCC(variable-to-set,cppflags-to-set) +AC_DEFUN([ASTRA_CHECK_NVCC],[ +cat >conftest.cu <<_ACEOF +#include <iostream> +int main() { + std::cout << "Test" << std::endl; + return 0; +} +_ACEOF +$1="yes" +$NVCC -c -o conftest.o conftest.cu $$2 >conftest.nvcc.out 2>&1 || { + $1="no" + # Check if hack for gcc 4.4 helps + if grep -q __builtin_stdarg_start conftest.nvcc.out; then + NVCC_OPT="-Xcompiler -D__builtin_stdarg_start=__builtin_va_start" + $NVCC -c -o conftest.o conftest.cu $$2 $NVCC_OPT >/dev/null 2>&1 && { + $1="yes" + $2="$$2 $NVCC_OPT" + } + fi +} +rm -f conftest.cu conftest.o conftest.nvcc.out +]) diff --git a/build/linux/autogen.sh b/build/linux/autogen.sh new file mode 100755 index 0000000..c856793 --- /dev/null +++ b/build/linux/autogen.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +aclocal +if test $? -ne 0; then + echo "Error running aclocal" + exit 1 +fi + +autoconf +if test $? -ne 0; then + echo "Error running autoconf" + exit 1 +fi + +libtoolize --install --force > /dev/null 2>&1 +if test $? -ne 0; then + libtoolize --force + if test $? -ne 0; then + echo "Error running libtoolize" + exit 1 + fi +fi + +if test ! -e config.guess; then + ln -s config.guess.dist config.guess +fi + +if test ! -e config.sub; then + ln -s config.sub.dist config.sub +fi + +if test ! -e install-sh; then + ln -s install-sh.dist install-sh +fi + +echo "Done." diff --git a/build/linux/config.guess.dist b/build/linux/config.guess.dist new file mode 100755 index 0000000..dc84c68 --- /dev/null +++ b/build/linux/config.guess.dist @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to <config-patches@gnu.org> and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +and + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/linux/config.sub.dist b/build/linux/config.sub.dist new file mode 100755 index 0000000..2a55a50 --- /dev/null +++ b/build/linux/config.sub.dist @@ -0,0 +1,1705 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/linux/configure.ac b/build/linux/configure.ac new file mode 100644 index 0000000..ad1d36c --- /dev/null +++ b/build/linux/configure.ac @@ -0,0 +1,185 @@ +dnl ----------------------------------------------------------------------- +dnl Copyright 2012 iMinds-Vision Lab, University of Antwerp +dnl +dnl Contact: astra@ua.ac.be +dnl Website: http://astra.ua.ac.be +dnl +dnl +dnl This file is part of the +dnl All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). +dnl +dnl The ASTRA Toolbox is free software: you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl The ASTRA Toolbox is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +dnl +dnl ----------------------------------------------------------------------- +dnl $Id$ + +AC_INIT(astra_toolbox, 1.3.0) +AC_CONFIG_SRCDIR([Makefile.in]) +LT_INIT([disable-static]) + +SAVED_CPPFLAGS="$CPPFLAGS" +SAVED_CXXFLAGS="$CXXFLAGS" +SAVED_LDFLAGS="$LDFLAGS" + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_INSTALL +AC_PROG_LIBTOOL +AC_PROG_MAKE_SET + +AC_LANG([C++]) + +dnl Use iostream to check if the C++ compiler works +AC_CHECK_HEADER(iostream, , AC_MSG_ERROR([No working c++ compiler found])) + +dnl TODO: Use ../../lib/include instead of .../tnt once all other +dnl libraries have been moved out of SVN +TNT_CPPFLAGS="-I../../lib/include/tnt -DJAMA_NO_SUBDIR" +CPPFLAGS="$CPPFLAGS $TNT_CPPFLAGS" +AC_CHECK_HEADER(tnt.h, HAVETNT=yes, HAVETNT=no) +AC_CHECK_HEADER(jama_lu.h, HAVEJAMA=yes, HAVEJAMA=no) + +if test x$HAVETNT = xno -o x$HAVEJAMA = xno; then + AC_MSG_ERROR([tnt or jama not found]) +fi +AC_SUBST(TNT_CPPFLAGS) + + + +# boost-unit-test-framework + +AC_MSG_CHECKING([for boost-unit-test-framework]) + +ASTRA_CHECK_BOOST_UNIT_TEST_FRAMEWORK(-lboost_unit_test_framework-mt, BOOSTUTF=yes_mt, BOOSTUTF=no) +if test x$BOOSTUTF = xno; then + ASTRA_CHECK_BOOST_UNIT_TEST_FRAMEWORK(-lboost_unit_test_framework, BOOSTUTF=yes, BOOSTUTF=no) + if test x$BOOSTTHREAD = xno; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([No boost-unit-test-framework library found]) + else + AC_MSG_RESULT([yes, libboost_unit_test_framework]) + LIBS_BOOSTUTF="-lboost_unit_test_framework" + fi +else + AC_MSG_RESULT([yes, libboost_unit_test_framework-mt]) + LIBS_BOOSTUTF="-lboost_unit_test_framework-mt" +fi +# TODO: do something with the result + + +# nvcc, cuda + +AC_ARG_WITH(cuda, [[ --with-cuda=path path of CUDA SDK (optional)]],,) + +NVCC_PATH=$PATH +if test x"$with_cuda" != x; then + NVCC_PATH="$with_cuda/bin:$NVCC_PATH" +fi +AC_PATH_PROG([NVCC], [nvcc], [no], [$NVCC_PATH]) +# TODO: do something with the result + +HAVECUDA=no +if test x"$NVCC" != xno; then + HAVECUDA=yes + BACKUP_CUDA_LDFLAGS="$LDFLAGS" + if test x"$with_cuda" != x; then + LDFLAGS_CUDA="-L$with_cuda/lib" + CPPFLAGS_CUDA="-I$with_cuda/include" + LDFLAGS="$LDFLAGS $LDFLAGS_CUDA" + fi + AC_CHECK_LIB(cudart,cudaMalloc, ,HAVECUDA=no) + AC_CHECK_LIB(cufft,cufftPlan1d, ,HAVECUDA=no) + + if test x"$HAVECUDA" = xno; then + # try lib64 instead of lib + + HAVECUDA=yes + LDFLAGS="$BACKUP_CUDA_LDFLAGS" + + # prevent cached values from being used + unset ac_cv_lib_cudart_cudaMalloc + unset ac_cv_lib_cufft_cufftPlan1d + + LDFLAGS_CUDA="-L$with_cuda/lib64" + LDFLAGS="$LDFLAGS $LDFLAGS_CUDA" + AC_CHECK_LIB(cudart,cudaMalloc, ,HAVECUDA=no) + AC_CHECK_LIB(cufft,cufftPlan1d, ,HAVECUDA=no) + fi + + LDFLAGS="$BACKUP_CUDA_LDFLAGS" + unset BACKUP_CUDA_LDFLAGS + # TODO: check for cuda headers? + + AC_SUBST(NVCC) +fi + +NVCCFLAGS="" +AC_MSG_CHECKING([if nvcc works]) +if test x"$HAVECUDA" = xyes; then + ASTRA_CHECK_NVCC(HAVECUDA,NVCCFLAGS) +fi +AC_MSG_RESULT($HAVECUDA) +AC_SUBST(HAVECUDA) +AC_SUBST(LDFLAGS_CUDA) +AC_SUBST(CPPFLAGS_CUDA) +AC_SUBST(NVCCFLAGS) + + +# mex, matlab + +AC_ARG_WITH(matlab, [[ --with-matlab=path path of Matlab (optional)]],,) + +MEX_PATH=$PATH +HAVEMATLAB=no +if test x"$with_matlab" != x; then + MEX_PATH="$with_matlab/bin:$MEX_PATH" + AC_PATH_PROG([MEX], [mex], [no], [$MEX_PATH]) + if test x"$MEX" != xno; then + HAVEMATLAB=yes + # TODO: check platform of C compiler is same as mex + AC_SUBST(MEX) + MATLAB_ROOT="$with_matlab" + AC_SUBST(MATLAB_ROOT) + + ASTRA_CHECK_MEX_SUFFIX([mexa64 mexglx mexmaci64 mexmaci],[MEXSUFFIX]) + if test x$MEXSUFFIX = x; then + AC_MSG_FAILURE([Unable to determine matlab mex suffix]) + HAVEMATLAB=no + fi + AC_SUBST(MEXSUFFIX) + fi +fi + +AC_SUBST(HAVEMATLAB) + + +# TODO: + +# Detection of tools: +# libtool (how?) + +# options: +# debugging/optimization/profiling flags + + +AC_SUBST(SAVED_CPPFLAGS) +AC_SUBST(SAVED_CXXFLAGS) +AC_SUBST(SAVED_LDFLAGS) + + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/build/linux/install-sh.dist b/build/linux/install-sh.dist new file mode 100755 index 0000000..a5897de --- /dev/null +++ b/build/linux/install-sh.dist @@ -0,0 +1,519 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2006-12-25.00 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/cuda/2d/algo.cu b/cuda/2d/algo.cu new file mode 100644 index 0000000..5ae5d08 --- /dev/null +++ b/cuda/2d/algo.cu @@ -0,0 +1,356 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cassert> + +#include "algo.h" +#include "par_fp.h" +#include "fan_fp.h" +#include "par_bp.h" +#include "fan_bp.h" +#include "util.h" +#include "arith.h" + +namespace astraCUDA { + +ReconAlgo::ReconAlgo() +{ + angles = 0; + TOffsets = 0; + fanProjs = 0; + shouldAbort = false; + + useVolumeMask = false; + useSinogramMask = false; + D_maskData = 0; + D_smaskData = 0; + + D_sinoData = 0; + D_volumeData = 0; + + useMinConstraint = false; + useMaxConstraint = false; + + freeGPUMemory = false; +} + +ReconAlgo::~ReconAlgo() +{ + reset(); +} + +void ReconAlgo::reset() +{ + delete[] angles; + delete[] TOffsets; + delete[] fanProjs; + + if (freeGPUMemory) { + cudaFree(D_maskData); + cudaFree(D_smaskData); + cudaFree(D_sinoData); + cudaFree(D_volumeData); + } + + angles = 0; + TOffsets = 0; + fanProjs = 0; + shouldAbort = false; + + useVolumeMask = false; + useSinogramMask = false; + + D_maskData = 0; + D_smaskData = 0; + + D_sinoData = 0; + D_volumeData = 0; + + useMinConstraint = false; + useMaxConstraint = false; + + freeGPUMemory = false; +} + +bool ReconAlgo::setGPUIndex(int iGPUIndex) +{ + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + return true; +} + +bool ReconAlgo::enableVolumeMask() +{ + useVolumeMask = true; + return true; +} + +bool ReconAlgo::enableSinogramMask() +{ + useSinogramMask = true; + return true; +} + + +bool ReconAlgo::setGeometry(const SDimensions& _dims, const float* _angles) +{ + dims = _dims; + + angles = new float[dims.iProjAngles]; + + memcpy(angles, _angles, sizeof(angles[0]) * dims.iProjAngles); + + delete[] fanProjs; + fanProjs = 0; + + return true; +} + +bool ReconAlgo::setFanGeometry(const SDimensions& _dims, + const SFanProjection* _projs) +{ + dims = _dims; + fanProjs = new SFanProjection[dims.iProjAngles]; + + memcpy(fanProjs, _projs, sizeof(fanProjs[0]) * dims.iProjAngles); + + delete[] angles; + angles = 0; + + return true; +} + + +bool ReconAlgo::setTOffsets(const float* _TOffsets) +{ + // TODO: determine if they're all zero? + TOffsets = new float[dims.iProjAngles]; + memcpy(TOffsets, _TOffsets, sizeof(angles[0]) * dims.iProjAngles); + + return true; +} + + + +bool ReconAlgo::setVolumeMask(float* _D_maskData, unsigned int _maskPitch) +{ + assert(useVolumeMask); + + D_maskData = _D_maskData; + maskPitch = _maskPitch; + + return true; +} + +bool ReconAlgo::setSinogramMask(float* _D_smaskData, unsigned int _smaskPitch) +{ + assert(useSinogramMask); + + D_smaskData = _D_smaskData; + smaskPitch = _smaskPitch; + + return true; +} + +bool ReconAlgo::setBuffers(float* _D_volumeData, unsigned int _volumePitch, + float* _D_projData, unsigned int _projPitch) +{ + D_volumeData = _D_volumeData; + volumePitch = _volumePitch; + D_sinoData = _D_projData; + sinoPitch = _projPitch; + + return true; +} + +bool ReconAlgo::setMinConstraint(float fMin) +{ + fMinConstraint = fMin; + useMinConstraint = true; + return true; +} + +bool ReconAlgo::setMaxConstraint(float fMax) +{ + fMaxConstraint = fMax; + useMaxConstraint = true; + return true; +} + + + +bool ReconAlgo::allocateBuffers() +{ + bool ok; + ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + if (!ok) + return false; + + ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + D_volumeData = 0; + return false; + } + + if (useVolumeMask) { + ok = allocateVolume(D_maskData, dims.iVolWidth+2, dims.iVolHeight+2, maskPitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + D_volumeData = 0; + D_sinoData = 0; + return false; + } + } + + if (useSinogramMask) { + ok = allocateVolume(D_smaskData, dims.iProjDets+2, dims.iProjAngles, smaskPitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + cudaFree(D_maskData); + D_volumeData = 0; + D_sinoData = 0; + D_maskData = 0; + return false; + } + } + + freeGPUMemory = true; + return true; +} + +bool ReconAlgo::copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale, + const float* pfReconstruction, unsigned int iReconstructionPitch, + const float* pfVolMask, unsigned int iVolMaskPitch, + const float* pfSinoMask, unsigned int iSinoMaskPitch) +{ + if (!pfSinogram) + return false; + if (!pfReconstruction) + return false; + + bool ok = copySinogramToDevice(pfSinogram, iSinogramPitch, + dims.iProjDets, + dims.iProjAngles, + D_sinoData, sinoPitch); + if (!ok) + return false; + + // rescale sinogram to adjust for pixel size + processVol<opMul,SINO>(D_sinoData, fSinogramScale, + //1.0f/(fPixelSize*fPixelSize), + sinoPitch, + dims.iProjDets, dims.iProjAngles); + + ok = copyVolumeToDevice(pfReconstruction, iReconstructionPitch, + dims.iVolWidth, dims.iVolHeight, + D_volumeData, volumePitch); + if (!ok) + return false; + + + + if (useVolumeMask) { + if (!pfVolMask) + return false; + + ok = copyVolumeToDevice(pfVolMask, iVolMaskPitch, + dims.iVolWidth, dims.iVolHeight, + D_maskData, maskPitch); + if (!ok) + return false; + } + + if (useSinogramMask) { + if (!pfSinoMask) + return false; + + ok = copySinogramToDevice(pfSinoMask, iSinoMaskPitch, + dims.iProjDets, dims.iProjAngles, + D_smaskData, smaskPitch); + if (!ok) + return false; + } + + return true; +} + +bool ReconAlgo::getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const +{ + bool ok = copyVolumeFromDevice(pfReconstruction, iReconstructionPitch, + dims.iVolWidth, + dims.iVolHeight, + D_volumeData, volumePitch); + if (!ok) + return false; + + return true; +} + + +bool ReconAlgo::callFP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + float outputScale) +{ + if (angles) { + assert(!fanProjs); + return FP(D_volumeData, volumePitch, D_projData, projPitch, + dims, angles, TOffsets, outputScale); + } else { + assert(fanProjs); + return FanFP(D_volumeData, volumePitch, D_projData, projPitch, + dims, fanProjs, outputScale); + } +} + +bool ReconAlgo::callBP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch) +{ + if (angles) { + assert(!fanProjs); + return BP(D_volumeData, volumePitch, D_projData, projPitch, + dims, angles, TOffsets); + } else { + assert(fanProjs); + return FanBP(D_volumeData, volumePitch, D_projData, projPitch, + dims, fanProjs); + } + +} + + + +} diff --git a/cuda/2d/algo.h b/cuda/2d/algo.h new file mode 100644 index 0000000..96195a3 --- /dev/null +++ b/cuda/2d/algo.h @@ -0,0 +1,155 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ALGO_H +#define _CUDA_ALGO_H + +#include "util.h" + +namespace astraCUDA { + +class _AstraExport ReconAlgo { +public: + ReconAlgo(); + virtual ~ReconAlgo(); + + bool setGPUIndex(int iGPUIndex); + + bool setGeometry(const SDimensions& dims, const float* angles); + bool setFanGeometry(const SDimensions& dims, const SFanProjection* projs); + + // setTOffsets should (optionally) be called after setGeometry + bool setTOffsets(const float* TOffsets); + + void signalAbort() { shouldAbort = true; } + + virtual bool enableVolumeMask(); + virtual bool enableSinogramMask(); + + // init should be called after setting all geometry + virtual bool init() = 0; + + // setVolumeMask should be called after init and before iterate, + // but only if enableVolumeMask was called before init. + // It may be called again after iterate. + bool setVolumeMask(float* D_maskData, unsigned int maskPitch); + + // setSinogramMask should be called after init and before iterate, + // but only if enableSinogramMask was called before init. + // It may be called again after iterate. + bool setSinogramMask(float* D_smaskData, unsigned int smaskPitch); + + + // setBuffers should be called after init and before iterate. + // It may be called again after iterate. + virtual bool setBuffers(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch); + + + // instead of calling setBuffers, you can also call allocateBuffers + // to let ReconAlgo manage its own GPU memory + virtual bool allocateBuffers(); + virtual bool copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale, + const float* pfReconstruction, unsigned int iReconstructionPitch, + const float* pfVolMask, unsigned int iVolMaskPitch, + const float* pfSinoMask, unsigned int iSinoMaskPitch); + + + + // set Min/Max constraints. They may be called at any time, and will affect + // any iterate() calls afterwards. + virtual bool setMinConstraint(float fMin); + virtual bool setMaxConstraint(float fMax); + + + // iterate should be called after init and setBuffers. + // It may be called multiple times. + virtual bool iterate(unsigned int iterations) = 0; + + // Compute the norm of the difference of the FP of the current + // reconstruction and the sinogram. (This performs one FP.) + // It can be called after iterate. + virtual float computeDiffNorm() = 0; + // TODO: computeDiffNorm shouldn't be virtual, but for it to be + // implemented in ReconAlgo, it needs a way to get a suitable + // temporary sinogram buffer. + + bool getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const; + + + +protected: + void reset(); + + bool callFP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + float outputScale); + bool callBP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch); + + + SDimensions dims; + float* angles; + float* TOffsets; + SFanProjection* fanProjs; + + volatile bool shouldAbort; + + bool freeGPUMemory; + + // Input/output + float* D_sinoData; + unsigned int sinoPitch; + + float* D_volumeData; + unsigned int volumePitch; + + // Masks + bool useVolumeMask; + bool useSinogramMask; + + float* D_maskData; + unsigned int maskPitch; + float* D_smaskData; + unsigned int smaskPitch; + + // Min/max + bool useMinConstraint; + bool useMaxConstraint; + float fMinConstraint; + float fMaxConstraint; + + +}; + + +} + +#endif + diff --git a/cuda/2d/arith.cu b/cuda/2d/arith.cu new file mode 100644 index 0000000..1ee02ca --- /dev/null +++ b/cuda/2d/arith.cu @@ -0,0 +1,893 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "util.h" +#include "arith.h" +#include <cassert> + +namespace astraCUDA { + + +struct opAddScaled { + __device__ void operator()(float& out, const float in, const float inp) { + out += in * inp; + } +}; +struct opScaleAndAdd { + __device__ void operator()(float& out, const float in, const float inp) { + out = in + out * inp; + } +}; +struct opAddMulScaled { + __device__ void operator()(float& out, const float in1, const float in2, const float inp) { + out += in1 * in2 * inp; + } +}; +struct opAddMul { + __device__ void operator()(float& out, const float in1, const float in2) { + out += in1 * in2; + } +}; +struct opAdd { + __device__ void operator()(float& out, const float in) { + out += in; + } +}; +struct opAdd2 { + __device__ void operator()(float& out, const float in1, const float in2) { + out += in1 + in2; + } +}; +struct opMul { + __device__ void operator()(float& out, const float in) { + out *= in; + } +}; +struct opMul2 { + __device__ void operator()(float& out, const float in1, const float in2) { + out *= in1 * in2; + } +}; +struct opDividedBy { + __device__ void operator()(float& out, const float in) { + if (out > 0.000001f) // out is assumed to be positive + out = in / out; + else + out = 0.0f; + } +}; +struct opInvert { + __device__ void operator()(float& out) { + if (out > 0.000001f) // out is assumed to be positive + out = 1 / out; + else + out = 0.0f; + } +}; +struct opSet { + __device__ void operator()(float& out, const float inp) { + out = inp; + } +}; +struct opClampMin { + __device__ void operator()(float& out, const float inp) { + if (out < inp) + out = inp; + } +}; +struct opClampMax { + __device__ void operator()(float& out, const float inp) { + if (out > inp) + out = inp; + } +}; +struct opClampMinMask { + __device__ void operator()(float& out, const float in) { + if (out < in) + out = in; + } +}; +struct opClampMaxMask { + __device__ void operator()(float& out, const float in) { + if (out > in) + out = in; + } +}; +struct opSetMaskedValues { + __device__ void operator()(float& out, const float in, const float inp) { + if (!in) + out = inp; + } +}; +struct opSegmentAndMask { + __device__ void operator()(float& out1, float& out2, const float inp1, const float inp2) { + if (out1 >= inp1) { + out1 = inp2; + out2 = 0.0f; + } + + } + +}; +struct opMulMask { + __device__ void operator()(float& out, const float mask, const float in) { + if (mask > 0.0f) { + out *= in; + } + } +}; + + + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devtoD(float* pfOut, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off]); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devFtoD(float* pfOut, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], fParam); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devFFtoDD(float* pfOut1, float* pfOut2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut1[off], pfOut2[off], fParam1, fParam2); + off += pitch; + y++; + } +} + + + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDtoD(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn[off]); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDFtoD(float* pfOut, const float* pfIn, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn[off], fParam); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDDtoD(float* pfOut, const float* pfIn1, const float* pfIn2, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn1[off], pfIn2[off]); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDDFtoD(float* pfOut, const float* pfIn1, const float* pfIn2, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn1[off], pfIn2[off], fParam); + off += pitch; + y++; + } +} + + + + + + + + + + + + + + + + +template<typename op, VolType t> +void processVolCopy(float* out, unsigned int width, unsigned int height) +{ + float* D_out; + + unsigned int pitch; + allocateVolume(D_out, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_out, pitch); + + processVol<op, t>(D_out, pitch, width, height); + + copyVolumeFromDevice(out, width, width, height, D_out, pitch); + + cudaFree(D_out); +} + +template<typename op, VolType t> +void processVolCopy(float* out, float param, unsigned int width, unsigned int height) +{ + float* D_out; + + unsigned int pitch; + allocateVolume(D_out, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_out, pitch); + + processVol<op, t>(D_out, param, pitch, width, height); + + copyVolumeFromDevice(out, width, width, height, D_out, pitch); + + cudaFree(D_out); +} + +template<typename op, VolType t> +void processVolCopy(float* out1, float* out2, float param1, float param2, unsigned int width, unsigned int height) +{ + float* D_out1; + float* D_out2; + + unsigned int pitch; + allocateVolume(D_out1, width+2, height+2, pitch); + copyVolumeToDevice(out1, width, width, height, D_out1, pitch); + allocateVolume(D_out2, width+2, height+2, pitch); + copyVolumeToDevice(out2, width, width, height, D_out2, pitch); + + processVol<op, t>(D_out1, D_out2, param1, param2, pitch, width, height); + + copyVolumeFromDevice(out1, width, width, height, D_out1, pitch); + copyVolumeFromDevice(out2, width, width, height, D_out2, pitch); + + cudaFree(D_out1); + cudaFree(D_out2); +} + + +template<typename op, VolType t> +void processVolCopy(float* out, const float* in, unsigned int width, unsigned int height) +{ + float* D_out; + float* D_in; + + unsigned int pitch; + allocateVolume(D_out, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_out, pitch); + allocateVolume(D_in, width+2, height+2, pitch); + copyVolumeToDevice(in, width, width, height, D_in, pitch); + + processVol<op, t>(D_out, D_in, pitch, width, height); + + copyVolumeFromDevice(out, width, width, height, D_out, pitch); + + cudaFree(D_out); + cudaFree(D_in); +} + +template<typename op, VolType t> +void processVolCopy(float* out, const float* in, float param, unsigned int width, unsigned int height) +{ + float* D_out; + float* D_in; + + unsigned int pitch; + allocateVolume(D_out, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_out, pitch); + allocateVolume(D_in, width+2, height+2, pitch); + copyVolumeToDevice(in, width, width, height, D_in, pitch); + + processVol<op, t>(D_out, D_in, param, pitch, width, height); + + copyVolumeFromDevice(out, width, width, height, D_out, pitch); + + cudaFree(D_out); + cudaFree(D_in); +} + +template<typename op, VolType t> +void processVolCopy(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height) +{ + float* D_out; + float* D_in1; + float* D_in2; + + unsigned int pitch; + allocateVolume(D_out, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_out, pitch); + allocateVolume(D_in1, width+2, height+2, pitch); + copyVolumeToDevice(in1, width, width, height, D_in1, pitch); + allocateVolume(D_in2, width+2, height+2, pitch); + copyVolumeToDevice(in2, width, width, height, D_in2, pitch); + + processVol<op, t>(D_out, D_in1, D_in2, pitch, width, height); + + copyVolumeFromDevice(out, width, width, height, D_out, pitch); + + cudaFree(D_out); + cudaFree(D_in1); + cudaFree(D_in2); +} + +template<typename op, VolType t> +void processVolCopy(float* out, const float* in1, const float* in2, float param, unsigned int width, unsigned int height) +{ + float* D_out; + float* D_in1; + float* D_in2; + + unsigned int pitch; + allocateVolume(D_out, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_out, pitch); + allocateVolume(D_in1, width+2, height+2, pitch); + copyVolumeToDevice(in1, width, width, height, D_in1, pitch); + allocateVolume(D_in2, width+2, height+2, pitch); + copyVolumeToDevice(in2, width, width, height, D_in2, pitch); + + processVol<op, t>(D_out, D_in1, D_in2, param, pitch, width, height); + + copyVolumeFromDevice(out, width, width, height, D_out, pitch); + + cudaFree(D_out); + cudaFree(D_in1); + cudaFree(D_in2); +} + + + + + + + + + +template<typename op, VolType t> +void processVol(float* pfOut, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+511)/512); + + devtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(float* pfOut, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + devFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, fParam, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(float* pfOut1, float* pfOut2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + devFFtoDD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut1, pfOut2, fParam1, fParam2, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + + +template<typename op, VolType t> +void processVol(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + devDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(float* pfOut, const float* pfIn, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + devDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(float* pfOut, const float* pfIn1, const float* pfIn2, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + devDDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(float* pfOut, const float* pfIn1, const float* pfIn2, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + devDDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + + + + + + + + + + + + + + + + + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut1 = (float*)out1.ptr; + float *pfOut2 = (float*)out2.ptr; + unsigned int step = out1.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devFFtoDD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut1, pfOut2, fParam1, fParam2, out1.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut1 += step; + pfOut2 += step; + } + + cudaTextForceKernelsCompletion(); +} + + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + + + + + + + + + + + + + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut1 = (float*)out1.ptr; + float *pfOut2 = (float*)out2.ptr; + unsigned int step = out1.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devFFtoDD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut1, pfOut2, fParam1, fParam2, out1.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut1 += step; + pfOut2 += step; + } + + cudaTextForceKernelsCompletion(); +} + + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + + + + + + + + + + + + + + + + + + +#define INST_DFtoD(name) \ + template void processVolCopy<name, VOL>(float* out, const float* in, float param, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out, const float* in, float param, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out, const float* in, float param, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out, const float* in, float param, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); + +#define INST_DtoD(name) \ + template void processVolCopy<name, VOL>(float* out, const float* in, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out, const float* in, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out, const float* in, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out, const float* in, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); + +#define INST_DDtoD(name) \ + template void processVolCopy<name, VOL>(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out, const float* in1, const float* in2, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out, const float* in1, const float* in2, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); + +#define INST_DDFtoD(name) \ + template void processVolCopy<name, VOL>(float* out, const float* in1, const float* in2, float fParam, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out, const float* in1, const float* in2, float fParam, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out, const float* in1, const float* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out, const float* in1, const float* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); + + +#define INST_toD(name) \ + template void processVolCopy<name, VOL>(float* out, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims); + +#define INST_FtoD(name) \ + template void processVolCopy<name, VOL>(float* out, float param, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out, float param, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out, float param, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out, float param, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, float param, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, float param, const SDimensions3D& dims); + +#define INST_FFtoDD(name) \ + template void processVolCopy<name, VOL>(float* out1, float* out2, float fParam1, float fParam2, unsigned int width, unsigned int height); \ + template void processVolCopy<name, SINO>(float* out1, float* out2, float fParam1, float fParam2, unsigned int width, unsigned int height); \ + template void processVol<name, VOL>(float* out1, float* out2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(float* out1, float* out2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims); + + + +INST_DFtoD(opAddScaled) +INST_DFtoD(opScaleAndAdd) +INST_DDFtoD(opAddMulScaled) +INST_DDtoD(opAddMul) +INST_DDtoD(opMul2) +INST_DDtoD(opAdd2) +INST_DtoD(opMul) +INST_DDtoD(opMulMask) +INST_DtoD(opAdd) +INST_DtoD(opDividedBy) +INST_toD(opInvert) +INST_FtoD(opSet) +INST_FtoD(opMul) +INST_DFtoD(opMulMask) +INST_FtoD(opAdd) +INST_FtoD(opClampMin) +INST_FtoD(opClampMax) +INST_DtoD(opClampMinMask) +INST_DtoD(opClampMaxMask) + +// PDART-specific: +INST_DFtoD(opSetMaskedValues) +INST_FFtoDD(opSegmentAndMask) + +} diff --git a/cuda/2d/arith.h b/cuda/2d/arith.h new file mode 100644 index 0000000..c8c7b41 --- /dev/null +++ b/cuda/2d/arith.h @@ -0,0 +1,101 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ARITH_H +#define _CUDA_ARITH_H + +#include <cuda.h> + +namespace astraCUDA { + + +struct opAddScaled; +struct opScaleAndAdd; +struct opAddMulScaled; +struct opAddMul; +struct opAdd; +struct opAdd2; +struct opMul; +struct opMul2; +struct opDividedBy; +struct opInvert; +struct opSet; +struct opClampMin; +struct opClampMax; +struct opClampMinMask; +struct opClampMaxMask; +struct opSegmentAndMask; +struct opSetMaskedValues; + +struct opMulMask; + + + +enum VolType { + SINO = 0, + VOL = 1 +}; + + +template<typename op, VolType t> void processVolCopy(float* out, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVolCopy(float* out, float param, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVolCopy(float* out1, float* out2, float param1, float param2, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVolCopy(float* out, const float* in, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVolCopy(float* out, const float* in, float param, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVolCopy(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVolCopy(float* out, const float* in1, const float* in2, float param, unsigned int width, unsigned int height); + +template<typename op, VolType t> void processVol(float* out, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(float* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(float* out1, float* out2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(float* out, const float* in, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(float* out, const float* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(float* out, const float* in1, const float* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(float* out, const float* in1, const float* in2, unsigned int pitch, unsigned int width, unsigned int height); + +template<typename op> void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); + +template<typename op> void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); + + + +} + +#endif diff --git a/cuda/2d/astra.cu b/cuda/2d/astra.cu new file mode 100644 index 0000000..71ed025 --- /dev/null +++ b/cuda/2d/astra.cu @@ -0,0 +1,824 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "util.h" +#include "par_fp.h" +#include "fan_fp.h" +#include "par_bp.h" +#include "arith.h" +#include "astra.h" + +#include "fft.h" + +#include <fstream> +#include <cuda.h> + +#include "../../include/astra/Logger.h" + +using namespace astraCUDA; +using namespace std; + + +namespace astra { + +enum CUDAProjectionType { + PROJ_PARALLEL, + PROJ_FAN +}; + + +class AstraFBP_internal { +public: + SDimensions dims; + float* angles; + float* TOffsets; + + float fPixelSize; + + bool initialized; + bool setStartReconstruction; + + float* D_sinoData; + unsigned int sinoPitch; + + float* D_volumeData; + unsigned int volumePitch; + + cufftComplex * m_pDevFilter; +}; + +AstraFBP::AstraFBP() +{ + pData = new AstraFBP_internal(); + + pData->angles = 0; + pData->D_sinoData = 0; + pData->D_volumeData = 0; + + pData->dims.iVolWidth = 0; + pData->dims.iProjAngles = 0; + pData->dims.fDetScale = 1.0f; + pData->dims.iRaysPerDet = 1; + pData->dims.iRaysPerPixelDim = 1; + + pData->initialized = false; + pData->setStartReconstruction = false; + + pData->m_pDevFilter = NULL; +} + +AstraFBP::~AstraFBP() +{ + delete[] pData->angles; + pData->angles = 0; + + delete[] pData->TOffsets; + pData->TOffsets = 0; + + cudaFree(pData->D_sinoData); + pData->D_sinoData = 0; + + cudaFree(pData->D_volumeData); + pData->D_volumeData = 0; + + if(pData->m_pDevFilter != NULL) + { + freeComplexOnDevice(pData->m_pDevFilter); + pData->m_pDevFilter = NULL; + } + + delete pData; + pData = 0; +} + +bool AstraFBP::setReconstructionGeometry(unsigned int iVolWidth, + unsigned int iVolHeight, + float fPixelSize) +{ + if (pData->initialized) + return false; + + pData->dims.iVolWidth = iVolWidth; + pData->dims.iVolHeight = iVolHeight; + + pData->fPixelSize = fPixelSize; + + return (iVolWidth > 0 && iVolHeight > 0 && fPixelSize > 0.0f); +} + +bool AstraFBP::setProjectionGeometry(unsigned int iProjAngles, + unsigned int iProjDets, + const float* pfAngles, + float fDetSize) +{ + if (pData->initialized) + return false; + + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjDets = iProjDets; + pData->dims.fDetScale = fDetSize / pData->fPixelSize; + + if (iProjAngles == 0 || iProjDets == 0 || pfAngles == 0) + return false; + + pData->angles = new float[iProjAngles]; + memcpy(pData->angles, pfAngles, iProjAngles * sizeof(pfAngles[0])); + + return true; +} + +bool AstraFBP::setPixelSuperSampling(unsigned int iPixelSuperSampling) +{ + if (pData->initialized) + return false; + + if (iPixelSuperSampling == 0) + return false; + + pData->dims.iRaysPerPixelDim = iPixelSuperSampling; + + return true; +} + + +bool AstraFBP::setTOffsets(const float* pfTOffsets) +{ + if (pData->initialized) + return false; + + if (pfTOffsets == 0) + return false; + + pData->TOffsets = new float[pData->dims.iProjAngles]; + memcpy(pData->TOffsets, pfTOffsets, pData->dims.iProjAngles * sizeof(pfTOffsets[0])); + + return true; +} + +bool AstraFBP::init(int iGPUIndex) +{ + if (pData->initialized) + { + return false; + } + + if (pData->dims.iProjAngles == 0 || pData->dims.iVolWidth == 0) + { + return false; + } + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + { + return false; + } + + bool ok = allocateVolume(pData->D_volumeData, pData->dims.iVolWidth+2, pData->dims.iVolHeight+2, pData->volumePitch); + if (!ok) + { + return false; + } + + ok = allocateVolume(pData->D_sinoData, pData->dims.iProjDets+2, pData->dims.iProjAngles, pData->sinoPitch); + if (!ok) + { + cudaFree(pData->D_volumeData); + pData->D_volumeData = 0; + return false; + } + + pData->initialized = true; + + return true; +} + +bool AstraFBP::setSinogram(const float* pfSinogram, + unsigned int iSinogramPitch) +{ + if (!pData->initialized) + return false; + if (!pfSinogram) + return false; + + bool ok = copySinogramToDevice(pfSinogram, iSinogramPitch, + pData->dims.iProjDets, + pData->dims.iProjAngles, + pData->D_sinoData, pData->sinoPitch); + if (!ok) + return false; + + // rescale sinogram to adjust for pixel size + processVol<opMul,SINO>(pData->D_sinoData, + 1.0f/(pData->fPixelSize*pData->fPixelSize), + pData->sinoPitch, + pData->dims.iProjDets, pData->dims.iProjAngles); + + pData->setStartReconstruction = false; + + return true; +} + +static int calcNextPowerOfTwo(int _iValue) +{ + int iOutput = 1; + + while(iOutput < _iValue) + { + iOutput *= 2; + } + + return iOutput; +} + +bool AstraFBP::run() +{ + if (!pData->initialized) + { + return false; + } + + zeroVolume(pData->D_volumeData, pData->volumePitch, pData->dims.iVolWidth+2, pData->dims.iVolHeight+2); + + bool ok = false; + + if (pData->m_pDevFilter) { + + int iFFTRealDetCount = calcNextPowerOfTwo(2 * pData->dims.iProjDets); + int iFFTFourDetCount = calcFFTFourSize(iFFTRealDetCount); + + cufftComplex * pDevComplexSinogram = NULL; + + allocateComplexOnDevice(pData->dims.iProjAngles, iFFTFourDetCount, &pDevComplexSinogram); + + runCudaFFT(pData->dims.iProjAngles, pData->D_sinoData, pData->sinoPitch, 1, pData->dims.iProjDets, iFFTRealDetCount, iFFTFourDetCount, pDevComplexSinogram); + + applyFilter(pData->dims.iProjAngles, iFFTFourDetCount, pDevComplexSinogram, pData->m_pDevFilter); + + runCudaIFFT(pData->dims.iProjAngles, pDevComplexSinogram, pData->D_sinoData, pData->sinoPitch, 1, pData->dims.iProjDets, iFFTRealDetCount, iFFTFourDetCount); + + freeComplexOnDevice(pDevComplexSinogram); + + } + + ok = BP(pData->D_volumeData, pData->volumePitch, pData->D_sinoData, pData->sinoPitch, pData->dims, pData->angles, pData->TOffsets); + if(!ok) + { + return false; + } + + processVol<opMul,VOL>(pData->D_volumeData, + (M_PI / 2.0f) / (float)pData->dims.iProjAngles, + pData->volumePitch, + pData->dims.iVolWidth, pData->dims.iVolHeight); + + return true; +} + +bool AstraFBP::getReconstruction(float* pfReconstruction, unsigned int iReconstructionPitch) const +{ + if (!pData->initialized) + return false; + + bool ok = copyVolumeFromDevice(pfReconstruction, iReconstructionPitch, + pData->dims.iVolWidth, + pData->dims.iVolHeight, + pData->D_volumeData, pData->volumePitch); + if (!ok) + return false; + + return true; +} + +int AstraFBP::calcFourierFilterSize(int _iDetectorCount) +{ + int iFFTRealDetCount = calcNextPowerOfTwo(2 * _iDetectorCount); + int iFreqBinCount = calcFFTFourSize(iFFTRealDetCount); + + // CHECKME: Matlab makes this at least 64. Do we also need to? + return iFreqBinCount; +} + +bool AstraFBP::setFilter(E_FBPFILTER _eFilter, const float * _pfHostFilter /* = NULL */, int _iFilterWidth /* = 0 */, float _fD /* = 1.0f */, float _fFilterParameter /* = -1.0f */) +{ + if(pData->m_pDevFilter != 0) + { + freeComplexOnDevice(pData->m_pDevFilter); + pData->m_pDevFilter = 0; + } + + if (_eFilter == FILTER_NONE) + return true; // leave pData->m_pDevFilter set to 0 + + + int iFFTRealDetCount = calcNextPowerOfTwo(2 * pData->dims.iProjDets); + int iFreqBinCount = calcFFTFourSize(iFFTRealDetCount); + + cufftComplex * pHostFilter = new cufftComplex[pData->dims.iProjAngles * iFreqBinCount]; + memset(pHostFilter, 0, sizeof(cufftComplex) * pData->dims.iProjAngles * iFreqBinCount); + + allocateComplexOnDevice(pData->dims.iProjAngles, iFreqBinCount, &(pData->m_pDevFilter)); + + switch(_eFilter) + { + case FILTER_NONE: + // handled above + break; + case FILTER_RAMLAK: + case FILTER_SHEPPLOGAN: + case FILTER_COSINE: + case FILTER_HAMMING: + case FILTER_HANN: + case FILTER_TUKEY: + case FILTER_LANCZOS: + case FILTER_TRIANGULAR: + case FILTER_GAUSSIAN: + case FILTER_BARTLETTHANN: + case FILTER_BLACKMAN: + case FILTER_NUTTALL: + case FILTER_BLACKMANHARRIS: + case FILTER_BLACKMANNUTTALL: + case FILTER_FLATTOP: + { + genFilter(_eFilter, _fD, pData->dims.iProjAngles, pHostFilter, iFFTRealDetCount, iFreqBinCount, _fFilterParameter); + uploadComplexArrayToDevice(pData->dims.iProjAngles, iFreqBinCount, pHostFilter, pData->m_pDevFilter); + + break; + } + case FILTER_PROJECTION: + { + // make sure the offered filter has the correct size + assert(_iFilterWidth == iFreqBinCount); + + for(int iFreqBinIndex = 0; iFreqBinIndex < iFreqBinCount; iFreqBinIndex++) + { + float fValue = _pfHostFilter[iFreqBinIndex]; + + for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++) + { + pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].x = fValue; + pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].y = 0.0f; + } + } + uploadComplexArrayToDevice(pData->dims.iProjAngles, iFreqBinCount, pHostFilter, pData->m_pDevFilter); + break; + } + case FILTER_SINOGRAM: + { + // make sure the offered filter has the correct size + assert(_iFilterWidth == iFreqBinCount); + + for(int iFreqBinIndex = 0; iFreqBinIndex < iFreqBinCount; iFreqBinIndex++) + { + for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++) + { + float fValue = _pfHostFilter[iFreqBinIndex + iProjectionIndex * _iFilterWidth]; + + pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].x = fValue; + pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].y = 0.0f; + } + } + uploadComplexArrayToDevice(pData->dims.iProjAngles, iFreqBinCount, pHostFilter, pData->m_pDevFilter); + break; + } + case FILTER_RPROJECTION: + { + int iProjectionCount = pData->dims.iProjAngles; + int iRealFilterElementCount = iProjectionCount * iFFTRealDetCount; + float * pfHostRealFilter = new float[iRealFilterElementCount]; + memset(pfHostRealFilter, 0, sizeof(float) * iRealFilterElementCount); + + int iUsedFilterWidth = min(_iFilterWidth, iFFTRealDetCount); + int iStartFilterIndex = (_iFilterWidth - iUsedFilterWidth) / 2; + int iMaxFilterIndex = iStartFilterIndex + iUsedFilterWidth; + + int iFilterShiftSize = _iFilterWidth / 2; + + for(int iDetectorIndex = iStartFilterIndex; iDetectorIndex < iMaxFilterIndex; iDetectorIndex++) + { + int iFFTInFilterIndex = (iDetectorIndex + iFFTRealDetCount - iFilterShiftSize) % iFFTRealDetCount; + float fValue = _pfHostFilter[iDetectorIndex]; + + for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++) + { + pfHostRealFilter[iFFTInFilterIndex + iProjectionIndex * iFFTRealDetCount] = fValue; + } + } + + float* pfDevRealFilter = NULL; + cudaMalloc((void **)&pfDevRealFilter, sizeof(float) * iRealFilterElementCount); // TODO: check for errors + cudaMemcpy(pfDevRealFilter, pfHostRealFilter, sizeof(float) * iRealFilterElementCount, cudaMemcpyHostToDevice); + delete[] pfHostRealFilter; + + runCudaFFT(iProjectionCount, pfDevRealFilter, iFFTRealDetCount, 0, iFFTRealDetCount, iFFTRealDetCount, iFreqBinCount, pData->m_pDevFilter); + + cudaFree(pfDevRealFilter); + + break; + } + case FILTER_RSINOGRAM: + { + int iProjectionCount = pData->dims.iProjAngles; + int iRealFilterElementCount = iProjectionCount * iFFTRealDetCount; + float* pfHostRealFilter = new float[iRealFilterElementCount]; + memset(pfHostRealFilter, 0, sizeof(float) * iRealFilterElementCount); + + int iUsedFilterWidth = min(_iFilterWidth, iFFTRealDetCount); + int iStartFilterIndex = (_iFilterWidth - iUsedFilterWidth) / 2; + int iMaxFilterIndex = iStartFilterIndex + iUsedFilterWidth; + + int iFilterShiftSize = _iFilterWidth / 2; + + for(int iDetectorIndex = iStartFilterIndex; iDetectorIndex < iMaxFilterIndex; iDetectorIndex++) + { + int iFFTInFilterIndex = (iDetectorIndex + iFFTRealDetCount - iFilterShiftSize) % iFFTRealDetCount; + + for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++) + { + float fValue = _pfHostFilter[iDetectorIndex + iProjectionIndex * _iFilterWidth]; + pfHostRealFilter[iFFTInFilterIndex + iProjectionIndex * iFFTRealDetCount] = fValue; + } + } + + float* pfDevRealFilter = NULL; + cudaMalloc((void **)&pfDevRealFilter, sizeof(float) * iRealFilterElementCount); // TODO: check for errors + cudaMemcpy(pfDevRealFilter, pfHostRealFilter, sizeof(float) * iRealFilterElementCount, cudaMemcpyHostToDevice); + delete[] pfHostRealFilter; + + runCudaFFT(iProjectionCount, pfDevRealFilter, iFFTRealDetCount, 0, iFFTRealDetCount, iFFTRealDetCount, iFreqBinCount, pData->m_pDevFilter); + + cudaFree(pfDevRealFilter); + + break; + } + default: + { + fprintf(stderr, "AstraFBP::setFilter: Weird filter type requested"); + delete [] pHostFilter; + return false; + } + } + + delete [] pHostFilter; + + return true; +} + +BPalgo::BPalgo() +{ + +} + +BPalgo::~BPalgo() +{ + +} + +bool BPalgo::init() +{ + return true; +} + +bool BPalgo::iterate(unsigned int) +{ + // TODO: This zeroVolume makes an earlier memcpy of D_volumeData redundant + zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + callBP(D_volumeData, volumePitch, D_sinoData, sinoPitch); + return true; +} + +float BPalgo::computeDiffNorm() +{ + float *D_projData; + unsigned int projPitch; + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + + cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f); + + float s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + + cudaFree(D_projData); + + return sqrt(s); +} + + +bool astraCudaFP(const float* pfVolume, float* pfSinogram, + unsigned int iVolWidth, unsigned int iVolHeight, + unsigned int iProjAngles, unsigned int iProjDets, + const float *pfAngles, const float *pfOffsets, + float fDetSize, unsigned int iDetSuperSampling, + int iGPUIndex) +{ + SDimensions dims; + + if (iProjAngles == 0 || iProjDets == 0 || pfAngles == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjDets = iProjDets; + dims.fDetScale = fDetSize; + + if (iDetSuperSampling == 0) + return false; + + dims.iRaysPerDet = iDetSuperSampling; + + if (iVolWidth <= 0 || iVolHeight <= 0) + return false; + + dims.iVolWidth = iVolWidth; + dims.iVolHeight = iVolHeight; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + bool ok; + + float* D_volumeData; + unsigned int volumePitch; + + ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + if (!ok) + return false; + + float* D_sinoData; + unsigned int sinoPitch; + + ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + return false; + } + + ok = copyVolumeToDevice(pfVolume, dims.iVolWidth, + dims.iVolWidth, dims.iVolHeight, + D_volumeData, volumePitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles); + ok = FP(D_volumeData, volumePitch, D_sinoData, sinoPitch, dims, pfAngles, pfOffsets, 1.0f); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + ok = copySinogramFromDevice(pfSinogram, dims.iProjDets, + dims.iProjDets, + dims.iProjAngles, + D_sinoData, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return true; +} + +bool astraCudaFanFP(const float* pfVolume, float* pfSinogram, + unsigned int iVolWidth, unsigned int iVolHeight, + unsigned int iProjAngles, unsigned int iProjDets, + const float *pfAngles, float fOriginSourceDistance, + float fOriginDetectorDistance, float fPixelSize, + float fDetSize, + unsigned int iDetSuperSampling, + int iGPUIndex) +{ + SDimensions dims; + + if (iProjAngles == 0 || iProjDets == 0 || pfAngles == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjDets = iProjDets; + + if (iDetSuperSampling == 0) + return false; + + dims.iRaysPerDet = iDetSuperSampling; + + if (iVolWidth <= 0 || iVolHeight <= 0) + return false; + + dims.iVolWidth = iVolWidth; + dims.iVolHeight = iVolHeight; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + bool ok; + + float* D_volumeData; + unsigned int volumePitch; + + ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + if (!ok) + return false; + + float* D_sinoData; + unsigned int sinoPitch; + + ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + return false; + } + + ok = copyVolumeToDevice(pfVolume, dims.iVolWidth, + dims.iVolWidth, dims.iVolHeight, + D_volumeData, volumePitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles); + + // TODO: Turn this geometry conversion into a util function + SFanProjection* projs = new SFanProjection[dims.iProjAngles]; + + float fSrcX0 = 0.0f; + float fSrcY0 = -fOriginSourceDistance / fPixelSize; + float fDetUX0 = fDetSize / fPixelSize; + float fDetUY0 = 0.0f; + float fDetSX0 = dims.iProjDets * fDetUX0 / -2.0f; + float fDetSY0 = fOriginDetectorDistance / fPixelSize; + +#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = f##name##X0 * cos(alpha) - f##name##Y0 * sin(alpha); projs[i].f##name##Y = f##name##X0 * sin(alpha) + f##name##Y0 * cos(alpha); } while(0) + for (int i = 0; i < dims.iProjAngles; ++i) { + ROTATE0(Src, i, pfAngles[i]); + ROTATE0(DetS, i, pfAngles[i]); + ROTATE0(DetU, i, pfAngles[i]); + } + +#undef ROTATE0 + + ok = FanFP(D_volumeData, volumePitch, D_sinoData, sinoPitch, dims, projs, 1.0f); + delete[] projs; + + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + ok = copySinogramFromDevice(pfSinogram, dims.iProjDets, + dims.iProjDets, + dims.iProjAngles, + D_sinoData, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + cudaFree(D_volumeData); + cudaFree(D_sinoData); + + return true; + +} + + +bool astraCudaFanFP(const float* pfVolume, float* pfSinogram, + unsigned int iVolWidth, unsigned int iVolHeight, + unsigned int iProjAngles, unsigned int iProjDets, + const SFanProjection *pAngles, + unsigned int iDetSuperSampling, + int iGPUIndex) +{ + SDimensions dims; + + if (iProjAngles == 0 || iProjDets == 0 || pAngles == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjDets = iProjDets; + dims.fDetScale = 1.0f; // TODO? + + if (iDetSuperSampling == 0) + return false; + + dims.iRaysPerDet = iDetSuperSampling; + + if (iVolWidth <= 0 || iVolHeight <= 0) + return false; + + dims.iVolWidth = iVolWidth; + dims.iVolHeight = iVolHeight; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + bool ok; + + float* D_volumeData; + unsigned int volumePitch; + + ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + if (!ok) + return false; + + float* D_sinoData; + unsigned int sinoPitch; + + ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + return false; + } + + ok = copyVolumeToDevice(pfVolume, dims.iVolWidth, + dims.iVolWidth, dims.iVolHeight, + D_volumeData, volumePitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles); + + ok = FanFP(D_volumeData, volumePitch, D_sinoData, sinoPitch, dims, pAngles, 1.0f); + + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + ok = copySinogramFromDevice(pfSinogram, dims.iProjDets, + dims.iProjDets, + dims.iProjAngles, + D_sinoData, sinoPitch); + if (!ok) { + cudaFree(D_volumeData); + cudaFree(D_sinoData); + return false; + } + + cudaFree(D_volumeData); + cudaFree(D_sinoData); + + return true; + +} + + +} diff --git a/cuda/2d/astra.h b/cuda/2d/astra.h new file mode 100644 index 0000000..9e58301 --- /dev/null +++ b/cuda/2d/astra.h @@ -0,0 +1,205 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ASTRA_H +#define _CUDA_ASTRA_H + +#include "fft.h" +#include "fbp_filters.h" +#include "dims.h" +#include "algo.h" + +using astraCUDA::SFanProjection; + +namespace astra { + +enum Cuda2DProjectionKernel { + ker2d_default = 0 +}; + +class AstraFBP_internal; + +class _AstraExport AstraFBP { +public: + // Constructor + AstraFBP(); + + // Destructor + ~AstraFBP(); + + // Set the size of the reconstruction rectangle. + // Volume pixels are currently assumed to be 1x1 squares. + bool setReconstructionGeometry(unsigned int iVolWidth, + unsigned int iVolHeight, + float fPixelSize = 1.0f); + + // Set the projection angles and number of detector pixels per angle. + // pfAngles must be a float array of length iProjAngles. + // fDetSize indicates the size of a detector pixel compared to a + // volume pixel edge. + // + // pfAngles will only be read from during this call. + bool setProjectionGeometry(unsigned int iProjAngles, + unsigned int iProjDets, + const float *pfAngles, + float fDetSize = 1.0f); + + // Set linear supersampling factor for the BP. + // (The number of rays is the square of this) + // + // This may optionally be called before init(). + bool setPixelSuperSampling(unsigned int iPixelSuperSampling); + + // Set per-detector shifts. + // + // pfTOffsets will only be read from during this call. + bool setTOffsets(const float *pfTOffsets); + + // Returns the required size of a filter in the fourier domain + // when multiplying it with the fft of the projection data. + // Its value is equal to the smallest power of two larger than + // or equal to twice the number of detectors in the spatial domain. + // + // _iDetectorCount is the number of detectors in the spatial domain. + static int calcFourierFilterSize(int _iDetectorCount); + + // Sets the filter type. Some filter types require the user to supply an + // array containing the filter. + // The number of elements in a filter in the fourier domain should be equal + // to the value returned by calcFourierFilterSize(). + // The following types require a filter: + // + // - FILTER_PROJECTION: + // The filter size should be equal to the output of + // calcFourierFilterSize(). The filtered sinogram is + // multiplied with the supplied filter. + // + // - FILTER_SINOGRAM: + // Same as FILTER_PROJECTION, but now the filter should contain a row for + // every projection direction. + // + // - FILTER_RPROJECTION: + // The filter should now contain one kernel (= ifft of filter), with the + // peak in the center. The filter width + // can be any value. If odd, the peak is assumed to be in the center, if + // even, it is assumed to be at floor(filter-width/2). + // + // - FILTER_RSINOGRAM + // Same as FILTER_RPROJECTION, but now the supplied filter should contain a + // row for every projection direction. + // + // A large number of other filters (FILTER_RAMLAK, FILTER_SHEPPLOGAN, + // FILTER_COSINE, FILTER_HAMMING, and FILTER_HANN) + // have a D variable, which gives the cutoff point in the frequency domain. + // Setting this value to 1.0 will include the whole filter + bool setFilter(E_FBPFILTER _eFilter, + const float * _pfHostFilter = NULL, + int _iFilterWidth = 0, float _fD = 1.0f, float _fFilterParameter = -1.0f); + + // Initialize CUDA, allocate GPU buffers and + // precompute geometry-specific data. + // + // CUDA is set up to use GPU number iGPUIndex. + // + // This must be called after calling setReconstructionGeometry() and + // setProjectionGeometry(). + bool init(int iGPUIndex = 0); + + // Setup input sinogram for a slice. + // pfSinogram must be a float array of size iProjAngles*iSinogramPitch. + // NB: iSinogramPitch is measured in floats, not in bytes. + // + // This must be called after init(), and before iterate(). It may be + // called again after iterate()/getReconstruction() to start a new slice. + // + // pfSinogram will only be read from during this call. + bool setSinogram(const float* pfSinogram, unsigned int iSinogramPitch); + + // Runs an FBP reconstruction. + // This must be called after setSinogram(). + // + // run can be called before setFilter, but will then use the default Ram-Lak filter + bool run(); + + // Get the reconstructed slice. + // pfReconstruction must be a float array of size + // iVolHeight*iReconstructionPitch. + // NB: iReconstructionPitch is measured in floats, not in bytes. + // + // This may be called after run(). + bool getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const; + +private: + AstraFBP_internal* pData; +}; + +class _AstraExport BPalgo : public astraCUDA::ReconAlgo { +public: + BPalgo(); + ~BPalgo(); + + virtual bool init(); + + virtual bool iterate(unsigned int iterations); + + virtual float computeDiffNorm(); +}; + + + + +// TODO: Clean up this interface to FP + +// Do a single forward projection +_AstraExport bool astraCudaFP(const float* pfVolume, float* pfSinogram, + unsigned int iVolWidth, unsigned int iVolHeight, + unsigned int iProjAngles, unsigned int iProjDets, + const float *pfAngles, const float *pfOffsets, + float fDetSize = 1.0f, unsigned int iDetSuperSampling = 1, + int iGPUIndex = 0); + +// Do a single forward projection, fan beam +_AstraExport bool astraCudaFanFP(const float* pfVolume, float* pfSinogram, + unsigned int iVolWidth, unsigned int iVolHeight, + unsigned int iProjAngles, unsigned int iProjDets, + const float *pfAngles, float fOriginSourceDistance, + float fOriginDetectorDistance, float fPixelSize = 1.0f, + float fDetSize = 1.0f, + unsigned int iDetSuperSampling = 1, + int iGPUIndex = 0); + +_AstraExport bool astraCudaFanFP(const float* pfVolume, float* pfSinogram, + unsigned int iVolWidth, unsigned int iVolHeight, + unsigned int iProjAngles, unsigned int iProjDets, + const SFanProjection *pAngles, + unsigned int iDetSuperSampling = 1, + int iGPUIndex = 0); + +} +#endif diff --git a/cuda/2d/cgls.cu b/cuda/2d/cgls.cu new file mode 100644 index 0000000..5b1cf46 --- /dev/null +++ b/cuda/2d/cgls.cu @@ -0,0 +1,304 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "cgls.h" +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +namespace astraCUDA { + +CGLS::CGLS() : ReconAlgo() +{ + D_z = 0; + D_p = 0; + D_r = 0; + D_w = 0; + + sliceInitialized = false; +} + + +CGLS::~CGLS() +{ + reset(); +} + +void CGLS::reset() +{ + cudaFree(D_z); + cudaFree(D_p); + cudaFree(D_r); + cudaFree(D_w); + + D_z = 0; + D_p = 0; + D_r = 0; + D_w = 0; + + ReconAlgo::reset(); +} + +bool CGLS::init() +{ + // Lifetime of z: within an iteration + allocateVolume(D_z, dims.iVolWidth+2, dims.iVolHeight+2, zPitch); + + // Lifetime of p: full algorithm + allocateVolume(D_p, dims.iVolWidth+2, dims.iVolHeight+2, pPitch); + + // Lifetime of r: full algorithm + allocateVolume(D_r, dims.iProjDets+2, dims.iProjAngles, rPitch); + + // Lifetime of w: within an iteration + allocateVolume(D_w, dims.iProjDets+2, dims.iProjAngles, wPitch); + + // TODO: check if allocations succeeded + return true; +} + + +bool CGLS::setBuffers(float* _D_volumeData, unsigned int _volumePitch, + float* _D_projData, unsigned int _projPitch) +{ + bool ok = ReconAlgo::setBuffers(_D_volumeData, _volumePitch, + _D_projData, _projPitch); + + if (!ok) + return false; + + sliceInitialized = false; + + return true; +} + +bool CGLS::copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale, + const float* pfReconstruction, unsigned int iReconstructionPitch, + const float* pfVolMask, unsigned int iVolMaskPitch, + const float* pfSinoMask, unsigned int iSinoMaskPitch) +{ + sliceInitialized = false; + + return ReconAlgo::copyDataToGPU(pfSinogram, iSinogramPitch, fSinogramScale, pfReconstruction, iReconstructionPitch, pfVolMask, iVolMaskPitch, pfSinoMask, iSinoMaskPitch); +} + +bool CGLS::iterate(unsigned int iterations) +{ + shouldAbort = false; + + if (!sliceInitialized) { + + // copy sinogram + cudaMemcpy2D(D_r, sizeof(float)*rPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + + // r = sino - A*x + if (useVolumeMask) { + // Use z as temporary storage here since it is unused + cudaMemcpy2D(D_z, sizeof(float)*zPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_z, D_maskData, zPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_z, zPitch, D_r, rPitch, -1.0f); + } else { + callFP(D_volumeData, volumePitch, D_r, rPitch, -1.0f); + } + + + // p = A'*r + zeroVolume(D_p, pPitch, dims.iVolWidth+2, dims.iVolHeight+2); + callBP(D_p, pPitch, D_r, rPitch); + if (useVolumeMask) + processVol<opMul, VOL>(D_p, D_maskData, pPitch, dims.iVolWidth, dims.iVolHeight); + + + gamma = dotProduct2D(D_p, pPitch, dims.iVolWidth, dims.iVolHeight, 1, 1); + + sliceInitialized = true; + } + + + // iteration + for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + + // w = A*p + zeroVolume(D_w, wPitch, dims.iProjDets+2, dims.iProjAngles); + callFP(D_p, pPitch, D_w, wPitch, 1.0f); + + // alpha = gamma / <w,w> + float ww = dotProduct2D(D_w, wPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + float alpha = gamma / ww; + + // x += alpha*p + processVol<opAddScaled, VOL>(D_volumeData, D_p, alpha, volumePitch, dims.iVolWidth, dims.iVolHeight); + + // r -= alpha*w + processVol<opAddScaled, SINO>(D_r, D_w, -alpha, rPitch, dims.iProjDets, dims.iProjAngles); + + + // z = A'*r + zeroVolume(D_z, zPitch, dims.iVolWidth+2, dims.iVolHeight+2); + callBP(D_z, zPitch, D_r, rPitch); + if (useVolumeMask) + processVol<opMul, VOL>(D_z, D_maskData, zPitch, dims.iVolWidth, dims.iVolHeight); + + float beta = 1.0f / gamma; + gamma = dotProduct2D(D_z, zPitch, dims.iVolWidth, dims.iVolHeight, 1, 1); + beta *= gamma; + + // p = z + beta*p + processVol<opScaleAndAdd, VOL>(D_p, D_z, beta, pPitch, dims.iVolWidth, dims.iVolHeight); + + } + + return true; +} + + +float CGLS::computeDiffNorm() +{ + // We can use w and z as temporary storage here since they're not + // used outside of iterations. + + // copy sinogram to w + cudaMemcpy2D(D_w, sizeof(float)*wPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + cudaMemcpy2D(D_z, sizeof(float)*zPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_z, D_maskData, zPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_z, zPitch, D_w, wPitch, -1.0f); + } else { + callFP(D_volumeData, volumePitch, D_w, wPitch, -1.0f); + } + + // compute norm of D_w + + float s = dotProduct2D(D_w, wPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + + return sqrt(s); +} + +bool doCGLS(float* D_volumeData, unsigned int volumePitch, + float* D_sinoData, unsigned int sinoPitch, + const SDimensions& dims, /*const SAugmentedData& augs,*/ + const float* angles, const float* TOffsets, unsigned int iterations) +{ + CGLS cgls; + bool ok = true; + + ok &= cgls.setGeometry(dims, angles); +#if 0 + if (D_maskData) + ok &= cgls.enableVolumeMask(); +#endif + if (TOffsets) + ok &= cgls.setTOffsets(TOffsets); + + if (!ok) + return false; + + ok = cgls.init(); + if (!ok) + return false; + +#if 0 + if (D_maskData) + ok &= cgls.setVolumeMask(D_maskData, maskPitch); +#endif + + ok &= cgls.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch); + if (!ok) + return false; + + ok = cgls.iterate(iterations); + + return ok; +} + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_sinoData; + + SDimensions dims; + dims.iVolWidth = 1024; + dims.iVolHeight = 1024; + dims.iProjAngles = 512; + dims.iProjDets = 1536; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + unsigned int volumePitch, sinoPitch; + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles); + printf("pitch: %u\n", sinoPitch); + + unsigned int y, x; + float* sino = loadImage("sino.png", y, x); + + float* img = new float[dims.iVolWidth*dims.iVolHeight]; + + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_sinoData, sinoPitch); + + float* angle = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) + angle[i] = i*(M_PI/dims.iProjAngles); + + CGLS cgls; + + cgls.setGeometry(dims, angle); + cgls.init(); + + cgls.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch); + + cgls.iterate(25); + + delete[] angle; + + copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + + saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img); + + return 0; +} +#endif diff --git a/cuda/2d/cgls.h b/cuda/2d/cgls.h new file mode 100644 index 0000000..1013bf8 --- /dev/null +++ b/cuda/2d/cgls.h @@ -0,0 +1,92 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_CGLS_H +#define _CUDA_CGLS_H + +#include "util.h" +#include "algo.h" + +namespace astraCUDA { + +class _AstraExport CGLS : public ReconAlgo { +public: + CGLS(); + virtual ~CGLS(); + + // disable some features + virtual bool enableSinogramMask() { return false; } + virtual bool setMinConstraint(float) { return false; } + virtual bool setMaxConstraint(float) { return false; } + + virtual bool init(); + + virtual bool setBuffers(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch); + + virtual bool copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale, + const float* pfReconstruction, unsigned int iReconstructionPitch, + const float* pfVolMask, unsigned int iVolMaskPitch, + const float* pfSinoMask, unsigned int iSinoMaskPitch); + + + virtual bool iterate(unsigned int iterations); + + virtual float computeDiffNorm(); + +protected: + void reset(); + + bool sliceInitialized; + + // Buffers + float* D_r; + unsigned int rPitch; + + float* D_w; + unsigned int wPitch; + + float* D_z; + unsigned int zPitch; + + float* D_p; + unsigned int pPitch; + + + float gamma; +}; + + +_AstraExport bool doCGLS(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, unsigned int iterations); + +} + +#endif diff --git a/cuda/2d/darthelper.cu b/cuda/2d/darthelper.cu new file mode 100644 index 0000000..db0036e --- /dev/null +++ b/cuda/2d/darthelper.cu @@ -0,0 +1,358 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "util.h" +#include "darthelper.h" +#include <cassert> + +namespace astraCUDA { + +// CUDA function for the selection of ROI +__global__ void devRoiSelect(float* in, float radius, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + float x = (float)(threadIdx.x + 16*blockIdx.x); + float y = (float)(threadIdx.y + 16*blockIdx.y); + + float w = (width-1.0f)*0.5f; + float h = (height-1.0f)*0.5f; + + if ((x-w)*(x-w) + (y-h)*(y-h) > radius * radius * 0.25f) + { + float* d = (float*)in; + unsigned int o = (y+padY)*pitch+x+padX; + d[o] = 0.0f; + } +} + +void roiSelect(float* out, float radius, unsigned int width, unsigned int height) +{ + float* D_data; + + unsigned int pitch; + allocateVolume(D_data, width+2, height+2, pitch); + copyVolumeToDevice(out, width, width, height, D_data, pitch); + + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + devRoiSelect<<<gridSize, blockSize>>>(D_data, radius, pitch, width, height, 1, 1); + + copyVolumeFromDevice(out, width, width, height, D_data, pitch); + + cudaFree(D_data); +} + + + + +// CUDA function for the masking of DART with a radius == 1 +__global__ void devDartMask(float* mask, const float* in, unsigned int conn, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > 0 && x < width - 1 && y > 0 && y < height - 1) { + float* d = (float*)in; + float* m = (float*)mask; + + unsigned int o2 = (y+padY)*pitch+x+padX; // On this row. + unsigned int o1 = o2 - pitch; // On previous row. + unsigned int o3 = o2 + pitch; // On next row. + + if ((conn == 8 && // 8-connected + (d[o1 - 1] != d[o2] || d[o1] != d[o2] || d[o1 + 1] != d[o2] || + d[o2 - 1] != d[o2] || d[o2 + 1] != d[o2] || + d[o3 - 1] != d[o2] || d[o3] != d[o2] || d[o3 + 1] != d[o2] )) + || + (conn == 4 && // 4-connected + ( d[o1] != d[o2] || + d[o2 - 1] != d[o2] || d[o3 + 1] != d[o2] || + d[o3] != d[o2] ))) + { + m[o2] = 1.0f; + } + } +} + + +// CUDA function for the masking of DART with a radius > 1 +__global__ void devDartMaskRadius(float* mask, const float* in, unsigned int conn, unsigned int radius, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > radius-1 && x < width - radius && y > radius-1 && y < height - radius) + { + float* d = (float*)in; + float* m = (float*)mask; + + int r = radius; + + // o2: index of the current center pixel + int o2 = (y+padY)*pitch+x+padX; + + if (conn == 8) // 8-connected + { + for (int row = -r; row <= r; row++) + { + int o1 = (y+padY+row)*pitch+x+padX; + for (int col = -r; col <= r; col++) + { + if (d[o1 + col] != d[o2]) {m[o2] = 1.0f; return;} + } + } + } + else if (conn == 4) // 4-connected + { + // horizontal + unsigned int o1 = (y+padY)*pitch+x+padX; + for (int col = -r; col <= r; col++) + { + if (d[o1 + col] != d[o2]) {m[o2] = 1.0f; return;} + } + + // vertical + for (int row = -r; row <= r; row++) + { + unsigned int o1 = (y+padY+row)*pitch+x+padX; + if (d[o1] != d[o2]) {m[o2] = 1.0f; return;} + } + } + } +} + + +// CUDA function for the masking of ADART with a radius == 1 +__global__ void devADartMask(float* mask, const float* in, unsigned int conn, unsigned int threshold, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > 0 && x < width - 1 && y > 0 && y < height - 1) { + float* d = (float*)in; + float* m = (float*)mask; + + unsigned int o2 = (y+padY)*pitch+x+padX; // On this row. + unsigned int o1 = o2 - pitch; // On previous row. + unsigned int o3 = o2 + pitch; // On next row. + + if (conn == 8) + { + if (d[o1 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o1 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o1 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o2 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o2 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o3 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o3 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o3 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + } + else if (conn == 4) + { + if (d[o1 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o2 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o2 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + if (d[o3 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + } + } +} + + +// CUDA function for the masking of ADART with a radius > 1 +__global__ void devADartMaskRadius(float* mask, const float* in, unsigned int conn, unsigned int radius, unsigned int threshold, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > radius-1 && x < width - radius && y > radius-1 && y < height - radius) + { + float* d = (float*)in; + float* m = (float*)mask; + + int r = radius; + + unsigned int o2 = (y+padY)*pitch+x+padX; // On this row. + + if (conn == 8) + { + for (int row = -r; row <= r; row++) + { + unsigned int o1 = (y+padY+row)*pitch+x+padX; + for (int col = -r; col <= r; col++) + { + if (d[o1+col] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + } + } + } + else if (conn == 4) + { + // horizontal + for (int col = -r; col <= r; col++) + { + if (d[o2+col] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + } + + // vertical + for (int row = -r; row <= r; row++) + { + unsigned int o1 = (y+padY+row)*pitch+x+padX; + if (d[o1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;} + } + } + } +} + + +void dartMask(float* mask, const float* segmentation, unsigned int conn, unsigned int radius, unsigned int threshold, unsigned int width, unsigned int height) +{ + float* D_segmentationData; + float* D_maskData; + + unsigned int pitch; + allocateVolume(D_segmentationData, width+2, height+2, pitch); + copyVolumeToDevice(segmentation, width, width, height, D_segmentationData, pitch); + + allocateVolume(D_maskData, width+2, height+2, pitch); + zeroVolume(D_maskData, pitch, width+2, height+2); + + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + if (threshold == 1 && radius == 1) + devDartMask<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, pitch, width, height, 1, 1); + else if (threshold > 1 && radius == 1) + devADartMask<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, threshold, pitch, width, height, 1, 1); + else if (threshold == 1 && radius > 1) + devDartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, pitch, width, height, 1, 1); + else + devADartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, threshold, pitch, width, height, 1, 1); + + copyVolumeFromDevice(mask, width, width, height, D_maskData, pitch); + + cudaFree(D_segmentationData); + cudaFree(D_maskData); + +} + + +__global__ void devDartSmoothingRadius(float* out, const float* in, float b, unsigned int radius, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > radius-1 && x < width - radius && y > radius-1 && y < height - radius) + { + float* d = (float*)in; + float* m = (float*)out; + + unsigned int o2 = (y+padY)*pitch+x+padX; + int r = radius; + float res = -d[o2]; + + for (int row = -r; row < r; row++) + { + unsigned int o1 = (y+padY+row)*pitch+x+padX; + for (int col = -r; col <= r; col++) + { + res += d[o1+col]; + } + } + + res *= b / 4*r*(r+1); + res += (1.0f-b) * d[o2]; + + m[o2] = res; + } +} + + +__global__ void devDartSmoothing(float* out, const float* in, float b, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > 0 && x < width - 1 && y > 0 && y < height - 1) { + float* d = (float*)in; + float* m = (float*)out; + + unsigned int o2 = (y+padY)*pitch+x+padX; // On this row. + unsigned int o1 = o2 - pitch; // On previous row. + unsigned int o3 = o2 + pitch; // On next row. + + m[o2] = (1.0f-b) * d[o2] + b * 0.125f * (d[o1 - 1] + d[o1] + d[o1 + 1] + d[o2 - 1] + d[o2 + 1] + d[o3 - 1] + d[o3] + d[o3 + 1]); + } +} + + +void dartSmoothing(float* out, const float* in, float b, unsigned int radius, unsigned int width, unsigned int height) +{ + float* D_inData; + float* D_outData; + + unsigned int pitch; + allocateVolume(D_inData, width+2, height+2, pitch); + copyVolumeToDevice(in, width, width, height, D_inData, pitch); + + allocateVolume(D_outData, width+2, height+2, pitch); + zeroVolume(D_outData, pitch, width+2, height+2); + + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + if (radius == 1) + devDartSmoothing<<<gridSize, blockSize>>>(D_outData, D_inData, b, pitch, width, height, 1, 1); + else + devDartSmoothingRadius<<<gridSize, blockSize>>>(D_outData, D_inData, b, radius, pitch, width, height, 1, 1); + + copyVolumeFromDevice(out, width, width, height, D_outData, pitch); + + cudaFree(D_outData); + cudaFree(D_inData); + +} + + + +bool setGPUIndex(int iGPUIndex) +{ + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + return true; +} + + +} diff --git a/cuda/2d/darthelper.h b/cuda/2d/darthelper.h new file mode 100644 index 0000000..e05f01e --- /dev/null +++ b/cuda/2d/darthelper.h @@ -0,0 +1,44 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ARITH2_H +#define _CUDA_ARITH2_H + +#include <cuda.h> + +namespace astraCUDA { + + void roiSelect(float* out, float radius, unsigned int width, unsigned int height); + void dartMask(float* out, const float* in, unsigned int conn, unsigned int radius, unsigned int threshold, unsigned int width, unsigned int height); + void dartSmoothing(float* out, const float* in, float b, unsigned int radius, unsigned int width, unsigned int height); + + bool setGPUIndex(int index); + +} + +#endif diff --git a/cuda/2d/dataop.cu b/cuda/2d/dataop.cu new file mode 100644 index 0000000..68573b2 --- /dev/null +++ b/cuda/2d/dataop.cu @@ -0,0 +1,130 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "util.h" +#include "dataop.h" +#include "arith.h" +#include <cassert> + +namespace astraCUDA { + +void operationVolumeMult(float* data1, float* data2, unsigned int width, unsigned int height) +{ + float* D_data1; + float* D_data2; + + unsigned int pitch; + allocateVolume(D_data1, width+2, height+2, pitch); + copyVolumeToDevice(data1, width, width, height, D_data1, pitch); + + allocateVolume(D_data2, width+2, height+2, pitch); + copyVolumeToDevice(data2, width, width, height, D_data2, pitch); + + processVol<opMul, VOL>(D_data1, D_data2, pitch, width, height); + + copyVolumeFromDevice(data1, width, width, height, D_data1, pitch); + + cudaFree(D_data1); + cudaFree(D_data2); +} + +void operationVolumeMultScalarMask(float* data, float* mask, float scalar, unsigned int width, unsigned int height) +{ + float* D_data; + float* D_mask; + + unsigned int pitch; + allocateVolume(D_data, width+2, height+2, pitch); + copyVolumeToDevice(data, width, width, height, D_data, pitch); + + allocateVolume(D_mask, width+2, height+2, pitch); + copyVolumeToDevice(mask, width, width, height, D_mask, pitch); + + processVol<opMulMask, VOL>(D_data, D_mask, scalar, pitch, width, height); + + copyVolumeFromDevice(data, width, width, height, D_data, pitch); + + cudaFree(D_data); + cudaFree(D_mask); +} + + +void operationVolumeMultScalar(float* data, float scalar, unsigned int width, unsigned int height) +{ + float* D_data; + + unsigned int pitch; + allocateVolume(D_data, width+2, height+2, pitch); + copyVolumeToDevice(data, width, width, height, D_data, pitch); + + processVol<opMul, VOL>(D_data, scalar, pitch, width, height); + + copyVolumeFromDevice(data, width, width, height, D_data, pitch); + + cudaFree(D_data); +} + + +void operationVolumeAdd(float* data1, float* data2, unsigned int width, unsigned int height) +{ + float* D_data1; + float* D_data2; + + unsigned int pitch; + allocateVolume(D_data1, width+2, height+2, pitch); + copyVolumeToDevice(data1, width, width, height, D_data1, pitch); + + allocateVolume(D_data2, width+2, height+2, pitch); + copyVolumeToDevice(data2, width, width, height, D_data2, pitch); + + processVol<opAdd, VOL>(D_data1, D_data2, pitch, width, height); + + copyVolumeFromDevice(data1, width, width, height, D_data1, pitch); + + cudaFree(D_data1); + cudaFree(D_data2); +} + + +void operationVolumeAddScalar(float* data, float scalar, unsigned int width, unsigned int height) +{ + float* D_data; + + unsigned int pitch; + allocateVolume(D_data, width+2, height+2, pitch); + copyVolumeToDevice(data, width, width, height, D_data, pitch); + + processVol<opAdd, VOL>(D_data, scalar, pitch, width, height); + + copyVolumeFromDevice(data, width, width, height, D_data, pitch); + + cudaFree(D_data); +} + + +} diff --git a/cuda/2d/dataop.h b/cuda/2d/dataop.h new file mode 100644 index 0000000..3e9c7e2 --- /dev/null +++ b/cuda/2d/dataop.h @@ -0,0 +1,47 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_DATAOP_H +#define _CUDA_DATAOP_H + +#include <cuda.h> + +namespace astraCUDA { + + void operationVolumeMult(float* data1, float* data2, unsigned int width, unsigned int height); + + void operationVolumeMultScalar(float* data, float scalar, unsigned int width, unsigned int height); + void operationVolumeMultScalarMask(float* data, float* mask, float scalar, unsigned int width, unsigned int height); + + void operationVolumeAdd(float* data1, float* data2, unsigned int width, unsigned int height); + + void operationVolumeAddScalar(float* data, float scalar, unsigned int width, unsigned int height); + +} + +#endif diff --git a/cuda/2d/dims.h b/cuda/2d/dims.h new file mode 100644 index 0000000..21ccb31 --- /dev/null +++ b/cuda/2d/dims.h @@ -0,0 +1,68 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_DIMS_H +#define _CUDA_DIMS_H + +namespace astraCUDA { + +struct SFanProjection { + // the source + float fSrcX, fSrcY; + + // the start of the (linear) detector + float fDetSX, fDetSY; + + // the length of a single detector pixel + float fDetUX, fDetUY; +}; + + +struct SDimensions { + unsigned int iVolWidth; + unsigned int iVolHeight; + unsigned int iProjAngles; + unsigned int iProjDets; + float fDetScale; // size of detector compared to volume pixels + unsigned int iRaysPerDet; + unsigned int iRaysPerPixelDim; +}; + +struct SDimensions3D { + unsigned int iVolX; + unsigned int iVolY; + unsigned int iVolZ; + unsigned int iProjAngles; + unsigned int iProjU; // number of detectors in the U direction + unsigned int iProjV; // number of detectors in the V direction +}; + +} + +#endif + diff --git a/cuda/2d/em.cu b/cuda/2d/em.cu new file mode 100644 index 0000000..74d1bbf --- /dev/null +++ b/cuda/2d/em.cu @@ -0,0 +1,262 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "em.h" +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +namespace astraCUDA { + + +// TODO: ensure non-negativity somewhere?? + + +EM::EM() +{ + D_projData = 0; + D_tmpData = 0; + D_pixelWeight = 0; + +} + + +EM::~EM() +{ + reset(); +} + +void EM::reset() +{ + cudaFree(D_projData); + cudaFree(D_tmpData); + cudaFree(D_pixelWeight); + + D_projData = 0; + D_tmpData = 0; + D_pixelWeight = 0; + + ReconAlgo::reset(); +} + + +bool EM::init() +{ + allocateVolume(D_pixelWeight, dims.iVolWidth+2, dims.iVolHeight+2, pixelPitch); + zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2); + + allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch); + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + + // We can't precompute pixelWeights when using a volume mask +#if 0 + if (!useVolumeMask) +#endif + precomputeWeights(); + + // TODO: check if allocations succeeded + return true; +} + +bool EM::precomputeWeights() +{ + zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2); +#if 0 + if (useSinogramMask) { + callBP(D_pixelWeight, pixelPitch, D_smaskData, smaskPitch); + } else +#endif + { + processVol<opSet, SINO>(D_projData, 1.0f, projPitch, dims.iProjDets, dims.iProjAngles); + callBP(D_pixelWeight, pixelPitch, D_projData, projPitch); + } + processVol<opInvert, VOL>(D_pixelWeight, pixelPitch, dims.iVolWidth, dims.iVolHeight); + +#if 0 + if (useVolumeMask) { + // scale pixel weights with mask to zero out masked pixels + processVol<opMul, VOL>(D_pixelWeight, D_maskData, pixelPitch, dims.iVolWidth, dims.iVolHeight); + } +#endif + + return true; +} + +bool EM::iterate(unsigned int iterations) +{ + shouldAbort = false; + +#if 0 + if (useVolumeMask) + precomputeWeights(); +#endif + + // iteration + for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + + // Do FP of volumeData + zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + callFP(D_volumeData, volumePitch, D_projData, projPitch, 1.0f); + + // Divide sinogram by FP (into projData) + processVol<opDividedBy, SINO>(D_projData, D_sinoData, projPitch, dims.iProjDets, dims.iProjAngles); + + // Do BP of projData into tmpData + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + callBP(D_tmpData, tmpPitch, D_projData, projPitch); + + // Multiply volumeData with tmpData divided by pixel weights + processVol<opMul2, VOL>(D_volumeData, D_tmpData, D_pixelWeight, pixelPitch, dims.iVolWidth, dims.iVolHeight); + + } + + return true; +} + +float EM::computeDiffNorm() +{ + // copy sinogram to projection data + cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f); + } else { + callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f); + } + + + // compute norm of D_projData + + float s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + + return sqrt(s); +} + + +bool doEM(float* D_volumeData, unsigned int volumePitch, + float* D_sinoData, unsigned int sinoPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, unsigned int iterations) +{ + EM em; + bool ok = true; + + ok &= em.setGeometry(dims, angles); + if (TOffsets) + ok &= em.setTOffsets(TOffsets); + + if (!ok) + return false; + + ok = em.init(); + if (!ok) + return false; + + ok &= em.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch); + if (!ok) + return false; + + ok = em.iterate(iterations); + + return ok; +} + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_sinoData; + + SDimensions dims; + dims.iVolWidth = 1024; + dims.iVolHeight = 1024; + dims.iProjAngles = 512; + dims.iProjDets = 1536; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + unsigned int volumePitch, sinoPitch; + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles); + printf("pitch: %u\n", sinoPitch); + + unsigned int y, x; + float* sino = loadImage("sino.png", y, x); + + float* img = new float[dims.iVolWidth*dims.iVolHeight]; + + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_sinoData, sinoPitch); + + float* angle = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) + angle[i] = i*(M_PI/dims.iProjAngles); + + EM em; + + em.setGeometry(dims, angle); + em.init(); + + // TODO: Initialize D_volumeData with an unfiltered backprojection + + em.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch); + + em.iterate(25); + + + delete[] angle; + + copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + + saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img); + + return 0; +} + +#endif diff --git a/cuda/2d/em.h b/cuda/2d/em.h new file mode 100644 index 0000000..5a9ffed --- /dev/null +++ b/cuda/2d/em.h @@ -0,0 +1,77 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_EM_H +#define _CUDA_EM_H + +#include "util.h" +#include "algo.h" + +namespace astraCUDA { + +class _AstraExport EM : public ReconAlgo { +public: + EM(); + virtual ~EM(); + + // disable some features + virtual bool enableSinogramMask() { return false; } + virtual bool enableVolumeMask() { return false; } + virtual bool setMinConstraint(float) { return false; } + virtual bool setMaxConstraint(float) { return false; } + + virtual bool init(); + + virtual bool iterate(unsigned int iterations); + + virtual float computeDiffNorm(); + +protected: + void reset(); + bool precomputeWeights(); + + // Temporary buffers + float* D_projData; + unsigned int projPitch; + + float* D_tmpData; + unsigned int tmpPitch; + + // Geometry-specific precomputed data + float* D_pixelWeight; + unsigned int pixelPitch; +}; + +_AstraExport bool doEM(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, unsigned int iterations); + +} + +#endif diff --git a/cuda/2d/fan_bp.cu b/cuda/2d/fan_bp.cu new file mode 100644 index 0000000..1edc6d9 --- /dev/null +++ b/cuda/2d/fan_bp.cu @@ -0,0 +1,374 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> + +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +#define PIXELTRACE + + +typedef texture<float, 2, cudaReadModeElementType> texture2D; + +static texture2D gT_FanProjTexture; + + +namespace astraCUDA { + +const unsigned int g_anglesPerBlock = 16; +const unsigned int g_blockSliceSize = 32; +const unsigned int g_blockSlices = 16; + +const unsigned int g_MaxAngles = 2560; + +__constant__ float gC_SrcX[g_MaxAngles]; +__constant__ float gC_SrcY[g_MaxAngles]; +__constant__ float gC_DetSX[g_MaxAngles]; +__constant__ float gC_DetSY[g_MaxAngles]; +__constant__ float gC_DetUX[g_MaxAngles]; +__constant__ float gC_DetUY[g_MaxAngles]; + + +static bool bindProjDataTexture(float* data, unsigned int pitch, unsigned int width, unsigned int height) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_FanProjTexture.addressMode[0] = cudaAddressModeClamp; + gT_FanProjTexture.addressMode[1] = cudaAddressModeClamp; + gT_FanProjTexture.filterMode = cudaFilterModeLinear; + gT_FanProjTexture.normalized = false; + + cudaBindTexture2D(0, gT_FanProjTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch); + + // TODO: error value? + + return true; +} + +__global__ void devFanBP(float* D_volData, unsigned int volPitch, unsigned int startAngle, const SDimensions dims) +{ + const int relX = threadIdx.x; + const int relY = threadIdx.y; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + const int X = blockIdx.x * g_blockSlices + relX; + const int Y = blockIdx.y * g_blockSliceSize + relY; + + if (X >= dims.iVolWidth || Y >= dims.iVolHeight) + return; + + const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f ); + const float fY = - ( Y - 0.5f*dims.iVolHeight + 0.5f ); + + float* volData = (float*)D_volData; + + float fVal = 0.0f; + float fA = startAngle + 0.5f; + + // TODO: Distance correction? + + for (int angle = startAngle; angle < endAngle; ++angle) + { + const float fSrcX = gC_SrcX[angle]; + const float fSrcY = gC_SrcY[angle]; + const float fDetSX = gC_DetSX[angle]; + const float fDetSY = gC_DetSY[angle]; + const float fDetUX = gC_DetUX[angle]; + const float fDetUY = gC_DetUY[angle]; + + const float fXD = fSrcX - fX; + const float fYD = fSrcY - fY; + + const float fNum = fDetSY * fXD - fDetSX * fYD + fX*fSrcY - fY*fSrcX; + const float fDen = fDetUX * fYD - fDetUY * fXD; + + const float fT = fNum / fDen + 1.0f; + fVal += tex2D(gT_FanProjTexture, fT, fA); + fA += 1.0f; + } + + volData[(Y+1)*volPitch+X+1] += fVal; +} + +// supersampling version +__global__ void devFanBP_SS(float* D_volData, unsigned int volPitch, unsigned int startAngle, const SDimensions dims) +{ + const int relX = threadIdx.x; + const int relY = threadIdx.y; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + const int X = blockIdx.x * g_blockSlices + relX; + const int Y = blockIdx.y * g_blockSliceSize + relY; + + if (X >= dims.iVolWidth || Y >= dims.iVolHeight) + return; + + const float fXb = ( X - 0.5f*dims.iVolWidth + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim); + const float fYb = - ( Y - 0.5f*dims.iVolHeight + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim); + + const float fSubStep = 1.0f/dims.iRaysPerPixelDim; + + float* volData = (float*)D_volData; + + float fVal = 0.0f; + float fA = startAngle + 0.5f; + + // TODO: Distance correction? + + for (int angle = startAngle; angle < endAngle; ++angle) + { + const float fSrcX = gC_SrcX[angle]; + const float fSrcY = gC_SrcY[angle]; + const float fDetSX = gC_DetSX[angle]; + const float fDetSY = gC_DetSY[angle]; + const float fDetUX = gC_DetUX[angle]; + const float fDetUY = gC_DetUY[angle]; + + // TODO: Optimize these loops... + float fX = fXb; + for (int iSubX = 0; iSubX < dims.iRaysPerPixelDim; ++iSubX) { + float fY = fYb; + for (int iSubY = 0; iSubY < dims.iRaysPerPixelDim; ++iSubY) { + const float fXD = fSrcX - fX; + const float fYD = fSrcY - fY; + + const float fNum = fDetSY * fXD - fDetSX * fYD + fX*fSrcY - fY*fSrcX; + const float fDen = fDetUX * fYD - fDetUY * fXD; + + const float fT = fNum / fDen + 1.0f; + fVal += tex2D(gT_FanProjTexture, fT, fA); + fY -= fSubStep; + } + fX += fSubStep; + } + fA += 1.0f; + } + + volData[(Y+1)*volPitch+X+1] += fVal / (dims.iRaysPerPixelDim * dims.iRaysPerPixelDim); +} + + +// BP specifically for SART. +// It includes (free) weighting with voxel weight. +// It assumes the proj texture is set up _without_ padding, unlike regular BP. +__global__ void devFanBP_SART(float* D_volData, unsigned int volPitch, const SDimensions dims) +{ + const int relX = threadIdx.x; + const int relY = threadIdx.y; + + const int X = blockIdx.x * g_blockSlices + relX; + const int Y = blockIdx.y * g_blockSliceSize + relY; + + if (X >= dims.iVolWidth || Y >= dims.iVolHeight) + return; + + const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f ); + const float fY = - ( Y - 0.5f*dims.iVolHeight + 0.5f ); + + float* volData = (float*)D_volData; + + // TODO: Distance correction? + + // TODO: Constant memory vs parameters. + const float fSrcX = gC_SrcX[0]; + const float fSrcY = gC_SrcY[0]; + const float fDetSX = gC_DetSX[0]; + const float fDetSY = gC_DetSY[0]; + const float fDetUX = gC_DetUX[0]; + const float fDetUY = gC_DetUY[0]; + + const float fXD = fSrcX - fX; + const float fYD = fSrcY - fY; + + const float fNum = fDetSY * fXD - fDetSX * fYD + fX*fSrcY - fY*fSrcX; + const float fDen = fDetUX * fYD - fDetUY * fXD; + + const float fT = fNum / fDen; + const float fVal = tex2D(gT_FanProjTexture, fT, 0.5f); + + volData[(Y+1)*volPitch+X+1] += fVal; +} + + +bool FanBP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const SFanProjection* angles) +{ + // TODO: process angles block by block + assert(dims.iProjAngles <= g_MaxAngles); + + bindProjDataTexture(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT(SrcX); + TRANSFER_TO_CONSTANT(SrcY); + TRANSFER_TO_CONSTANT(DetSX); + TRANSFER_TO_CONSTANT(DetSY); + TRANSFER_TO_CONSTANT(DetUX); + TRANSFER_TO_CONSTANT(DetUY); + +#undef TRANSFER_TO_CONSTANT + + delete[] tmp; + + dim3 dimBlock(g_blockSlices, g_blockSliceSize); + dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices, + (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize); + + cudaStream_t stream; + cudaStreamCreate(&stream); + + for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) { + if (dims.iRaysPerPixelDim > 1) + devFanBP_SS<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, dims); + else + devFanBP<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, dims); + } + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + cudaStreamDestroy(stream); + + return true; +} + + +// D_projData is a pointer to one padded sinogram line +bool FanBP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle, + const SDimensions& dims, const SFanProjection* angles) +{ + // only one angle + bindProjDataTexture(D_projData, projPitch, dims.iProjDets, 1); + + // transfer angle to constant memory +#define TRANSFER_TO_CONSTANT(name) do { cudaMemcpyToSymbol(gC_##name, &(angles[angle].f##name), sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT(SrcX); + TRANSFER_TO_CONSTANT(SrcY); + TRANSFER_TO_CONSTANT(DetSX); + TRANSFER_TO_CONSTANT(DetSY); + TRANSFER_TO_CONSTANT(DetUX); + TRANSFER_TO_CONSTANT(DetUY); + +#undef TRANSFER_TO_CONSTANT + + dim3 dimBlock(g_blockSlices, g_blockSliceSize); + dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices, + (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize); + + devFanBP_SART<<<dimGrid, dimBlock>>>(D_volumeData, volumePitch, dims); + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + return true; +} + + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_projData; + + SDimensions dims; + dims.iVolWidth = 128; + dims.iVolHeight = 128; + dims.iProjAngles = 180; + dims.iProjDets = 256; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + unsigned int volumePitch, projPitch; + + SFanProjection projs[180]; + + projs[0].fSrcX = 0.0f; + projs[0].fSrcY = 1536.0f; + projs[0].fDetSX = 128.0f; + projs[0].fDetSY = -512.0f; + projs[0].fDetUX = -1.0f; + projs[0].fDetUY = 0.0f; + +#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = projs[0].f##name##X * cos(alpha) - projs[0].f##name##Y * sin(alpha); projs[i].f##name##Y = projs[0].f##name##X * sin(alpha) + projs[0].f##name##Y * cos(alpha); } while(0) + + for (int i = 1; i < 180; ++i) { + ROTATE0(Src, i, i*2*M_PI/180); + ROTATE0(DetS, i, i*2*M_PI/180); + ROTATE0(DetU, i, i*2*M_PI/180); + } + +#undef ROTATE0 + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + printf("pitch: %u\n", projPitch); + + unsigned int y, x; + float* sino = loadImage("sino.png", y, x); + + float* img = new float[dims.iVolWidth*dims.iVolHeight]; + + memset(img, 0, dims.iVolWidth*dims.iVolHeight*sizeof(float)); + + copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch); + + FanBP(D_volumeData, volumePitch, D_projData, projPitch, dims, projs); + + copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + + saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img); + + return 0; +} +#endif diff --git a/cuda/2d/fan_bp.h b/cuda/2d/fan_bp.h new file mode 100644 index 0000000..a4e62be --- /dev/null +++ b/cuda/2d/fan_bp.h @@ -0,0 +1,45 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_FAN_BP_H +#define _CUDA_FAN_BP_H + +namespace astraCUDA { + +_AstraExport bool FanBP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const SFanProjection* angles); + +_AstraExport bool FanBP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle, + const SDimensions& dims, const SFanProjection* angles); + +} + +#endif diff --git a/cuda/2d/fan_fp.cu b/cuda/2d/fan_fp.cu new file mode 100644 index 0000000..cf9f352 --- /dev/null +++ b/cuda/2d/fan_fp.cu @@ -0,0 +1,370 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + + +typedef texture<float, 2, cudaReadModeElementType> texture2D; + +static texture2D gT_FanVolumeTexture; + + +namespace astraCUDA { + +static const unsigned g_MaxAngles = 2560; +__constant__ float gC_SrcX[g_MaxAngles]; +__constant__ float gC_SrcY[g_MaxAngles]; +__constant__ float gC_DetSX[g_MaxAngles]; +__constant__ float gC_DetSY[g_MaxAngles]; +__constant__ float gC_DetUX[g_MaxAngles]; +__constant__ float gC_DetUY[g_MaxAngles]; + + +// optimization parameters +static const unsigned int g_anglesPerBlock = 16; +static const unsigned int g_detBlockSize = 32; +static const unsigned int g_blockSlices = 64; + +static bool bindVolumeDataTexture(float* data, cudaArray*& dataArray, unsigned int pitch, unsigned int width, unsigned int height) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + dataArray = 0; + cudaMallocArray(&dataArray, &channelDesc, width, height); + cudaMemcpy2DToArray(dataArray, 0, 0, data, pitch*sizeof(float), width*sizeof(float), height, cudaMemcpyDeviceToDevice); + + gT_FanVolumeTexture.addressMode[0] = cudaAddressModeClamp; + gT_FanVolumeTexture.addressMode[1] = cudaAddressModeClamp; + gT_FanVolumeTexture.filterMode = cudaFilterModeLinear; + gT_FanVolumeTexture.normalized = false; + + // TODO: For very small sizes (roughly <=512x128) with few angles (<=180) + // not using an array is more efficient. + //cudaBindTexture2D(0, gT_FanVolumeTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch); + cudaBindTextureToArray(gT_FanVolumeTexture, dataArray, channelDesc); + + // TODO: error value? + + return true; +} + +// projection for angles that are roughly horizontal +// (detector roughly vertical) +__global__ void FanFPhorizontal(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale) +{ + float* projData = (float*)D_projData; + const int relDet = threadIdx.x; + const int relAngle = threadIdx.y; + + const int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle; + if (angle >= endAngle) + return; + + const int detector = blockIdx.y * g_detBlockSize + relDet; + + if (detector < 0 || detector >= dims.iProjDets) + return; + + const float fSrcX = gC_SrcX[angle]; + const float fSrcY = gC_SrcY[angle]; + const float fDetSX = gC_DetSX[angle]; + const float fDetSY = gC_DetSY[angle]; + const float fDetUX = gC_DetUX[angle]; + const float fDetUY = gC_DetUY[angle]; + + float fVal = 0.0f; + + const float fdx = fabsf(fDetSX + detector*fDetUX + 0.5f - fSrcX); + const float fdy = fabsf(fDetSY + detector*fDetUY + 0.5f - fSrcY); + + if (fdy > fdx) + return; + + + for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) { + const float fDet = detector + (0.5f + iSubT) / dims.iRaysPerDet; + + const float fDetX = fDetSX + fDet * fDetUX; + const float fDetY = fDetSY + fDet * fDetUY; + + // ray: y = alpha * x + beta + const float alpha = (fSrcY - fDetY) / (fSrcX - fDetX); + const float beta = fSrcY - alpha * fSrcX; + + const float fDistCorr = sqrt(alpha*alpha+1.0f) * outputScale / dims.iRaysPerDet; + + // intersect ray with first slice + + float fY = -alpha * (startSlice - 0.5f*dims.iVolWidth + 0.5f) - beta + 0.5f*dims.iVolHeight - 0.5f + 1.5f; + float fX = startSlice + 1.5f; + + int endSlice = startSlice + g_blockSlices; + if (endSlice > dims.iVolWidth) + endSlice = dims.iVolWidth; + + float fV = 0.0f; + for (int slice = startSlice; slice < endSlice; ++slice) + { + fV += tex2D(gT_FanVolumeTexture, fX, fY); + fY -= alpha; + fX += 1.0f; + } + + fVal += fV * fDistCorr; + + } + + projData[angle*projPitch+detector+1] += fVal; +} + + +// projection for angles that are roughly vertical +// (detector roughly horizontal) +__global__ void FanFPvertical(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale) +{ + const int relDet = threadIdx.x; + const int relAngle = threadIdx.y; + + const int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle; + + if (angle >= endAngle) + return; + + const int detector = blockIdx.y * g_detBlockSize + relDet; + + if (detector < 0 || detector >= dims.iProjDets) + return; + + float* projData = (float*)D_projData; + + const float fSrcX = gC_SrcX[angle]; + const float fSrcY = gC_SrcY[angle]; + const float fDetSX = gC_DetSX[angle]; + const float fDetSY = gC_DetSY[angle]; + const float fDetUX = gC_DetUX[angle]; + const float fDetUY = gC_DetUY[angle]; + + float fVal = 0.0f; + + const float fdx = fabsf(fDetSX + detector*fDetUX + 0.5f - fSrcX); + const float fdy = fabsf(fDetSY + detector*fDetUY + 0.5f - fSrcY); + + if (fdy <= fdx) + return; + + + for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) { + const float fDet = detector + (0.5f + iSubT) / dims.iRaysPerDet /*- gC_angle_offset[angle]*/; + + const float fDetX = fDetSX + fDet * fDetUX; + const float fDetY = fDetSY + fDet * fDetUY; + + // ray: x = alpha * y + beta + const float alpha = (fSrcX - fDetX) / (fSrcY - fDetY); + const float beta = fSrcX - alpha * fSrcY; + + const float fDistCorr = sqrt(alpha*alpha+1) * outputScale / dims.iRaysPerDet; + + // intersect ray with first slice + + float fX = -alpha * (startSlice - 0.5f*dims.iVolHeight + 0.5f) + beta + 0.5f*dims.iVolWidth - 0.5f + 1.5f; + float fY = startSlice + 1.5f; + + int endSlice = startSlice + g_blockSlices; + if (endSlice > dims.iVolHeight) + endSlice = dims.iVolHeight; + + float fV = 0.0f; + + for (int slice = startSlice; slice < endSlice; ++slice) + { + fV += tex2D(gT_FanVolumeTexture, fX, fY); + fX -= alpha; + fY += 1.0f; + } + + fVal += fV * fDistCorr; + + } + + projData[angle*projPitch+detector+1] += fVal; +} + +bool FanFP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const SFanProjection* angles, + float outputScale) +{ + // TODO: load angles into constant memory in smaller blocks + assert(dims.iProjAngles <= g_MaxAngles); + + cudaArray* D_dataArray; + bindVolumeDataTexture(D_volumeData, D_dataArray, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT(SrcX); + TRANSFER_TO_CONSTANT(SrcY); + TRANSFER_TO_CONSTANT(DetSX); + TRANSFER_TO_CONSTANT(DetSY); + TRANSFER_TO_CONSTANT(DetUX); + TRANSFER_TO_CONSTANT(DetUY); + +#undef TRANSFER_TO_CONSTANT + + delete[] tmp; + + dim3 dimBlock(g_detBlockSize, g_anglesPerBlock); // region size, angles + const unsigned int g_blockSliceSize = g_detBlockSize; + + std::list<cudaStream_t> streams; + + + unsigned int blockStart = 0; + unsigned int blockEnd = dims.iProjAngles; + + dim3 dimGrid((blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock, + (dims.iProjDets+g_blockSliceSize-1)/g_blockSliceSize); // angle blocks, regions + cudaStream_t stream1; + cudaStreamCreate(&stream1); + streams.push_back(stream1); + for (unsigned int i = 0; i < dims.iVolWidth; i += g_blockSlices) + FanFPhorizontal<<<dimGrid, dimBlock, 0, stream1>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale); + + cudaStream_t stream2; + cudaStreamCreate(&stream2); + streams.push_back(stream2); + for (unsigned int i = 0; i < dims.iVolHeight; i += g_blockSlices) + FanFPvertical<<<dimGrid, dimBlock, 0, stream2>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale); + + cudaStreamDestroy(stream1); + cudaStreamDestroy(stream2); + + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + cudaFreeArray(D_dataArray); + + return true; +} + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_projData; + + SDimensions dims; + dims.iVolWidth = 128; + dims.iVolHeight = 128; + dims.iProjAngles = 180; + dims.iProjDets = 256; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + unsigned int volumePitch, projPitch; + + SFanProjection projs[180]; + + projs[0].fSrcX = 0.0f; + projs[0].fSrcY = 1536.0f; + projs[0].fDetSX = 128.0f; + projs[0].fDetSY = -512.0f; + projs[0].fDetUX = -1.0f; + projs[0].fDetUY = 0.0f; + +#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = projs[0].f##name##X * cos(alpha) - projs[0].f##name##Y * sin(alpha); projs[i].f##name##Y = projs[0].f##name##X * sin(alpha) + projs[0].f##name##Y * cos(alpha); } while(0) + + for (int i = 1; i < 180; ++i) { + ROTATE0(Src, i, i*2*M_PI/180); + ROTATE0(DetS, i, i*2*M_PI/180); + ROTATE0(DetU, i, i*2*M_PI/180); + } + +#undef ROTATE0 + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + printf("pitch: %u\n", projPitch); + + unsigned int y, x; + float* img = loadImage("phantom128.png", y, x); + + float* sino = new float[dims.iProjAngles * dims.iProjDets]; + + memset(sino, 0, dims.iProjAngles * dims.iProjDets * sizeof(float)); + + copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch); + + float* angle = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) + angle[i] = i*(M_PI/dims.iProjAngles); + + FanFP(D_volumeData, volumePitch, D_projData, projPitch, dims, projs, 1.0f); + + delete[] angle; + + copySinogramFromDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch); + + float s = 0.0f; + for (unsigned int y = 0; y < dims.iProjAngles; ++y) + for (unsigned int x = 0; x < dims.iProjDets; ++x) + s += sino[y*dims.iProjDets+x] * sino[y*dims.iProjDets+x]; + printf("cpu norm: %f\n", s); + + //zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + printf("gpu norm: %f\n", s); + + saveImage("sino.png",dims.iProjAngles,dims.iProjDets,sino); + + + return 0; +} +#endif diff --git a/cuda/2d/fan_fp.h b/cuda/2d/fan_fp.h new file mode 100644 index 0000000..0734f40 --- /dev/null +++ b/cuda/2d/fan_fp.h @@ -0,0 +1,41 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_FAN_FP_H +#define _CUDA_FAN_FP_H + +namespace astraCUDA { + +_AstraExport bool FanFP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const SFanProjection* angles, + float outputScale); + +} + +#endif diff --git a/cuda/2d/fbp_filters.h b/cuda/2d/fbp_filters.h new file mode 100644 index 0000000..1232f8e --- /dev/null +++ b/cuda/2d/fbp_filters.h @@ -0,0 +1,58 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef FBP_FILTERS_H +#define FBP_FILTERS_H + +enum E_FBPFILTER +{ + FILTER_NONE, //< no filter (regular BP) + FILTER_RAMLAK, //< default FBP filter + FILTER_SHEPPLOGAN, //< Shepp-Logan + FILTER_COSINE, //< Cosine + FILTER_HAMMING, //< Hamming filter + FILTER_HANN, //< Hann filter + FILTER_TUKEY, //< Tukey filter + FILTER_LANCZOS, //< Lanczos filter + FILTER_TRIANGULAR, //< Triangular filter + FILTER_GAUSSIAN, //< Gaussian filter + FILTER_BARTLETTHANN, //< Bartlett-Hann filter + FILTER_BLACKMAN, //< Blackman filter + FILTER_NUTTALL, //< Nuttall filter, continuous first derivative + FILTER_BLACKMANHARRIS, //< Blackman-Harris filter + FILTER_BLACKMANNUTTALL, //< Blackman-Nuttall filter + FILTER_FLATTOP, //< Flat top filter + FILTER_KAISER, //< Kaiser filter + FILTER_PARZEN, //< Parzen filter + FILTER_PROJECTION, //< all projection directions share one filter + FILTER_SINOGRAM, //< every projection direction has its own filter + FILTER_RPROJECTION, //< projection filter in real space (as opposed to fourier space) + FILTER_RSINOGRAM, //< sinogram filter in real space +}; + +#endif /* FBP_FILTERS_H */ diff --git a/cuda/2d/fft.cu b/cuda/2d/fft.cu new file mode 100644 index 0000000..79e4be7 --- /dev/null +++ b/cuda/2d/fft.cu @@ -0,0 +1,873 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "fft.h" +#include "util.h" + +#include <cufft.h> +#include <iostream> +#include <cuda.h> +#include <fstream> + +#include "../../include/astra/Logger.h" + +using namespace astra; + +// TODO: evaluate what we want to do in these situations: + +#define CHECK_ERROR(errorMessage) do { \ + cudaError_t err = cudaThreadSynchronize(); \ + if( cudaSuccess != err) { \ + fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n", \ + errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\ + CLogger::writeTerminalCUDAError(__FILE__, __LINE__, cudaGetErrorString( err)); \ + exit(EXIT_FAILURE); \ + } } while (0) + +#define SAFE_CALL( call) do { \ + cudaError err = call; \ + if( cudaSuccess != err) { \ + fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n", \ + __FILE__, __LINE__, cudaGetErrorString( err) ); \ + CLogger::writeTerminalCUDAError(__FILE__, __LINE__, cudaGetErrorString( err)); \ + exit(EXIT_FAILURE); \ + } \ + err = cudaThreadSynchronize(); \ + if( cudaSuccess != err) { \ + fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n", \ + __FILE__, __LINE__, cudaGetErrorString( err) ); \ + CLogger::writeTerminalCUDAError(__FILE__, __LINE__, cudaGetErrorString( err)); \ + exit(EXIT_FAILURE); \ + } } while (0) + + +__global__ static void applyFilter_kernel(int _iProjectionCount, + int _iFreqBinCount, + cufftComplex * _pSinogram, + cufftComplex * _pFilter) +{ + int iIndex = threadIdx.x + blockIdx.x * blockDim.x; + int iProjectionIndex = iIndex / _iFreqBinCount; + + if(iProjectionIndex >= _iProjectionCount) + { + return; + } + + float fA = _pSinogram[iIndex].x; + float fB = _pSinogram[iIndex].y; + float fC = _pFilter[iIndex].x; + float fD = _pFilter[iIndex].y; + + _pSinogram[iIndex].x = fA * fC - fB * fD; + _pSinogram[iIndex].y = fA * fD + fC * fB; +} + +__global__ static void rescaleInverseFourier_kernel(int _iProjectionCount, + int _iDetectorCount, + float* _pfInFourierOutput) +{ + int iIndex = threadIdx.x + blockIdx.x * blockDim.x; + int iProjectionIndex = iIndex / _iDetectorCount; + int iDetectorIndex = iIndex % _iDetectorCount; + + if(iProjectionIndex >= _iProjectionCount) + { + return; + } + + _pfInFourierOutput[iProjectionIndex * _iDetectorCount + iDetectorIndex] /= (float)_iDetectorCount; +} + +static void rescaleInverseFourier(int _iProjectionCount, int _iDetectorCount, + float * _pfInFourierOutput) +{ + const int iBlockSize = 256; + int iElementCount = _iProjectionCount * _iDetectorCount; + int iBlockCount = (iElementCount + iBlockSize - 1) / iBlockSize; + + rescaleInverseFourier_kernel<<< iBlockCount, iBlockSize >>>(_iProjectionCount, + _iDetectorCount, + _pfInFourierOutput); + CHECK_ERROR("rescaleInverseFourier_kernel failed"); +} + +void applyFilter(int _iProjectionCount, int _iFreqBinCount, + cufftComplex * _pSinogram, cufftComplex * _pFilter) +{ + const int iBlockSize = 256; + int iElementCount = _iProjectionCount * _iFreqBinCount; + int iBlockCount = (iElementCount + iBlockSize - 1) / iBlockSize; + + applyFilter_kernel<<< iBlockCount, iBlockSize >>>(_iProjectionCount, + _iFreqBinCount, + _pSinogram, _pFilter); + CHECK_ERROR("applyFilter_kernel failed"); +} + +static bool invokeCudaFFT(int _iProjectionCount, int _iDetectorCount, + const float * _pfDevSource, + cufftComplex * _pDevTargetComplex) +{ + cufftHandle plan; + cufftResult result; + + result = cufftPlan1d(&plan, _iDetectorCount, CUFFT_R2C, _iProjectionCount); + if(result != CUFFT_SUCCESS) + { + std::cerr << "Failed to plan 1d r2c fft" << std::endl; + return false; + } + + result = cufftExecR2C(plan, (cufftReal *)_pfDevSource, _pDevTargetComplex); + cufftDestroy(plan); + + if(result != CUFFT_SUCCESS) + { + std::cerr << "Failed to exec 1d r2c fft" << std::endl; + return false; + } + + return true; +} + +static bool invokeCudaIFFT(int _iProjectionCount, int _iDetectorCount, + const cufftComplex * _pDevSourceComplex, + float * _pfDevTarget) +{ + cufftHandle plan; + cufftResult result; + + result = cufftPlan1d(&plan, _iDetectorCount, CUFFT_C2R, _iProjectionCount); + if(result != CUFFT_SUCCESS) + { + std::cerr << "Failed to plan 1d c2r fft" << std::endl; + return false; + } + + // todo: why do we have to get rid of the const qualifier? + result = cufftExecC2R(plan, (cufftComplex *)_pDevSourceComplex, + (cufftReal *)_pfDevTarget); + cufftDestroy(plan); + + if(result != CUFFT_SUCCESS) + { + std::cerr << "Failed to exec 1d c2r fft" << std::endl; + return false; + } + + return true; +} + +bool allocateComplexOnDevice(int _iProjectionCount, int _iDetectorCount, + cufftComplex ** _ppDevComplex) +{ + size_t bufferSize = sizeof(cufftComplex) * _iProjectionCount * _iDetectorCount; + SAFE_CALL(cudaMalloc((void **)_ppDevComplex, bufferSize)); + return true; +} + +bool freeComplexOnDevice(cufftComplex * _pDevComplex) +{ + SAFE_CALL(cudaFree(_pDevComplex)); + return true; +} + +bool uploadComplexArrayToDevice(int _iProjectionCount, int _iDetectorCount, + cufftComplex * _pHostComplexSource, + cufftComplex * _pDevComplexTarget) +{ + size_t memSize = sizeof(cufftComplex) * _iProjectionCount * _iDetectorCount; + SAFE_CALL(cudaMemcpy(_pDevComplexTarget, _pHostComplexSource, memSize, cudaMemcpyHostToDevice)); + + return true; +} + +bool runCudaFFT(int _iProjectionCount, const float * _pfDevRealSource, + int _iSourcePitch, int _iSourcePadX, int _iProjDets, + int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount, + cufftComplex * _pDevTargetComplex) +{ + float * pfDevRealFFTSource = NULL; + size_t bufferMemSize = sizeof(float) * _iProjectionCount * _iFFTRealDetectorCount; + + SAFE_CALL(cudaMalloc((void **)&pfDevRealFFTSource, bufferMemSize)); + SAFE_CALL(cudaMemset(pfDevRealFFTSource, 0, bufferMemSize)); + + for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++) + { + const float * pfSourceLocation = _pfDevRealSource + iProjectionIndex * _iSourcePitch + _iSourcePadX; + float * pfTargetLocation = pfDevRealFFTSource + iProjectionIndex * _iFFTRealDetectorCount; + + SAFE_CALL(cudaMemcpy(pfTargetLocation, pfSourceLocation, sizeof(float) * _iProjDets, cudaMemcpyDeviceToDevice)); + } + + bool bResult = invokeCudaFFT(_iProjectionCount, _iFFTRealDetectorCount, + pfDevRealFFTSource, _pDevTargetComplex); + if(!bResult) + { + return false; + } + + SAFE_CALL(cudaFree(pfDevRealFFTSource)); + + return true; +} + +bool runCudaIFFT(int _iProjectionCount, const cufftComplex* _pDevSourceComplex, + float * _pfRealTarget, + int _iTargetPitch, int _iTargetPadX, int _iProjDets, + int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount) +{ + float * pfDevRealFFTTarget = NULL; + size_t bufferMemSize = sizeof(float) * _iProjectionCount * _iFFTRealDetectorCount; + + SAFE_CALL(cudaMalloc((void **)&pfDevRealFFTTarget, bufferMemSize)); + + bool bResult = invokeCudaIFFT(_iProjectionCount, _iFFTRealDetectorCount, + _pDevSourceComplex, pfDevRealFFTTarget); + if(!bResult) + { + return false; + } + + rescaleInverseFourier(_iProjectionCount, _iFFTRealDetectorCount, + pfDevRealFFTTarget); + + SAFE_CALL(cudaMemset(_pfRealTarget, 0, sizeof(float) * _iProjectionCount * _iTargetPitch)); + + for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++) + { + const float * pfSourceLocation = pfDevRealFFTTarget + iProjectionIndex * _iFFTRealDetectorCount; + float* pfTargetLocation = _pfRealTarget + iProjectionIndex * _iTargetPitch + _iTargetPadX; + + SAFE_CALL(cudaMemcpy(pfTargetLocation, pfSourceLocation, sizeof(float) * _iProjDets, cudaMemcpyDeviceToDevice)); + } + + SAFE_CALL(cudaFree(pfDevRealFFTTarget)); + + return true; +} + + +// Because the input is real, the Fourier transform is symmetric. +// CUFFT only outputs the first half (ignoring the redundant second half), +// and expects the same as input for the IFFT. +int calcFFTFourSize(int _iFFTRealSize) +{ + int iFFTFourSize = _iFFTRealSize / 2 + 1; + + return iFFTFourSize; +} + +void genIdenFilter(int _iProjectionCount, cufftComplex * _pFilter, + int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount) +{ + for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++) + { + for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + int iIndex = iDetectorIndex + iProjectionIndex * _iFFTFourierDetectorCount; + _pFilter[iIndex].x = 1.0f; + _pFilter[iIndex].y = 0.0f; + } + } +} + +void genFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, + cufftComplex * _pFilter, int _iFFTRealDetectorCount, + int _iFFTFourierDetectorCount, float _fParameter /* = -1.0f */) +{ + float * pfFilt = new float[_iFFTFourierDetectorCount]; + float * pfW = new float[_iFFTFourierDetectorCount]; + + for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fRelIndex = (float)iDetectorIndex / (float)_iFFTRealDetectorCount; + + // filt = 2*( 0:(order/2) )./order; + pfFilt[iDetectorIndex] = 2.0f * fRelIndex; + //pfFilt[iDetectorIndex] = 1.0f; + + // w = 2*pi*(0:size(filt,2)-1)/order + pfW[iDetectorIndex] = 3.1415f * 2.0f * fRelIndex; + } + + switch(_eFilter) + { + case FILTER_RAMLAK: + { + // do nothing + break; + } + case FILTER_SHEPPLOGAN: + { + // filt(2:end) = filt(2:end) .* (sin(w(2:end)/(2*d))./(w(2:end)/(2*d))) + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * (sinf(pfW[iDetectorIndex] / 2.0f / _fD) / (pfW[iDetectorIndex] / 2.0f / _fD)); + } + break; + } + case FILTER_COSINE: + { + // filt(2:end) = filt(2:end) .* cos(w(2:end)/(2*d)) + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * cosf(pfW[iDetectorIndex] / 2.0f / _fD); + } + break; + } + case FILTER_HAMMING: + { + // filt(2:end) = filt(2:end) .* (.54 + .46 * cos(w(2:end)/d)) + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * ( 0.54f + 0.46f * cosf(pfW[iDetectorIndex] / _fD)); + } + break; + } + case FILTER_HANN: + { + // filt(2:end) = filt(2:end) .*(1+cos(w(2:end)./d)) / 2 + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * (1.0f + cosf(pfW[iDetectorIndex] / _fD)) / 2.0f; + } + break; + } + case FILTER_TUKEY: + { + float fAlpha = _fParameter; + if(_fParameter < 0.0f) fAlpha = 0.5f; + float fN = (float)_iFFTFourierDetectorCount; + float fHalfN = fN / 2.0f; + float fEnumTerm = fAlpha * fHalfN; + float fDenom = (1.0f - fAlpha) * fHalfN; + float fBlockStart = fHalfN - fEnumTerm; + float fBlockEnd = fHalfN + fEnumTerm; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fAbsSmallN = fabs((float)iDetectorIndex); + float fStoredValue = 0.0f; + + if((fBlockStart <= fAbsSmallN) && (fAbsSmallN <= fBlockEnd)) + { + fStoredValue = 1.0f; + } + else + { + float fEnum = fAbsSmallN - fEnumTerm; + float fCosInput = M_PI * fEnum / fDenom; + fStoredValue = 0.5f * (1.0f + cosf(fCosInput)); + } + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_LANCZOS: + { + float fDenum = (float)(_iFFTFourierDetectorCount - 1); + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fX = 2.0f * fSmallN / fDenum - 1.0f; + float fSinInput = M_PI * fX; + float fStoredValue = 0.0f; + + if(fabsf(fSinInput) > 0.001f) + { + fStoredValue = sin(fSinInput)/fSinInput; + } + else + { + fStoredValue = 1.0f; + } + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_TRIANGULAR: + { + float fNMinusOne = (float)(_iFFTFourierDetectorCount - 1); + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fAbsInput = fSmallN - fNMinusOne / 2.0f; + float fParenInput = fNMinusOne / 2.0f - fabsf(fAbsInput); + float fStoredValue = 2.0f / fNMinusOne * fParenInput; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_GAUSSIAN: + { + float fSigma = _fParameter; + if(_fParameter < 0.0f) fSigma = 0.4f; + float fN = (float)_iFFTFourierDetectorCount; + float fQuotient = (fN - 1.0f) / 2.0f; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fEnum = fSmallN - fQuotient; + float fDenom = fSigma * fQuotient; + float fPower = -0.5f * (fEnum / fDenom) * (fEnum / fDenom); + float fStoredValue = expf(fPower); + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_BARTLETTHANN: + { + const float fA0 = 0.62f; + const float fA1 = 0.48f; + const float fA2 = 0.38f; + float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fAbsInput = fSmallN / fNMinusOne - 0.5f; + float fFirstTerm = fA1 * fabsf(fAbsInput); + float fCosInput = 2.0f * M_PI * fSmallN / fNMinusOne; + float fSecondTerm = fA2 * cosf(fCosInput); + float fStoredValue = fA0 - fFirstTerm - fSecondTerm; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_BLACKMAN: + { + float fAlpha = _fParameter; + if(_fParameter < 0.0f) fAlpha = 0.16f; + float fA0 = (1.0f - fAlpha) / 2.0f; + float fA1 = 0.5f; + float fA2 = fAlpha / 2.0f; + float fNMinusOne = (float)(_iFFTFourierDetectorCount - 1); + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fCosInput1 = 2.0f * M_PI * 0.5f * fSmallN / fNMinusOne; + float fCosInput2 = 4.0f * M_PI * 0.5f * fSmallN / fNMinusOne; + float fStoredValue = fA0 - fA1 * cosf(fCosInput1) + fA2 * cosf(fCosInput2); + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_NUTTALL: + { + const float fA0 = 0.355768f; + const float fA1 = 0.487396f; + const float fA2 = 0.144232f; + const float fA3 = 0.012604f; + float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fBaseCosInput = M_PI * fSmallN / fNMinusOne; + float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput); + float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput); + float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput); + float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_BLACKMANHARRIS: + { + const float fA0 = 0.35875f; + const float fA1 = 0.48829f; + const float fA2 = 0.14128f; + const float fA3 = 0.01168f; + float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fBaseCosInput = M_PI * fSmallN / fNMinusOne; + float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput); + float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput); + float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput); + float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_BLACKMANNUTTALL: + { + const float fA0 = 0.3635819f; + const float fA1 = 0.4891775f; + const float fA2 = 0.1365995f; + const float fA3 = 0.0106411f; + float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fBaseCosInput = M_PI * fSmallN / fNMinusOne; + float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput); + float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput); + float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput); + float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_FLATTOP: + { + const float fA0 = 1.0f; + const float fA1 = 1.93f; + const float fA2 = 1.29f; + const float fA3 = 0.388f; + const float fA4 = 0.032f; + float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f; + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fBaseCosInput = M_PI * fSmallN / fNMinusOne; + float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput); + float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput); + float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput); + float fFourthTerm = fA4 * cosf(8.0f * fBaseCosInput); + float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm + fFourthTerm; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_KAISER: + { + float fAlpha = _fParameter; + if(_fParameter < 0.0f) fAlpha = 3.0f; + float fPiTimesAlpha = M_PI * fAlpha; + float fNMinusOne = (float)(_iFFTFourierDetectorCount - 1); + float fDenom = (float)j0((double)fPiTimesAlpha); + + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fSquareInput = 2.0f * fSmallN / fNMinusOne - 1; + float fSqrtInput = 1.0f - fSquareInput * fSquareInput; + float fBesselInput = fPiTimesAlpha * sqrt(fSqrtInput); + float fEnum = (float)j0((double)fBesselInput); + float fStoredValue = fEnum / fDenom; + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + case FILTER_PARZEN: + { + for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fSmallN = (float)iDetectorIndex; + float fQ = fSmallN / (float)(_iFFTFourierDetectorCount - 1); + float fStoredValue = 0.0f; + + if(fQ <= 0.5f) + { + fStoredValue = 1.0f - 6.0f * fQ * fQ * (1.0f - fQ); + } + else + { + float fCubedValue = 1.0f - fQ; + fStoredValue = 2.0f * fCubedValue * fCubedValue * fCubedValue; + } + + pfFilt[iDetectorIndex] *= fStoredValue; + } + + break; + } + default: + { + std::cerr << "Cannot serve requested filter" << std::endl; + } + } + + // filt(w>pi*d) = 0; + float fPiTimesD = M_PI * _fD; + for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fWValue = pfW[iDetectorIndex]; + + if(fWValue > fPiTimesD) + { + pfFilt[iDetectorIndex] = 0.0f; + } + } + + for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++) + { + float fFilterValue = pfFilt[iDetectorIndex]; + + for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++) + { + int iIndex = iDetectorIndex + iProjectionIndex * _iFFTFourierDetectorCount; + _pFilter[iIndex].x = fFilterValue; + _pFilter[iIndex].y = 0.0f; + } + } + + delete[] pfFilt; + delete[] pfW; +} + +#ifdef STANDALONE + +__global__ static void doubleFourierOutput_kernel(int _iProjectionCount, + int _iDetectorCount, + cufftComplex* _pFourierOutput) +{ + int iIndex = threadIdx.x + blockIdx.x * blockDim.x; + int iProjectionIndex = iIndex / _iDetectorCount; + int iDetectorIndex = iIndex % _iDetectorCount; + + if(iProjectionIndex >= _iProjectionCount) + { + return; + } + + if(iDetectorIndex <= (_iDetectorCount / 2)) + { + return; + } + + int iOtherDetectorIndex = _iDetectorCount - iDetectorIndex; + + _pFourierOutput[iProjectionIndex * _iDetectorCount + iDetectorIndex].x = _pFourierOutput[iProjectionIndex * _iDetectorCount + iOtherDetectorIndex].x; + _pFourierOutput[iProjectionIndex * _iDetectorCount + iDetectorIndex].y = -_pFourierOutput[iProjectionIndex * _iDetectorCount + iOtherDetectorIndex].y; +} + +static void doubleFourierOutput(int _iProjectionCount, int _iDetectorCount, + cufftComplex * _pFourierOutput) +{ + const int iBlockSize = 256; + int iElementCount = _iProjectionCount * _iDetectorCount; + int iBlockCount = (iElementCount + iBlockSize - 1) / iBlockSize; + + doubleFourierOutput_kernel<<< iBlockCount, iBlockSize >>>(_iProjectionCount, + _iDetectorCount, + _pFourierOutput); + CHECK_ERROR("doubleFourierOutput_kernel failed"); +} + + + +static void writeToMatlabFile(const char * _fileName, const float * _pfData, + int _iRowCount, int _iColumnCount) +{ + std::ofstream out(_fileName); + + for(int iRowIndex = 0; iRowIndex < _iRowCount; iRowIndex++) + { + for(int iColumnIndex = 0; iColumnIndex < _iColumnCount; iColumnIndex++) + { + out << _pfData[iColumnIndex + iRowIndex * _iColumnCount] << " "; + } + + out << std::endl; + } +} + +static void convertComplexToRealImg(const cufftComplex * _pComplex, + int _iElementCount, + float * _pfReal, float * _pfImaginary) +{ + for(int iIndex = 0; iIndex < _iElementCount; iIndex++) + { + _pfReal[iIndex] = _pComplex[iIndex].x; + _pfImaginary[iIndex] = _pComplex[iIndex].y; + } +} + +void testCudaFFT() +{ + const int iProjectionCount = 2; + const int iDetectorCount = 1024; + const int iTotalElementCount = iProjectionCount * iDetectorCount; + + float * pfHostProj = new float[iTotalElementCount]; + memset(pfHostProj, 0, sizeof(float) * iTotalElementCount); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++) + { +// int + +// pfHostProj[iIndex] = (float)rand() / (float)RAND_MAX; + } + } + + writeToMatlabFile("proj.mat", pfHostProj, iProjectionCount, iDetectorCount); + + float * pfDevProj = NULL; + SAFE_CALL(cudaMalloc((void **)&pfDevProj, sizeof(float) * iTotalElementCount)); + SAFE_CALL(cudaMemcpy(pfDevProj, pfHostProj, sizeof(float) * iTotalElementCount, cudaMemcpyHostToDevice)); + + cufftComplex * pDevFourProj = NULL; + SAFE_CALL(cudaMalloc((void **)&pDevFourProj, sizeof(cufftComplex) * iTotalElementCount)); + + cufftHandle plan; + cufftResult result; + + result = cufftPlan1d(&plan, iDetectorCount, CUFFT_R2C, iProjectionCount); + if(result != CUFFT_SUCCESS) + { + cerr << "Failed to plan 1d r2c fft" << endl; + } + + result = cufftExecR2C(plan, pfDevProj, pDevFourProj); + if(result != CUFFT_SUCCESS) + { + cerr << "Failed to exec 1d r2c fft" << endl; + } + + cufftDestroy(plan); + + doubleFourierOutput(iProjectionCount, iDetectorCount, pDevFourProj); + + cufftComplex * pHostFourProj = new cufftComplex[iTotalElementCount]; + SAFE_CALL(cudaMemcpy(pHostFourProj, pDevFourProj, sizeof(cufftComplex) * iTotalElementCount, cudaMemcpyDeviceToHost)); + + float * pfHostFourProjReal = new float[iTotalElementCount]; + float * pfHostFourProjImaginary = new float[iTotalElementCount]; + + convertComplexToRealImg(pHostFourProj, iTotalElementCount, pfHostFourProjReal, pfHostFourProjImaginary); + + writeToMatlabFile("proj_four_real.mat", pfHostFourProjReal, iProjectionCount, iDetectorCount); + writeToMatlabFile("proj_four_imaginary.mat", pfHostFourProjImaginary, iProjectionCount, iDetectorCount); + + float * pfDevInFourProj = NULL; + SAFE_CALL(cudaMalloc((void **)&pfDevInFourProj, sizeof(float) * iTotalElementCount)); + + result = cufftPlan1d(&plan, iDetectorCount, CUFFT_C2R, iProjectionCount); + if(result != CUFFT_SUCCESS) + { + cerr << "Failed to plan 1d c2r fft" << endl; + } + + result = cufftExecC2R(plan, pDevFourProj, pfDevInFourProj); + if(result != CUFFT_SUCCESS) + { + cerr << "Failed to exec 1d c2r fft" << endl; + } + + cufftDestroy(plan); + + rescaleInverseFourier(iProjectionCount, iDetectorCount, pfDevInFourProj); + + float * pfHostInFourProj = new float[iTotalElementCount]; + SAFE_CALL(cudaMemcpy(pfHostInFourProj, pfDevInFourProj, sizeof(float) * iTotalElementCount, cudaMemcpyDeviceToHost)); + + writeToMatlabFile("in_four.mat", pfHostInFourProj, iProjectionCount, iDetectorCount); + + SAFE_CALL(cudaFree(pDevFourProj)); + SAFE_CALL(cudaFree(pfDevProj)); + + delete [] pfHostInFourProj; + delete [] pfHostFourProjReal; + delete [] pfHostFourProjImaginary; + delete [] pfHostProj; + delete [] pHostFourProj; +} + +void downloadDebugFilterComplex(float * _pfHostSinogram, int _iProjectionCount, + int _iDetectorCount, + cufftComplex * _pDevFilter, + int _iFilterDetCount) +{ + cufftComplex * pHostFilter = NULL; + size_t complMemSize = sizeof(cufftComplex) * _iFilterDetCount * _iProjectionCount; + pHostFilter = (cufftComplex *)malloc(complMemSize); + SAFE_CALL(cudaMemcpy(pHostFilter, _pDevFilter, complMemSize, cudaMemcpyDeviceToHost)); + + for(int iTargetProjIndex = 0; iTargetProjIndex < _iProjectionCount; iTargetProjIndex++) + { + for(int iTargetDetIndex = 0; iTargetDetIndex < min(_iDetectorCount, _iFilterDetCount); iTargetDetIndex++) + { + cufftComplex source = pHostFilter[iTargetDetIndex + iTargetProjIndex * _iFilterDetCount]; + float fReadValue = sqrtf(source.x * source.x + source.y * source.y); + _pfHostSinogram[iTargetDetIndex + iTargetProjIndex * _iDetectorCount] = fReadValue; + } + } + + free(pHostFilter); +} + +void downloadDebugFilterReal(float * _pfHostSinogram, int _iProjectionCount, + int _iDetectorCount, float * _pfDevFilter, + int _iFilterDetCount) +{ + float * pfHostFilter = NULL; + size_t memSize = sizeof(float) * _iFilterDetCount * _iProjectionCount; + pfHostFilter = (float *)malloc(memSize); + SAFE_CALL(cudaMemcpy(pfHostFilter, _pfDevFilter, memSize, cudaMemcpyDeviceToHost)); + + for(int iTargetProjIndex = 0; iTargetProjIndex < _iProjectionCount; iTargetProjIndex++) + { + for(int iTargetDetIndex = 0; iTargetDetIndex < min(_iDetectorCount, _iFilterDetCount); iTargetDetIndex++) + { + float fSource = pfHostFilter[iTargetDetIndex + iTargetProjIndex * _iFilterDetCount]; + _pfHostSinogram[iTargetDetIndex + iTargetProjIndex * _iDetectorCount] = fSource; + } + } + + free(pfHostFilter); +} + + +#endif diff --git a/cuda/2d/fft.h b/cuda/2d/fft.h new file mode 100644 index 0000000..55324e5 --- /dev/null +++ b/cuda/2d/fft.h @@ -0,0 +1,69 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef FFT_H +#define FFT_H + +#include <cufft.h> +#include <cuda.h> + +#include "fbp_filters.h" + +bool allocateComplexOnDevice(int _iProjectionCount, + int _iDetectorCount, + cufftComplex ** _ppDevComplex); + +bool freeComplexOnDevice(cufftComplex * _pDevComplex); + +bool uploadComplexArrayToDevice(int _iProjectionCount, int _iDetectorCount, + cufftComplex * _pHostComplexSource, + cufftComplex * _pDevComplexTarget); + +bool runCudaFFT(int _iProjectionCount, const float * _pfDevRealSource, + int _iSourcePitch, int _iSourcePadX, int _iProjDets, + int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount, + cufftComplex * _pDevTargetComplex); + +bool runCudaIFFT(int _iProjectionCount, const cufftComplex* _pDevSourceComplex, + float * _pfRealTarget, + int _iTargetPitch, int _iTargetPadX, int _iProjDets, + int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount); + +void applyFilter(int _iProjectionCount, int _iFreqBinCount, + cufftComplex * _pSinogram, cufftComplex * _pFilter); + +int calcFFTFourSize(int _iFFTRealSize); + +void genFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, + cufftComplex * _pFilter, int _iFFTRealDetectorCount, + int _iFFTFourierDetectorCount, float _fParameter = -1.0f); + +void genIdenFilter(int _iProjectionCount, cufftComplex * _pFilter, + int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount); + +#endif /* FFT_H */ diff --git a/cuda/2d/par_bp.cu b/cuda/2d/par_bp.cu new file mode 100644 index 0000000..1057879 --- /dev/null +++ b/cuda/2d/par_bp.cu @@ -0,0 +1,357 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> + +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +#define PIXELTRACE + + +typedef texture<float, 2, cudaReadModeElementType> texture2D; + +static texture2D gT_projTexture; + + +namespace astraCUDA { + +const unsigned int g_anglesPerBlock = 16; +const unsigned int g_blockSliceSize = 32; +const unsigned int g_blockSlices = 16; + +const unsigned int g_MaxAngles = 2560; + +__constant__ float gC_angle_sin[g_MaxAngles]; +__constant__ float gC_angle_cos[g_MaxAngles]; +__constant__ float gC_angle_offset[g_MaxAngles]; + +static bool bindProjDataTexture(float* data, unsigned int pitch, unsigned int width, unsigned int height) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_projTexture.addressMode[0] = cudaAddressModeClamp; + gT_projTexture.addressMode[1] = cudaAddressModeClamp; + gT_projTexture.filterMode = cudaFilterModeLinear; + gT_projTexture.normalized = false; + + cudaBindTexture2D(0, gT_projTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch); + + // TODO: error value? + + return true; +} + +__global__ void devBP(float* D_volData, unsigned int volPitch, unsigned int startAngle, bool offsets, const SDimensions dims) +{ + const int relX = threadIdx.x; + const int relY = threadIdx.y; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + const int X = blockIdx.x * g_blockSlices + relX; + const int Y = blockIdx.y * g_blockSliceSize + relY; + + if (X >= dims.iVolWidth || Y >= dims.iVolHeight) + return; + + const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f ) / dims.fDetScale; + const float fY = ( Y - 0.5f*dims.iVolHeight + 0.5f ) / dims.fDetScale; + + float* volData = (float*)D_volData; + + float fVal = 0.0f; + float fA = startAngle + 0.5f; + const float fT_base = 0.5f*dims.iProjDets - 0.5f + 1.5f; + + if (offsets) { + + for (int angle = startAngle; angle < endAngle; ++angle) + { + const float cos_theta = gC_angle_cos[angle]; + const float sin_theta = gC_angle_sin[angle]; + const float TOffset = gC_angle_offset[angle]; + + const float fT = fT_base + fX * cos_theta - fY * sin_theta + TOffset; + fVal += tex2D(gT_projTexture, fT, fA); + fA += 1.0f; + } + + } else { + + for (int angle = startAngle; angle < endAngle; ++angle) + { + const float cos_theta = gC_angle_cos[angle]; + const float sin_theta = gC_angle_sin[angle]; + + const float fT = fT_base + fX * cos_theta - fY * sin_theta; + fVal += tex2D(gT_projTexture, fT, fA); + fA += 1.0f; + } + + } + + volData[(Y+1)*volPitch+X+1] += fVal; +} + +// supersampling version +__global__ void devBP_SS(float* D_volData, unsigned int volPitch, unsigned int startAngle, bool offsets, const SDimensions dims) +{ + const int relX = threadIdx.x; + const int relY = threadIdx.y; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + const int X = blockIdx.x * g_blockSlices + relX; + const int Y = blockIdx.y * g_blockSliceSize + relY; + + if (X >= dims.iVolWidth || Y >= dims.iVolHeight) + return; + + const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim) / dims.fDetScale; + const float fY = ( Y - 0.5f*dims.iVolHeight + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim) / dims.fDetScale; + + const float fSubStep = 1.0f/(dims.iRaysPerPixelDim * dims.fDetScale); + + float* volData = (float*)D_volData; + + float fVal = 0.0f; + float fA = startAngle + 0.5f; + const float fT_base = 0.5f*dims.iProjDets - 0.5f + 1.5f; + + if (offsets) { + + for (int angle = startAngle; angle < endAngle; ++angle) + { + const float cos_theta = gC_angle_cos[angle]; + const float sin_theta = gC_angle_sin[angle]; + const float TOffset = gC_angle_offset[angle]; + + float fT = fT_base + fX * cos_theta - fY * sin_theta + TOffset; + + for (int iSubX = 0; iSubX < dims.iRaysPerPixelDim; ++iSubX) { + float fTy = fT; + fT += fSubStep * cos_theta; + for (int iSubY = 0; iSubY < dims.iRaysPerPixelDim; ++iSubY) { + fVal += tex2D(gT_projTexture, fTy, fA); + fTy -= fSubStep * sin_theta; + } + } + fA += 1.0f; + } + + } else { + + for (int angle = startAngle; angle < endAngle; ++angle) + { + const float cos_theta = gC_angle_cos[angle]; + const float sin_theta = gC_angle_sin[angle]; + + float fT = fT_base + fX * cos_theta - fY * sin_theta; + + for (int iSubX = 0; iSubX < dims.iRaysPerPixelDim; ++iSubX) { + float fTy = fT; + fT += fSubStep * cos_theta; + for (int iSubY = 0; iSubY < dims.iRaysPerPixelDim; ++iSubY) { + fVal += tex2D(gT_projTexture, fTy, fA); + fTy -= fSubStep * sin_theta; + } + } + fA += 1.0f; + + } + + } + + volData[(Y+1)*volPitch+X+1] += fVal / (dims.iRaysPerPixelDim * dims.iRaysPerPixelDim); +} + +__global__ void devBP_SART(float* D_volData, unsigned int volPitch, float offset, float angle_sin, float angle_cos, const SDimensions dims) +{ + const int relX = threadIdx.x; + const int relY = threadIdx.y; + + const int X = blockIdx.x * g_blockSlices + relX; + const int Y = blockIdx.y * g_blockSliceSize + relY; + + if (X >= dims.iVolWidth || Y >= dims.iVolHeight) + return; + + const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f ) / dims.fDetScale; + const float fY = ( Y - 0.5f*dims.iVolHeight + 0.5f ) / dims.fDetScale; + + const float fT_base = 0.5f*dims.iProjDets - 0.5f + 0.5f; + + const float fT = fT_base + fX * angle_cos - fY * angle_sin + offset; + const float fVal = tex2D(gT_projTexture, fT, 0.5f); + + D_volData[(Y+1)*volPitch+X+1] += fVal; +} + + +bool BP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, const float* TOffsets) +{ + // TODO: process angles block by block + assert(dims.iProjAngles <= g_MaxAngles); + + float* angle_sin = new float[dims.iProjAngles]; + float* angle_cos = new float[dims.iProjAngles]; + + bindProjDataTexture(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) { + angle_sin[i] = sinf(angles[i]); + angle_cos[i] = cosf(angles[i]); + } + cudaError_t e1 = cudaMemcpyToSymbol(gC_angle_sin, angle_sin, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + cudaError_t e2 = cudaMemcpyToSymbol(gC_angle_cos, angle_cos, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + assert(e1 == cudaSuccess); + assert(e2 == cudaSuccess); + + if (TOffsets) { + cudaError_t e3 = cudaMemcpyToSymbol(gC_angle_offset, TOffsets, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + assert(e3 == cudaSuccess); + } + + delete[] angle_sin; + delete[] angle_cos; + + dim3 dimBlock(g_blockSlices, g_blockSliceSize); + dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices, + (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize); + + cudaStream_t stream; + cudaStreamCreate(&stream); + + for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) { + + if (dims.iRaysPerPixelDim > 1) + devBP_SS<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, (TOffsets != 0), dims); + else + devBP<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, (TOffsets != 0), dims); + } + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + cudaStreamDestroy(stream); + + return true; +} + +bool BP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle, const SDimensions& dims, + const float* angles, const float* TOffsets) +{ + // only one angle + bindProjDataTexture(D_projData, projPitch, dims.iProjDets, 1); + + float angle_sin = sinf(angles[angle]); + float angle_cos = cosf(angles[angle]); + + float offset = 0.0f; + if (TOffsets) + offset = TOffsets[angle]; + + dim3 dimBlock(g_blockSlices, g_blockSliceSize); + dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices, + (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize); + + devBP_SART<<<dimGrid, dimBlock>>>(D_volumeData, volumePitch, offset, angle_sin, angle_cos, dims); + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + return true; +} + + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_projData; + + SDimensions dims; + dims.iVolWidth = 1024; + dims.iVolHeight = 1024; + dims.iProjAngles = 512; + dims.iProjDets = 1536; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + + unsigned int volumePitch, projPitch; + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + printf("pitch: %u\n", projPitch); + + unsigned int y, x; + float* sino = loadImage("sino.png", y, x); + + float* img = new float[dims.iVolWidth*dims.iVolHeight]; + + memset(img, 0, dims.iVolWidth*dims.iVolHeight*sizeof(float)); + + copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch); + + float* angle = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) + angle[i] = i*(M_PI/dims.iProjAngles); + + BP(D_volumeData, volumePitch, D_projData, projPitch, dims, angle, 0); + + delete[] angle; + + copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + + saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img); + + return 0; +} +#endif diff --git a/cuda/2d/par_bp.h b/cuda/2d/par_bp.h new file mode 100644 index 0000000..c6dbd59 --- /dev/null +++ b/cuda/2d/par_bp.h @@ -0,0 +1,48 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_PAR_BP_H +#define _CUDA_PAR_BP_H + +#include "dims.h" + +namespace astraCUDA { + +_AstraExport bool BP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets); + +_AstraExport bool BP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle, const SDimensions& dims, + const float* angles, const float* TOffsets); + +} + +#endif diff --git a/cuda/2d/par_fp.cu b/cuda/2d/par_fp.cu new file mode 100644 index 0000000..585cb06 --- /dev/null +++ b/cuda/2d/par_fp.cu @@ -0,0 +1,704 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +#define PIXELTRACE + + +typedef texture<float, 2, cudaReadModeElementType> texture2D; + +static texture2D gT_volumeTexture; + + +namespace astraCUDA { + +static const unsigned g_MaxAngles = 2560; +__constant__ float gC_angle[g_MaxAngles]; +__constant__ float gC_angle_offset[g_MaxAngles]; + + +// optimization parameters +static const unsigned int g_anglesPerBlock = 16; +static const unsigned int g_detBlockSize = 32; +static const unsigned int g_blockSlices = 64; + +// fixed point scaling factor +#define fPREC_FACTOR 16.0f +#define iPREC_FACTOR 16 + + +// if necessary, a buffer of zeroes of size g_MaxAngles +static float* g_pfZeroes = 0; + + +static bool bindVolumeDataTexture(float* data, cudaArray*& dataArray, unsigned int pitch, unsigned int width, unsigned int height) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + dataArray = 0; + cudaMallocArray(&dataArray, &channelDesc, width, height); + cudaMemcpy2DToArray(dataArray, 0, 0, data, pitch*sizeof(float), width*sizeof(float), height, cudaMemcpyDeviceToDevice); + + gT_volumeTexture.addressMode[0] = cudaAddressModeClamp; + gT_volumeTexture.addressMode[1] = cudaAddressModeClamp; + gT_volumeTexture.filterMode = cudaFilterModeLinear; + gT_volumeTexture.normalized = false; + + // TODO: For very small sizes (roughly <=512x128) with few angles (<=180) + // not using an array is more efficient. +// cudaBindTexture2D(0, gT_volumeTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch); + cudaBindTextureToArray(gT_volumeTexture, dataArray, channelDesc); + + // TODO: error value? + + return true; +} + +// projection for angles that are roughly horizontal +// theta between 45 and 135 degrees +__global__ void FPhorizontal(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, int regionOffset, const SDimensions dims, float outputScale) +{ + const int relDet = threadIdx.x; + const int relAngle = threadIdx.y; + + int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle; + + if (angle >= endAngle) + return; + + const float theta = gC_angle[angle]; + const float cos_theta = __cosf(theta); + const float sin_theta = __sinf(theta); + + // compute start detector for this block/angle: + // (The same for all threadIdx.x) + // ------------------------------------- + + const int midSlice = startSlice + g_blockSlices / 2; + + // ASSUMPTION: fDetScale >= 1.0f + // problem: detector regions get skipped because slice blocks aren't large + // enough + const unsigned int g_blockSliceSize = g_detBlockSize; + + // project (midSlice,midRegion) on this thread's detector + + const float fBase = 0.5f*dims.iProjDets - 0.5f + + ( + (midSlice - 0.5f*dims.iVolWidth + 0.5f) * cos_theta + - (g_blockSliceSize/2 - 0.5f*dims.iVolHeight + 0.5f) * sin_theta + + gC_angle_offset[angle] + ) / dims.fDetScale; + int iBase = (int)floorf(fBase * fPREC_FACTOR); + int iInc = (int)floorf(g_blockSliceSize * sin_theta / dims.fDetScale * -fPREC_FACTOR); + + // ASSUMPTION: 16 > regionOffset / fDetScale + const int detRegion = (iBase + (blockIdx.y - regionOffset)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16; + const int detPrevRegion = (iBase + (blockIdx.y - regionOffset - 1)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16; + + if (blockIdx.y > 0 && detRegion == detPrevRegion) + return; + + const int detector = detRegion * g_detBlockSize + relDet; + + // Now project the part of the ray to angle,detector through + // slices startSlice to startSlice+g_blockSlices-1 + + if (detector < 0 || detector >= dims.iProjDets) + return; + + const float fDetStep = -dims.fDetScale / sin_theta; + float fSliceStep = cos_theta / sin_theta; + float fDistCorr; + if (sin_theta > 0.0f) + fDistCorr = -fDetStep; + else + fDistCorr = fDetStep; + fDistCorr *= outputScale; + + float fVal = 0.0f; + // project detector on slice + float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolWidth + 0.5f) * fSliceStep + 0.5f*dims.iVolHeight - 0.5f + 1.5f; + float fS = startSlice + 1.5f; + int endSlice = startSlice + g_blockSlices; + if (endSlice > dims.iVolWidth) + endSlice = dims.iVolWidth; + + if (dims.iRaysPerDet > 1) { + + fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep; + const float fSubDetStep = fDetStep / dims.iRaysPerDet; + fDistCorr /= dims.iRaysPerDet; + + fSliceStep -= dims.iRaysPerDet * fSubDetStep; + + for (int slice = startSlice; slice < endSlice; ++slice) + { + for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) { + fVal += tex2D(gT_volumeTexture, fS, fP); + fP += fSubDetStep; + } + fP += fSliceStep; + fS += 1.0f; + } + + } else { + + for (int slice = startSlice; slice < endSlice; ++slice) + { + fVal += tex2D(gT_volumeTexture, fS, fP); + fP += fSliceStep; + fS += 1.0f; + } + + + } + + D_projData[angle*projPitch+detector+1] += fVal * fDistCorr; +} + +// projection for angles that are roughly vertical +// theta between 0 and 45, or 135 and 180 degrees +__global__ void FPvertical(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, int regionOffset, const SDimensions dims, float outputScale) +{ + const int relDet = threadIdx.x; + const int relAngle = threadIdx.y; + + int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle; + + if (angle >= endAngle) + return; + + const float theta = gC_angle[angle]; + const float cos_theta = __cosf(theta); + const float sin_theta = __sinf(theta); + + // compute start detector for this block/angle: + // (The same for all threadIdx.x) + // ------------------------------------- + + const int midSlice = startSlice + g_blockSlices / 2; + + // project (midSlice,midRegion) on this thread's detector + + // ASSUMPTION: fDetScale >= 1.0f + // problem: detector regions get skipped because slice blocks aren't large + // enough + const unsigned int g_blockSliceSize = g_detBlockSize; + + const float fBase = 0.5f*dims.iProjDets - 0.5f + + ( + (g_blockSliceSize/2 - 0.5f*dims.iVolWidth + 0.5f) * cos_theta + - (midSlice - 0.5f*dims.iVolHeight + 0.5f) * sin_theta + + gC_angle_offset[angle] + ) / dims.fDetScale; + int iBase = (int)floorf(fBase * fPREC_FACTOR); + int iInc = (int)floorf(g_blockSliceSize * cos_theta / dims.fDetScale * fPREC_FACTOR); + + // ASSUMPTION: 16 > regionOffset / fDetScale + const int detRegion = (iBase + (blockIdx.y - regionOffset)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16; + const int detPrevRegion = (iBase + (blockIdx.y - regionOffset-1)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16; + + if (blockIdx.y > 0 && detRegion == detPrevRegion) + return; + + const int detector = detRegion * g_detBlockSize + relDet; + + // Now project the part of the ray to angle,detector through + // slices startSlice to startSlice+g_blockSlices-1 + + if (detector < 0 || detector >= dims.iProjDets) + return; + + const float fDetStep = dims.fDetScale / cos_theta; + float fSliceStep = sin_theta / cos_theta; + float fDistCorr; + if (cos_theta < 0.0f) + fDistCorr = -fDetStep; + else + fDistCorr = fDetStep; + fDistCorr *= outputScale; + + float fVal = 0.0f; + float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolHeight + 0.5f) * fSliceStep + 0.5f*dims.iVolWidth - 0.5f + 1.5f; + float fS = startSlice+1.5f; + int endSlice = startSlice + g_blockSlices; + if (endSlice > dims.iVolHeight) + endSlice = dims.iVolHeight; + + if (dims.iRaysPerDet > 1) { + + fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep; + const float fSubDetStep = fDetStep / dims.iRaysPerDet; + fDistCorr /= dims.iRaysPerDet; + + fSliceStep -= dims.iRaysPerDet * fSubDetStep; + + for (int slice = startSlice; slice < endSlice; ++slice) + { + for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) { + fVal += tex2D(gT_volumeTexture, fP, fS); + fP += fSubDetStep; + } + fP += fSliceStep; + fS += 1.0f; + } + + } else { + + for (int slice = startSlice; slice < endSlice; ++slice) + { + fVal += tex2D(gT_volumeTexture, fP, fS); + fP += fSliceStep; + fS += 1.0f; + } + + } + + D_projData[angle*projPitch+detector+1] += fVal * fDistCorr; +} + +// projection for angles that are roughly horizontal +// (detector roughly vertical) +__global__ void FPhorizontal_simple(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale) +{ + const int relDet = threadIdx.x; + const int relAngle = threadIdx.y; + + int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle; + + if (angle >= endAngle) + return; + + const float theta = gC_angle[angle]; + const float cos_theta = __cosf(theta); + const float sin_theta = __sinf(theta); + + // compute start detector for this block/angle: + const int detRegion = blockIdx.y; + + const int detector = detRegion * g_detBlockSize + relDet; + + // Now project the part of the ray to angle,detector through + // slices startSlice to startSlice+g_blockSlices-1 + + if (detector < 0 || detector >= dims.iProjDets) + return; + + const float fDetStep = -dims.fDetScale / sin_theta; + float fSliceStep = cos_theta / sin_theta; + float fDistCorr; + if (sin_theta > 0.0f) + fDistCorr = -fDetStep; + else + fDistCorr = fDetStep; + fDistCorr *= outputScale; + + float fVal = 0.0f; + // project detector on slice + float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolWidth + 0.5f) * fSliceStep + 0.5f*dims.iVolHeight - 0.5f + 1.5f; + float fS = startSlice + 1.5f; + int endSlice = startSlice + g_blockSlices; + if (endSlice > dims.iVolWidth) + endSlice = dims.iVolWidth; + + if (dims.iRaysPerDet > 1) { + + fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep; + const float fSubDetStep = fDetStep / dims.iRaysPerDet; + fDistCorr /= dims.iRaysPerDet; + + fSliceStep -= dims.iRaysPerDet * fSubDetStep; + + for (int slice = startSlice; slice < endSlice; ++slice) + { + for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) { + fVal += tex2D(gT_volumeTexture, fS, fP); + fP += fSubDetStep; + } + fP += fSliceStep; + fS += 1.0f; + } + + } else { + + for (int slice = startSlice; slice < endSlice; ++slice) + { + fVal += tex2D(gT_volumeTexture, fS, fP); + fP += fSliceStep; + fS += 1.0f; + } + + + } + + D_projData[angle*projPitch+detector+1] += fVal * fDistCorr; +} + + +// projection for angles that are roughly vertical +// (detector roughly horizontal) +__global__ void FPvertical_simple(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale) +{ + const int relDet = threadIdx.x; + const int relAngle = threadIdx.y; + + int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle; + + if (angle >= endAngle) + return; + + const float theta = gC_angle[angle]; + const float cos_theta = __cosf(theta); + const float sin_theta = __sinf(theta); + + // compute start detector for this block/angle: + const int detRegion = blockIdx.y; + + const int detector = detRegion * g_detBlockSize + relDet; + + // Now project the part of the ray to angle,detector through + // slices startSlice to startSlice+g_blockSlices-1 + + if (detector < 0 || detector >= dims.iProjDets) + return; + + const float fDetStep = dims.fDetScale / cos_theta; + float fSliceStep = sin_theta / cos_theta; + float fDistCorr; + if (cos_theta < 0.0f) + fDistCorr = -fDetStep; + else + fDistCorr = fDetStep; + fDistCorr *= outputScale; + + float fVal = 0.0f; + float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolHeight + 0.5f) * fSliceStep + 0.5f*dims.iVolWidth - 0.5f + 1.5f; + float fS = startSlice+1.5f; + int endSlice = startSlice + g_blockSlices; + if (endSlice > dims.iVolHeight) + endSlice = dims.iVolHeight; + + if (dims.iRaysPerDet > 1) { + + fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep; + const float fSubDetStep = fDetStep / dims.iRaysPerDet; + fDistCorr /= dims.iRaysPerDet; + + fSliceStep -= dims.iRaysPerDet * fSubDetStep; + + for (int slice = startSlice; slice < endSlice; ++slice) + { + for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) { + fVal += tex2D(gT_volumeTexture, fP, fS); + fP += fSubDetStep; + } + fP += fSliceStep; + fS += 1.0f; + } + + } else { + + for (int slice = startSlice; slice < endSlice; ++slice) + { + fVal += tex2D(gT_volumeTexture, fP, fS); + fP += fSliceStep; + fS += 1.0f; + } + + } + + D_projData[angle*projPitch+detector+1] += fVal * fDistCorr; +} + + + +bool FP_simple(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, float outputScale) +{ + // TODO: load angles into constant memory in smaller blocks + assert(dims.iProjAngles <= g_MaxAngles); + + cudaArray* D_dataArray; + bindVolumeDataTexture(D_volumeData, D_dataArray, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + + cudaMemcpyToSymbol(gC_angle, angles, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + + if (TOffsets) { + cudaMemcpyToSymbol(gC_angle_offset, TOffsets, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + } else { + if (!g_pfZeroes) { + g_pfZeroes = new float[g_MaxAngles]; + memset(g_pfZeroes, 0, g_MaxAngles * sizeof(float)); + } + cudaMemcpyToSymbol(gC_angle_offset, g_pfZeroes, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + } + + dim3 dimBlock(g_detBlockSize, g_anglesPerBlock); // detector block size, angles + + std::list<cudaStream_t> streams; + + + // Run over all angles, grouping them into groups of the same + // orientation (roughly horizontal vs. roughly vertical). + // Start a stream of grids for each such group. + + // TODO: Check if it's worth it to store this info instead + // of recomputing it every FP. + + unsigned int blockStart = 0; + unsigned int blockEnd = 0; + bool blockVertical = false; + for (unsigned int a = 0; a <= dims.iProjAngles; ++a) { + bool vertical; + // TODO: Having <= instead of < below causes a 5% speedup. + // Maybe we should detect corner cases and put them in the optimal + // group of angles. + if (a != dims.iProjAngles) + vertical = (fabsf(sinf(angles[a])) <= fabsf(cosf(angles[a]))); + if (a == dims.iProjAngles || vertical != blockVertical) { + // block done + + blockEnd = a; + if (blockStart != blockEnd) { + dim3 dimGrid((blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock, + (dims.iProjDets+g_detBlockSize-1)/g_detBlockSize); // angle blocks, detector blocks + + // TODO: check if we can't immediately + // destroy the stream after use + cudaStream_t stream; + cudaStreamCreate(&stream); + streams.push_back(stream); + //printf("angle block: %d to %d, %d\n", blockStart, blockEnd, blockVertical); + if (!blockVertical) + for (unsigned int i = 0; i < dims.iVolWidth; i += g_blockSlices) + FPhorizontal_simple<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale); + else + for (unsigned int i = 0; i < dims.iVolHeight; i += g_blockSlices) + FPvertical_simple<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale); + } + blockVertical = vertical; + blockStart = a; + } + } + + for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter) + cudaStreamDestroy(*iter); + + streams.clear(); + + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + cudaFreeArray(D_dataArray); + + + return true; +} + +bool FP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, float outputScale) +{ + return FP_simple(D_volumeData, volumePitch, D_projData, projPitch, + dims, angles, TOffsets, outputScale); + + // TODO: Fix bug in this non-simple FP with large detscale and TOffsets +#if 0 + + // TODO: load angles into constant memory in smaller blocks + assert(dims.iProjAngles <= g_MaxAngles); + + // TODO: compute region size dynamically to resolve these two assumptions + // ASSUMPTION: 16 > regionOffset / fDetScale + const unsigned int g_blockSliceSize = g_detBlockSize; + assert(16 > (g_blockSlices / g_blockSliceSize) / dims.fDetScale); + // ASSUMPTION: fDetScale >= 1.0f + assert(dims.fDetScale > 0.9999f); + + cudaArray* D_dataArray; + bindVolumeDataTexture(D_volumeData, D_dataArray, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + + cudaMemcpyToSymbol(gC_angle, angles, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + + if (TOffsets) { + cudaMemcpyToSymbol(gC_angle_offset, TOffsets, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + } else { + if (!g_pfZeroes) { + g_pfZeroes = new float[g_MaxAngles]; + memset(g_pfZeroes, 0, g_MaxAngles * sizeof(float)); + } + cudaMemcpyToSymbol(gC_angle_offset, g_pfZeroes, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + } + + int regionOffset = g_blockSlices / g_blockSliceSize; + + dim3 dimBlock(g_detBlockSize, g_anglesPerBlock); // region size, angles + + std::list<cudaStream_t> streams; + + + // Run over all angles, grouping them into groups of the same + // orientation (roughly horizontal vs. roughly vertical). + // Start a stream of grids for each such group. + + // TODO: Check if it's worth it to store this info instead + // of recomputing it every FP. + + unsigned int blockStart = 0; + unsigned int blockEnd = 0; + bool blockVertical = false; + for (unsigned int a = 0; a <= dims.iProjAngles; ++a) { + bool vertical; + // TODO: Having <= instead of < below causes a 5% speedup. + // Maybe we should detect corner cases and put them in the optimal + // group of angles. + if (a != dims.iProjAngles) + vertical = (fabsf(sinf(angles[a])) <= fabsf(cosf(angles[a]))); + if (a == dims.iProjAngles || vertical != blockVertical) { + // block done + + blockEnd = a; + if (blockStart != blockEnd) { + unsigned int length = dims.iVolHeight; + if (blockVertical) + length = dims.iVolWidth; + dim3 dimGrid((blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock, + (length+g_blockSliceSize-1)/g_blockSliceSize+2*regionOffset); // angle blocks, regions + // TODO: check if we can't immediately + // destroy the stream after use + cudaStream_t stream; + cudaStreamCreate(&stream); + streams.push_back(stream); + //printf("angle block: %d to %d, %d\n", blockStart, blockEnd, blockVertical); + if (!blockVertical) + for (unsigned int i = 0; i < dims.iVolWidth; i += g_blockSlices) + FPhorizontal<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, regionOffset, dims, outputScale); + else + for (unsigned int i = 0; i < dims.iVolHeight; i += g_blockSlices) + FPvertical<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, regionOffset, dims, outputScale); + } + blockVertical = vertical; + blockStart = a; + } + } + + for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter) + cudaStreamDestroy(*iter); + + streams.clear(); + + cudaThreadSynchronize(); + + cudaTextForceKernelsCompletion(); + + cudaFreeArray(D_dataArray); + + + return true; +#endif +} + + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_projData; + + SDimensions dims; + dims.iVolWidth = 1024; + dims.iVolHeight = 1024; + dims.iProjAngles = 512; + dims.iProjDets = 1536; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + unsigned int volumePitch, projPitch; + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + printf("pitch: %u\n", projPitch); + + unsigned int y, x; + float* img = loadImage("phantom.png", y, x); + + float* sino = new float[dims.iProjAngles * dims.iProjDets]; + + memset(sino, 0, dims.iProjAngles * dims.iProjDets * sizeof(float)); + + copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch); + + float* angle = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) + angle[i] = i*(M_PI/dims.iProjAngles); + + FP(D_volumeData, volumePitch, D_projData, projPitch, dims, angle, 0, 1.0f); + + delete[] angle; + + copySinogramFromDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch); + + float s = 0.0f; + for (unsigned int y = 0; y < dims.iProjAngles; ++y) + for (unsigned int x = 0; x < dims.iProjDets; ++x) + s += sino[y*dims.iProjDets+x] * sino[y*dims.iProjDets+x]; + printf("cpu norm: %f\n", s); + + //zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + printf("gpu norm: %f\n", s); + + saveImage("sino.png",dims.iProjAngles,dims.iProjDets,sino); + + + return 0; +} +#endif diff --git a/cuda/2d/par_fp.h b/cuda/2d/par_fp.h new file mode 100644 index 0000000..3213b14 --- /dev/null +++ b/cuda/2d/par_fp.h @@ -0,0 +1,41 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_PAR_FP_H +#define _CUDA_PAR_FP_H + +namespace astraCUDA { + +_AstraExport bool FP(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, float fOutputScale); + +} + +#endif diff --git a/cuda/2d/sart.cu b/cuda/2d/sart.cu new file mode 100644 index 0000000..a40176d --- /dev/null +++ b/cuda/2d/sart.cu @@ -0,0 +1,283 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "sart.h" +#include "util.h" +#include "arith.h" +#include "fan_fp.h" +#include "fan_bp.h" +#include "par_fp.h" +#include "par_bp.h" + +namespace astraCUDA { + + +__global__ void devMUL_SART(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + // Copy result down and left one pixel. + pfOut[x + pitch] = pfOut[x + 1] * pfIn[x + 1]; +} + +void MUL_SART(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, 1); + + devMUL_SART<<<gridSize, blockSize>>>(pfOut, pfIn, pitch, width); + + cudaTextForceKernelsCompletion(); +} + + + +SART::SART() : ReconAlgo() +{ + D_projData = 0; + D_tmpData = 0; + + D_lineWeight = 0; + + projectionOrder = 0; + projectionCount = 0; + iteration = 0; + customOrder = false; +} + + +SART::~SART() +{ + reset(); +} + +void SART::reset() +{ + cudaFree(D_projData); + cudaFree(D_tmpData); + cudaFree(D_lineWeight); + + D_projData = 0; + D_tmpData = 0; + + D_lineWeight = 0; + + useVolumeMask = false; + useSinogramMask = false; + + if (projectionOrder != NULL) delete[] projectionOrder; + projectionOrder = 0; + projectionCount = 0; + iteration = 0; + customOrder = false; + + ReconAlgo::reset(); +} + +bool SART::init() +{ + if (useVolumeMask) { + allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch); + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + } + + // HACK: D_projData consists of two lines. The first is used padded, + // the second unpadded. This is to satisfy the alignment requirements + // of resp. FP and BP_SART. + allocateVolume(D_projData, dims.iProjDets+2, 2, projPitch); + zeroVolume(D_projData, projPitch, dims.iProjDets+2, 1); + + allocateVolume(D_lineWeight, dims.iProjDets+2, dims.iProjAngles, linePitch); + zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles); + + // We can't precompute lineWeights when using a mask + if (!useVolumeMask) + precomputeWeights(); + + // TODO: check if allocations succeeded + return true; +} + +bool SART::setProjectionOrder(int* _projectionOrder, int _projectionCount) +{ + customOrder = true; + projectionCount = _projectionCount; + projectionOrder = new int[projectionCount]; + for (int i = 0; i < projectionCount; i++) { + projectionOrder[i] = _projectionOrder[i]; + } + + return true; +} + + +bool SART::precomputeWeights() +{ + zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles); + if (useVolumeMask) { + callFP(D_maskData, maskPitch, D_lineWeight, linePitch, 1.0f); + } else { + // Allocate tmpData temporarily + allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch); + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + + + processVol<opSet, VOL>(D_tmpData, 1.0f, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_tmpData, tmpPitch, D_lineWeight, linePitch, 1.0f); + + + cudaFree(D_tmpData); + D_tmpData = 0; + } + processVol<opInvert, SINO>(D_lineWeight, linePitch, dims.iProjDets, dims.iProjAngles); + + return true; +} + +bool SART::iterate(unsigned int iterations) +{ + shouldAbort = false; + + if (useVolumeMask) + precomputeWeights(); + + // iteration + for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + + int angle; + if (customOrder) { + angle = projectionOrder[iteration % projectionCount]; + } else { + angle = iteration % dims.iProjAngles; + } + + // copy one line of sinogram to projection data + cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData + angle*sinoPitch, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), 1, cudaMemcpyDeviceToDevice); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP_SART(D_tmpData, tmpPitch, D_projData, projPitch, angle, -1.0f); + } else { + callFP_SART(D_volumeData, volumePitch, D_projData, projPitch, angle, -1.0f); + } + + MUL_SART(D_projData, D_lineWeight + angle*linePitch, projPitch, dims.iProjDets); + + if (useVolumeMask) { + // BP, mask, and add back + // TODO: Try putting the masking directly in the BP + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + callBP_SART(D_tmpData, tmpPitch, D_projData, projPitch, angle); + processVol<opAddMul, VOL>(D_volumeData, D_maskData, D_tmpData, volumePitch, dims.iVolWidth, dims.iVolHeight); + } else { + callBP_SART(D_volumeData, volumePitch, D_projData, projPitch, angle); + } + + if (useMinConstraint) + processVol<opClampMin, VOL>(D_volumeData, fMinConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight); + if (useMaxConstraint) + processVol<opClampMax, VOL>(D_volumeData, fMaxConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight); + + iteration++; + + } + + return true; +} + +float SART::computeDiffNorm() +{ + unsigned int pPitch; + float *D_p; + allocateVolume(D_p, dims.iProjDets+2, dims.iProjAngles, pPitch); + zeroVolume(D_p, pPitch, dims.iProjDets+2, dims.iProjAngles); + + // copy sinogram to D_p + cudaMemcpy2D(D_p, sizeof(float)*pPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f); + } else { + callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f); + } + + + // compute norm of D_p + float s = dotProduct2D(D_p, pPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + + cudaFree(D_p); + + return sqrt(s); +} + +bool SART::callFP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle, float outputScale) +{ + SDimensions d = dims; + d.iProjAngles = 1; + if (angles) { + assert(!fanProjs); + return FP(D_volumeData, volumePitch, D_projData, projPitch, + d, &angles[angle], TOffsets, outputScale); + } else { + assert(fanProjs); + return FanFP(D_volumeData, volumePitch, D_projData, projPitch, + d, &fanProjs[angle], outputScale); + } +} + +bool SART::callBP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle) +{ + if (angles) { + assert(!fanProjs); + return BP_SART(D_volumeData, volumePitch, D_projData + projPitch, projPitch, + angle, dims, angles, TOffsets); + } else { + assert(fanProjs); + return FanBP_SART(D_volumeData, volumePitch, D_projData + projPitch, projPitch, + angle, dims, fanProjs); + } + +} + + +} + + diff --git a/cuda/2d/sart.h b/cuda/2d/sart.h new file mode 100644 index 0000000..ad80259 --- /dev/null +++ b/cuda/2d/sart.h @@ -0,0 +1,85 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_SART_H +#define _CUDA_SART_H + +#include "util.h" +#include "algo.h" + +namespace astraCUDA { + +class _AstraExport SART : public ReconAlgo { +public: + SART(); + ~SART(); + + // disable some features + virtual bool enableSinogramMask() { return false; } + + virtual bool init(); + + virtual bool setProjectionOrder(int* projectionOrder, int projectionCount); + + virtual bool iterate(unsigned int iterations); + + virtual float computeDiffNorm(); + +protected: + void reset(); + bool precomputeWeights(); + + bool callFP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle, float outputScale); + bool callBP_SART(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + unsigned int angle); + + + // projection angle variables + bool customOrder; + int* projectionOrder; + int projectionCount; + int iteration; + + // Temporary buffers + float* D_projData; + unsigned int projPitch; + + float* D_tmpData; // Only used when there's a volume mask + unsigned int tmpPitch; + + // Geometry-specific precomputed data + float* D_lineWeight; + unsigned int linePitch; +}; + +} + +#endif diff --git a/cuda/2d/sirt.cu b/cuda/2d/sirt.cu new file mode 100644 index 0000000..31954e4 --- /dev/null +++ b/cuda/2d/sirt.cu @@ -0,0 +1,342 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "sirt.h" +#include "util.h" +#include "arith.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +namespace astraCUDA { + +SIRT::SIRT() : ReconAlgo() +{ + D_projData = 0; + D_tmpData = 0; + + D_lineWeight = 0; + D_pixelWeight = 0; + + D_minMaskData = 0; + D_maxMaskData = 0; + + freeMinMaxMasks = false; +} + + +SIRT::~SIRT() +{ + reset(); +} + +void SIRT::reset() +{ + cudaFree(D_projData); + cudaFree(D_tmpData); + cudaFree(D_lineWeight); + cudaFree(D_pixelWeight); + if (freeMinMaxMasks) { + cudaFree(D_minMaskData); + cudaFree(D_maxMaskData); + } + + D_projData = 0; + D_tmpData = 0; + + D_lineWeight = 0; + D_pixelWeight = 0; + + freeMinMaxMasks = false; + D_minMaskData = 0; + D_maxMaskData = 0; + + useVolumeMask = false; + useSinogramMask = false; + + ReconAlgo::reset(); +} + +bool SIRT::init() +{ + allocateVolume(D_pixelWeight, dims.iVolWidth+2, dims.iVolHeight+2, pixelPitch); + zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2); + + allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch); + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + + allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch); + zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles); + + allocateVolume(D_lineWeight, dims.iProjDets+2, dims.iProjAngles, linePitch); + zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles); + + // We can't precompute lineWeights and pixelWeights when using a mask + if (!useVolumeMask && !useSinogramMask) + precomputeWeights(); + + // TODO: check if allocations succeeded + return true; +} + +bool SIRT::precomputeWeights() +{ + zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles); + if (useVolumeMask) { + callFP(D_maskData, maskPitch, D_lineWeight, linePitch, 1.0f); + } else { + processVol<opSet, VOL>(D_tmpData, 1.0f, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_tmpData, tmpPitch, D_lineWeight, linePitch, 1.0f); + } + processVol<opInvert, SINO>(D_lineWeight, linePitch, dims.iProjDets, dims.iProjAngles); + + if (useSinogramMask) { + // scale line weights with sinogram mask to zero out masked sinogram pixels + processVol<opMul, SINO>(D_lineWeight, D_smaskData, linePitch, dims.iProjDets, dims.iProjAngles); + } + + + zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2); + if (useSinogramMask) { + callBP(D_pixelWeight, pixelPitch, D_smaskData, smaskPitch); + } else { + processVol<opSet, SINO>(D_projData, 1.0f, projPitch, dims.iProjDets, dims.iProjAngles); + callBP(D_pixelWeight, pixelPitch, D_projData, projPitch); + } + processVol<opInvert, VOL>(D_pixelWeight, pixelPitch, dims.iVolWidth, dims.iVolHeight); + + if (useVolumeMask) { + // scale pixel weights with mask to zero out masked pixels + processVol<opMul, VOL>(D_pixelWeight, D_maskData, pixelPitch, dims.iVolWidth, dims.iVolHeight); + } + + return true; +} + +bool SIRT::setMinMaxMasks(float* D_minMaskData_, float* D_maxMaskData_, + unsigned int iPitch) +{ + D_minMaskData = D_minMaskData_; + D_maxMaskData = D_maxMaskData_; + minMaskPitch = iPitch; + maxMaskPitch = iPitch; + + freeMinMaxMasks = false; + return true; +} + +bool SIRT::uploadMinMaxMasks(const float* pfMinMaskData, const float* pfMaxMaskData, + unsigned int iPitch) +{ + freeMinMaxMasks = true; + bool ok = true; + if (pfMinMaskData) { + allocateVolume(D_minMaskData, dims.iVolWidth+2, dims.iVolHeight+2, minMaskPitch); + ok = copyVolumeToDevice(pfMinMaskData, iPitch, + dims.iVolWidth, dims.iVolHeight, + D_minMaskData, minMaskPitch); + } + if (!ok) + return false; + + if (pfMaxMaskData) { + allocateVolume(D_maxMaskData, dims.iVolWidth+2, dims.iVolHeight+2, maxMaskPitch); + ok = copyVolumeToDevice(pfMaxMaskData, iPitch, + dims.iVolWidth, dims.iVolHeight, + D_maxMaskData, maxMaskPitch); + } + if (!ok) + return false; + + return true; +} + +bool SIRT::iterate(unsigned int iterations) +{ + shouldAbort = false; + + if (useVolumeMask || useSinogramMask) + precomputeWeights(); + + // iteration + for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + + // copy sinogram to projection data + cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f); + } else { + callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f); + } + + processVol<opMul, SINO>(D_projData, D_lineWeight, projPitch, dims.iProjDets, dims.iProjAngles); + + zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2); + + callBP(D_tmpData, tmpPitch, D_projData, projPitch); + + processVol<opAddMul, VOL>(D_volumeData, D_pixelWeight, D_tmpData, volumePitch, dims.iVolWidth, dims.iVolHeight); + + if (useMinConstraint) + processVol<opClampMin, VOL>(D_volumeData, fMinConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight); + if (useMaxConstraint) + processVol<opClampMax, VOL>(D_volumeData, fMaxConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight); + if (D_minMaskData) + processVol<opClampMinMask, VOL>(D_volumeData, D_minMaskData, volumePitch, dims.iVolWidth, dims.iVolHeight); + if (D_maxMaskData) + processVol<opClampMaxMask, VOL>(D_volumeData, D_maxMaskData, volumePitch, dims.iVolWidth, dims.iVolHeight); + } + + return true; +} + +float SIRT::computeDiffNorm() +{ + // copy sinogram to projection data + cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice); + processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight); + callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f); + } else { + callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f); + } + + + // compute norm of D_projData + + float s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0); + + return sqrt(s); +} + + +bool doSIRT(float* D_volumeData, unsigned int volumePitch, + float* D_sinoData, unsigned int sinoPitch, + float* D_maskData, unsigned int maskPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, unsigned int iterations) +{ + SIRT sirt; + bool ok = true; + + ok &= sirt.setGeometry(dims, angles); + if (D_maskData) + ok &= sirt.enableVolumeMask(); + if (TOffsets) + ok &= sirt.setTOffsets(TOffsets); + + if (!ok) + return false; + + ok = sirt.init(); + if (!ok) + return false; + + if (D_maskData) + ok &= sirt.setVolumeMask(D_maskData, maskPitch); + + ok &= sirt.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch); + if (!ok) + return false; + + ok = sirt.iterate(iterations); + + return ok; +} + +} + +#ifdef STANDALONE + +using namespace astraCUDA; + +int main() +{ + float* D_volumeData; + float* D_sinoData; + + SDimensions dims; + dims.iVolWidth = 1024; + dims.iVolHeight = 1024; + dims.iProjAngles = 512; + dims.iProjDets = 1536; + dims.fDetScale = 1.0f; + dims.iRaysPerDet = 1; + unsigned int volumePitch, sinoPitch; + + allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch); + zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2); + printf("pitch: %u\n", volumePitch); + + allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch); + zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles); + printf("pitch: %u\n", sinoPitch); + + unsigned int y, x; + float* sino = loadImage("sino.png", y, x); + + float* img = new float[dims.iVolWidth*dims.iVolHeight]; + + copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_sinoData, sinoPitch); + + float* angle = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) + angle[i] = i*(M_PI/dims.iProjAngles); + + SIRT sirt; + + sirt.setGeometry(dims, angle); + sirt.init(); + + sirt.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch); + + sirt.iterate(25); + + + delete[] angle; + + copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch); + + saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img); + + return 0; +} +#endif + diff --git a/cuda/2d/sirt.h b/cuda/2d/sirt.h new file mode 100644 index 0000000..5592616 --- /dev/null +++ b/cuda/2d/sirt.h @@ -0,0 +1,90 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_SIRT_H +#define _CUDA_SIRT_H + +#include "util.h" +#include "algo.h" + +namespace astraCUDA { + +class _AstraExport SIRT : public ReconAlgo { +public: + SIRT(); + ~SIRT(); + + virtual bool init(); + + // Set min/max masks to existing GPU memory buffers + bool setMinMaxMasks(float* D_minMaskData, float* D_maxMaskData, + unsigned int pitch); + + // Set min/max masks from RAM buffers + bool uploadMinMaxMasks(const float* minMaskData, const float* maxMaskData, + unsigned int pitch); + + virtual bool iterate(unsigned int iterations); + + virtual float computeDiffNorm(); + +protected: + void reset(); + bool precomputeWeights(); + + // Temporary buffers + float* D_projData; + unsigned int projPitch; + + float* D_tmpData; + unsigned int tmpPitch; + + // Geometry-specific precomputed data + float* D_lineWeight; + unsigned int linePitch; + + float* D_pixelWeight; + unsigned int pixelPitch; + + // Masks + bool freeMinMaxMasks; + float* D_minMaskData; + unsigned int minMaskPitch; + float* D_maxMaskData; + unsigned int maxMaskPitch; +}; + +bool doSIRT(float* D_volumeData, unsigned int volumePitch, + float* D_projData, unsigned int projPitch, + float* D_maskData, unsigned int maskPitch, + const SDimensions& dims, const float* angles, + const float* TOffsets, unsigned int iterations); + +} + +#endif diff --git a/cuda/2d/util.cu b/cuda/2d/util.cu new file mode 100644 index 0000000..06f6714 --- /dev/null +++ b/cuda/2d/util.cu @@ -0,0 +1,244 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include "util.h" + +namespace astraCUDA { + +bool copyVolumeToDevice(const float* in_data, unsigned int in_pitch, + unsigned int width, unsigned int height, + float* outD_data, unsigned int out_pitch) +{ + // TODO: a full memset isn't necessary. Only the edges. + cudaError_t err; + err = cudaMemset2D(outD_data, sizeof(float)*out_pitch, 0, sizeof(float)*(width+2), height+2); + ASTRA_CUDA_ASSERT(err); + err = cudaMemcpy2D(outD_data + out_pitch + 1, sizeof(float)*out_pitch, in_data, sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyHostToDevice); + ASTRA_CUDA_ASSERT(err); + assert(err == cudaSuccess); + return true; +} + +bool copyVolumeFromDevice(float* out_data, unsigned int out_pitch, + unsigned int width, unsigned int height, + float* inD_data, unsigned int in_pitch) +{ + cudaError_t err = cudaMemcpy2D(out_data, sizeof(float)*out_pitch, inD_data + (in_pitch + 1), sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyDeviceToHost); + ASTRA_CUDA_ASSERT(err); + return true; +} + + +bool copySinogramFromDevice(float* out_data, unsigned int out_pitch, + unsigned int width, unsigned int height, + float* inD_data, unsigned int in_pitch) +{ + cudaError_t err = cudaMemcpy2D(out_data, sizeof(float)*out_pitch, inD_data + 1, sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyDeviceToHost); + ASTRA_CUDA_ASSERT(err); + return true; +} + +bool copySinogramToDevice(const float* in_data, unsigned int in_pitch, + unsigned int width, unsigned int height, + float* outD_data, unsigned int out_pitch) +{ + // TODO: a full memset isn't necessary. Only the edges. + cudaError_t err; + err = cudaMemset2D(outD_data, sizeof(float)*out_pitch, 0, (width+2)*sizeof(float), height); + ASTRA_CUDA_ASSERT(err); + err = cudaMemcpy2D(outD_data + 1, sizeof(float)*out_pitch, in_data, sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyHostToDevice); + ASTRA_CUDA_ASSERT(err); + return true; +} + + +bool allocateVolume(float*& ptr, unsigned int width, unsigned int height, unsigned int& pitch) +{ + size_t p; + cudaError_t ret = cudaMallocPitch((void**)&ptr, &p, sizeof(float)*width, height); + if (ret != cudaSuccess) { + reportCudaError(ret); + fprintf(stderr, "Failed to allocate %dx%d GPU buffer\n", width, height); + return false; + } + + assert(p % sizeof(float) == 0); + + pitch = p / sizeof(float); + + return true; +} + +void zeroVolume(float* data, unsigned int pitch, unsigned int width, unsigned int height) +{ + cudaError_t err; + err = cudaMemset2D(data, sizeof(float)*pitch, 0, sizeof(float)*width, height); + ASTRA_CUDA_ASSERT(err); +} + + +template <unsigned int blockSize> +__global__ void reduce1D(float *g_idata, float *g_odata, unsigned int n) +{ + extern __shared__ float sdata[]; + unsigned int tid = threadIdx.x; + + unsigned int i = blockIdx.x*(blockSize*2) + tid; + unsigned int gridSize = blockSize*gridDim.x; + sdata[tid] = 0; + while (i < n) { sdata[tid] += g_idata[i]; i += gridSize; } + __syncthreads(); + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); } + if (tid < 32) { + volatile float* smem = sdata; + if (blockSize >= 64) smem[tid] += smem[tid + 32]; + if (blockSize >= 32) smem[tid] += smem[tid + 16]; + if (blockSize >= 16) smem[tid] += smem[tid + 8]; + if (blockSize >= 8) smem[tid] += smem[tid + 4]; + if (blockSize >= 4) smem[tid] += smem[tid + 2]; + if (blockSize >= 2) smem[tid] += smem[tid + 1]; + } + if (tid == 0) g_odata[blockIdx.x] = sdata[0]; +} + +__global__ void reduce2D(float *g_idata, float *g_odata, + unsigned int pitch, + unsigned int nx, unsigned int ny, + unsigned int padX, unsigned int padY) +{ + extern __shared__ float sdata[]; + const unsigned int tidx = threadIdx.x; + const unsigned int tidy = threadIdx.y; + const unsigned int tid = tidy * 16 + tidx; + + unsigned int x = blockIdx.x*16 + tidx; + unsigned int y = blockIdx.y*16 + tidy; + + sdata[tid] = 0; + + if (x >= padX && x < padX + nx) { + + while (y < padY + ny) { + if (y >= padY) + sdata[tid] += (g_idata[pitch*y+x] * g_idata[pitch*y+x]); + y += 16 * gridDim.y; + } + + } + + __syncthreads(); + + if (tid < 128) + sdata[tid] += sdata[tid + 128]; + __syncthreads(); + + if (tid < 64) + sdata[tid] += sdata[tid + 64]; + __syncthreads(); + + if (tid < 32) { // 32 is warp size + volatile float* smem = sdata; + smem[tid] += smem[tid + 32]; + smem[tid] += smem[tid + 16]; + smem[tid] += smem[tid + 8]; + smem[tid] += smem[tid + 4]; + smem[tid] += smem[tid + 2]; + smem[tid] += smem[tid + 1]; + } + + if (tid == 0) + g_odata[blockIdx.y * gridDim.x + blockIdx.x] = sdata[0]; +} + +float dotProduct2D(float* D_data, unsigned int pitch, + unsigned int width, unsigned int height, + unsigned int padX, unsigned int padY) +{ + unsigned int bx = ((width+padX) + 15) / 16; + unsigned int by = ((height+padY) + 127) / 128; + unsigned int shared_mem2 = sizeof(float) * 16 * 16; + + dim3 dimBlock2(16, 16); + dim3 dimGrid2(bx, by); + + float* D_buf; + cudaMalloc(&D_buf, sizeof(float) * (bx * by + 1) ); + + // Step 1: reduce 2D from image to a single vector, taking sum of squares + + reduce2D<<< dimGrid2, dimBlock2, shared_mem2>>>(D_data, D_buf, pitch, width, height, padX, padY); + cudaTextForceKernelsCompletion(); + + // Step 2: reduce 1D: add up elements in vector + if (bx * by > 512) + reduce1D<512><<< 1, 512, sizeof(float)*512>>>(D_buf, D_buf+(bx*by), bx*by); + else if (bx * by > 128) + reduce1D<128><<< 1, 128, sizeof(float)*128>>>(D_buf, D_buf+(bx*by), bx*by); + else if (bx * by > 32) + reduce1D<32><<< 1, 32, sizeof(float)*32*2>>>(D_buf, D_buf+(bx*by), bx*by); + else if (bx * by > 8) + reduce1D<8><<< 1, 8, sizeof(float)*8*2>>>(D_buf, D_buf+(bx*by), bx*by); + else + reduce1D<1><<< 1, 1, sizeof(float)*1*2>>>(D_buf, D_buf+(bx*by), bx*by); + + float x; + cudaMemcpy(&x, D_buf+(bx*by), 4, cudaMemcpyDeviceToHost); + + cudaTextForceKernelsCompletion(); + + cudaFree(D_buf); + + return x; +} + + +bool cudaTextForceKernelsCompletion() +{ + cudaError_t returnedCudaError = cudaThreadSynchronize(); + + if(returnedCudaError != cudaSuccess) { + fprintf(stderr, "Failed to force completion of cuda kernels: %d: %s.\n", returnedCudaError, cudaGetErrorString(returnedCudaError)); + return false; + } + + return true; +} + +void reportCudaError(cudaError_t err) +{ + if(err != cudaSuccess) + fprintf(stderr, "CUDA error %d: %s.\n", err, cudaGetErrorString(err)); +} + + + +} diff --git a/cuda/2d/util.h b/cuda/2d/util.h new file mode 100644 index 0000000..d31e2eb --- /dev/null +++ b/cuda/2d/util.h @@ -0,0 +1,90 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_UTIL_H +#define _CUDA_UTIL_H + +#include <cuda.h> +#include <driver_types.h> + +#ifdef _MSC_VER + +#ifdef DLL_EXPORTS +#define _AstraExport __declspec(dllexport) +#define EXPIMP_TEMPLATE +#else +#define _AstraExport __declspec(dllimport) +#define EXPIMP_TEMPLATE extern +#endif + +#else + +#define _AstraExport + +#endif + +#include "dims.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define ASTRA_CUDA_ASSERT(err) do { if (err != cudaSuccess) { astraCUDA::reportCudaError(err); assert(err == cudaSuccess); } } while(0) + + +namespace astraCUDA { + +bool copyVolumeToDevice(const float* in_data, unsigned int in_pitch, + unsigned int width, unsigned int height, + float* outD_data, unsigned int out_pitch); +bool copyVolumeFromDevice(float* out_data, unsigned int out_pitch, + unsigned int width, unsigned int height, + float* inD_data, unsigned int in_pitch); +bool copySinogramFromDevice(float* out_data, unsigned int out_pitch, + unsigned int width, unsigned int height, + float* inD_data, unsigned int in_pitch); +bool copySinogramToDevice(const float* in_data, unsigned int in_pitch, + unsigned int width, unsigned int height, + float* outD_data, unsigned int out_pitch); + +bool allocateVolume(float*& D_ptr, unsigned int width, unsigned int height, unsigned int& pitch); + +void zeroVolume(float* D_data, unsigned int pitch, unsigned int width, unsigned int height); + +bool cudaTextForceKernelsCompletion(); +void reportCudaError(cudaError_t err); + + + +float dotProduct2D(float* D_data, unsigned int pitch, + unsigned int width, unsigned int height, + unsigned int padX, unsigned int padY); + +} + +#endif diff --git a/cuda/3d/algo3d.cu b/cuda/3d/algo3d.cu new file mode 100644 index 0000000..20e7381 --- /dev/null +++ b/cuda/3d/algo3d.cu @@ -0,0 +1,108 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cassert> + +#include "algo3d.h" +#include "cone_fp.h" +#include "cone_bp.h" +#include "par3d_fp.h" +#include "par3d_bp.h" + +namespace astraCUDA3d { + +ReconAlgo3D::ReconAlgo3D() +{ + coneProjs = 0; + par3DProjs = 0; + shouldAbort = false; +} + +ReconAlgo3D::~ReconAlgo3D() +{ + reset(); +} + +void ReconAlgo3D::reset() +{ + delete[] coneProjs; + coneProjs = 0; + delete[] par3DProjs; + par3DProjs = 0; + shouldAbort = false; +} + +bool ReconAlgo3D::setConeGeometry(const SDimensions3D& _dims, const SConeProjection* _angles) +{ + dims = _dims; + + coneProjs = new SConeProjection[dims.iProjAngles]; + par3DProjs = 0; + + memcpy(coneProjs, _angles, sizeof(coneProjs[0]) * dims.iProjAngles); + + return true; +} + +bool ReconAlgo3D::setPar3DGeometry(const SDimensions3D& _dims, const SPar3DProjection* _angles) +{ + dims = _dims; + + par3DProjs = new SPar3DProjection[dims.iProjAngles]; + coneProjs = 0; + + memcpy(par3DProjs, _angles, sizeof(par3DProjs[0]) * dims.iProjAngles); + + return true; +} + + +bool ReconAlgo3D::callFP(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_projData, + float outputScale) +{ + if (coneProjs) { + return ConeFP(D_volumeData, D_projData, dims, coneProjs, outputScale); + } else { + return Par3DFP(D_volumeData, D_projData, dims, par3DProjs, outputScale); + } +} + +bool ReconAlgo3D::callBP(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_projData) +{ + if (coneProjs) { + return ConeBP(D_volumeData, D_projData, dims, coneProjs); + } else { + return Par3DBP(D_volumeData, D_projData, dims, par3DProjs); + } +} + + + +} diff --git a/cuda/3d/algo3d.h b/cuda/3d/algo3d.h new file mode 100644 index 0000000..2b44f6f --- /dev/null +++ b/cuda/3d/algo3d.h @@ -0,0 +1,68 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ALGO_H +#define _CUDA_ALGO_H + +#include "dims3d.h" +#include "util3d.h" + +namespace astraCUDA3d { + +class _AstraExport ReconAlgo3D { +public: + ReconAlgo3D(); + ~ReconAlgo3D(); + + bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs); + bool setPar3DGeometry(const SDimensions3D& dims, const SPar3DProjection* projs); + + void signalAbort() { shouldAbort = true; } + +protected: + void reset(); + + bool callFP(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_projData, + float outputScale); + bool callBP(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_projData); + + SDimensions3D dims; + SConeProjection* coneProjs; + SPar3DProjection* par3DProjs; + + volatile bool shouldAbort; + +}; + + +} + +#endif + diff --git a/cuda/3d/arith3d.cu b/cuda/3d/arith3d.cu new file mode 100644 index 0000000..9a19be0 --- /dev/null +++ b/cuda/3d/arith3d.cu @@ -0,0 +1,610 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "util3d.h" +#include "arith3d.h" +#include <cassert> + +namespace astraCUDA3d { + +struct opAddScaled { + __device__ void operator()(float& out, const float in, const float inp) { + out += in * inp; + } +}; +struct opScaleAndAdd { + __device__ void operator()(float& out, const float in, const float inp) { + out = in + out * inp; + } +}; +struct opAddMulScaled { + __device__ void operator()(float& out, const float in1, const float in2, const float inp) { + out += in1 * in2 * inp; + } +}; +struct opAddMul { + __device__ void operator()(float& out, const float in1, const float in2) { + out += in1 * in2; + } +}; +struct opMul { + __device__ void operator()(float& out, const float in) { + out *= in; + } +}; +struct opMul2 { + __device__ void operator()(float& out, const float in1, const float in2) { + out *= in1 * in2; + } +}; +struct opDividedBy { + __device__ void operator()(float& out, const float in) { + if (out > 0.000001f) // out is assumed to be positive + out = in / out; + else + out = 0.0f; + } +}; +struct opInvert { + __device__ void operator()(float& out) { + if (out > 0.000001f) // out is assumed to be positive + out = 1 / out; + else + out = 0.0f; + } +}; +struct opSet { + __device__ void operator()(float& out, const float inp) { + out = inp; + } +}; +struct opClampMin { + __device__ void operator()(float& out, const float inp) { + if (out < inp) + out = inp; + } +}; +struct opClampMax { + __device__ void operator()(float& out, const float inp) { + if (out > inp) + out = inp; + } +}; + + + + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devtoD(float* pfOut, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off]); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devFtoD(float* pfOut, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], fParam); + off += pitch; + y++; + } +} + + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDtoD(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn[off]); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDFtoD(float* pfOut, const float* pfIn, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn[off], fParam); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDDtoD(float* pfOut, const float* pfIn1, const float* pfIn2, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn1[off], pfIn2[off]); + off += pitch; + y++; + } +} + +template<class op, unsigned int padX, unsigned int padY, unsigned int repeat> +__global__ void devDDFtoD(float* pfOut, const float* pfIn1, const float* pfIn2, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + unsigned int x = threadIdx.x + 16*blockIdx.x; + if (x >= width) return; + + unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat; + unsigned int off = (y+padY)*pitch+x+padX; + for (unsigned int i = 0; i < repeat; ++i) { + if (y >= height) + break; + op()(pfOut[off], pfIn1[off], pfIn2[off], fParam); + off += pitch; + y++; + } +} + + + + + + + + + +template<typename op, VolType t> +void processVol(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+511)/512); + + float *pfOut = (float*)out; + + devtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + float *pfOut = (float*)out; + + devFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, fParam, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + float *pfOut = (float*)out; + const float *pfIn = (const float*)in; + + devDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + float *pfOut = (float*)out; + const float *pfIn = (const float*)in; + + devDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + float *pfOut = (float*)out; + const float *pfIn1 = (const float*)in1; + const float *pfIn2 = (const float*)in2; + + devDDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + +template<typename op, VolType t> +void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height) +{ + dim3 blockSize(16,16); + dim3 gridSize((width+15)/16, (height+15)/16); + + float *pfOut = (float*)out; + const float *pfIn1 = (const float*)in1; + const float *pfIn2 = (const float*)in2; + + devDDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, pitch, width, height); + + cudaTextForceKernelsCompletion(); +} + + + + + + + + + + + + + + + + + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iVolY; + + for (unsigned int i = 0; i < dims.iVolZ; ++i) { + devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iVolX, dims.iVolY); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + + + + + + + + + + + + + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn = (float*)in.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + +template<typename op> +void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims) +{ + dim3 blockSize(16,16); + dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512); + float *pfOut = (float*)out.ptr; + float *pfIn1 = (float*)in1.ptr; + float *pfIn2 = (float*)in2.ptr; + unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles; + + for (unsigned int i = 0; i < dims.iProjV; ++i) { + devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles); + pfOut += step; + pfIn1 += step; + pfIn2 += step; + } + + cudaTextForceKernelsCompletion(); +} + + + + + + + + + + + + + + + + + + +#define INST_DFtoD(name) \ + template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); + +#define INST_DtoD(name) \ + template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); + +#define INST_DDtoD(name) \ + template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); + +#define INST_DDFtoD(name) \ + template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); + + +#define INST_toD(name) \ + template void processVol<name, VOL>(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims); + +#define INST_FtoD(name) \ + template void processVol<name, VOL>(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol<name, SINO>(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \ + template void processVol3D<name>(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); \ + template void processSino3D<name>(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); + + + +INST_DFtoD(opAddScaled) +INST_DFtoD(opScaleAndAdd) +INST_DDFtoD(opAddMulScaled) +INST_DDtoD(opAddMul) +INST_DDtoD(opMul2) +INST_DtoD(opMul) +INST_DtoD(opDividedBy) +INST_toD(opInvert) +INST_FtoD(opSet) +INST_FtoD(opClampMin) +INST_FtoD(opClampMax) + + +} diff --git a/cuda/3d/arith3d.h b/cuda/3d/arith3d.h new file mode 100644 index 0000000..53c9b79 --- /dev/null +++ b/cuda/3d/arith3d.h @@ -0,0 +1,79 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ARITH3D_H +#define _CUDA_ARITH3D_H + +#include <cuda.h> + +namespace astraCUDA3d { + +struct opAddScaled; +struct opScaleAndAdd; +struct opAddMulScaled; +struct opAddMul; +struct opMul; +struct opMul2; +struct opDividedBy; +struct opInvert; +struct opSet; +struct opClampMin; +struct opClampMax; + +enum VolType { + SINO = 0, + VOL = 1 +}; + + +template<typename op, VolType t> void processVol(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); +template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height); + +template<typename op> void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); +template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); + +template<typename op> void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); +template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); + + + +} + +#endif diff --git a/cuda/3d/astra3d.cu b/cuda/3d/astra3d.cu new file mode 100644 index 0000000..fd4b370 --- /dev/null +++ b/cuda/3d/astra3d.cu @@ -0,0 +1,1620 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "cgls3d.h" +#include "sirt3d.h" +#include "util3d.h" +#include "cone_fp.h" +#include "cone_bp.h" +#include "par3d_fp.h" +#include "par3d_bp.h" +#include "fdk.h" +#include "arith3d.h" +#include "astra3d.h" + +#include <iostream> + +using namespace astraCUDA3d; + +namespace astra { + +enum CUDAProjectionType3d { + PROJ_PARALLEL, + PROJ_CONE +}; + + +static SConeProjection* genConeProjections(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + double fOriginSourceDistance, + double fOriginDetectorDistance, + double fDetUSize, + double fDetVSize, + const float *pfAngles) +{ + SConeProjection base; + base.fSrcX = 0.0f; + base.fSrcY = -fOriginSourceDistance; + base.fSrcZ = 0.0f; + + base.fDetSX = iProjU * fDetUSize * -0.5f; + base.fDetSY = fOriginDetectorDistance; + base.fDetSZ = iProjV * fDetVSize * -0.5f; + + base.fDetUX = fDetUSize; + base.fDetUY = 0.0f; + base.fDetUZ = 0.0f; + + base.fDetVX = 0.0f; + base.fDetVY = 0.0f; + base.fDetVZ = fDetVSize; + + SConeProjection* p = new SConeProjection[iProjAngles]; + +#define ROTATE0(name,i,alpha) do { p[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); p[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); p[i].f##name##Z = base.f##name##Z; } while(0) + + for (unsigned int i = 0; i < iProjAngles; ++i) { + ROTATE0(Src, i, pfAngles[i]); + ROTATE0(DetS, i, pfAngles[i]); + ROTATE0(DetU, i, pfAngles[i]); + ROTATE0(DetV, i, pfAngles[i]); + } + +#undef ROTATE0 + + return p; +} + +static SPar3DProjection* genPar3DProjections(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + double fDetUSize, + double fDetVSize, + const float *pfAngles) +{ + SPar3DProjection base; + base.fRayX = 0.0f; + base.fRayY = 1.0f; + base.fRayZ = 0.0f; + + base.fDetSX = iProjU * fDetUSize * -0.5f; + base.fDetSY = 0.0f; + base.fDetSZ = iProjV * fDetVSize * -0.5f; + + base.fDetUX = fDetUSize; + base.fDetUY = 0.0f; + base.fDetUZ = 0.0f; + + base.fDetVX = 0.0f; + base.fDetVY = 0.0f; + base.fDetVZ = fDetVSize; + + SPar3DProjection* p = new SPar3DProjection[iProjAngles]; + +#define ROTATE0(name,i,alpha) do { p[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); p[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); p[i].f##name##Z = base.f##name##Z; } while(0) + + for (unsigned int i = 0; i < iProjAngles; ++i) { + ROTATE0(Ray, i, pfAngles[i]); + ROTATE0(DetS, i, pfAngles[i]); + ROTATE0(DetU, i, pfAngles[i]); + ROTATE0(DetV, i, pfAngles[i]); + } + +#undef ROTATE0 + + return p; +} + + + + +class AstraSIRT3d_internal { +public: + SDimensions3D dims; + CUDAProjectionType3d projType; + + float* angles; + float fOriginSourceDistance; + float fOriginDetectorDistance; + float fSourceZ; + float fDetSize; + + SConeProjection* projs; + SPar3DProjection* parprojs; + + float fPixelSize; + + bool initialized; + bool setStartReconstruction; + + bool useVolumeMask; + bool useSinogramMask; + + // Input/output + cudaPitchedPtr D_projData; + cudaPitchedPtr D_volumeData; + cudaPitchedPtr D_maskData; + cudaPitchedPtr D_smaskData; + + SIRT sirt; +}; + +AstraSIRT3d::AstraSIRT3d() +{ + pData = new AstraSIRT3d_internal(); + + pData->angles = 0; + pData->D_projData.ptr = 0; + pData->D_volumeData.ptr = 0; + pData->D_maskData.ptr = 0; + pData->D_smaskData.ptr = 0; + + pData->dims.iVolX = 0; + pData->dims.iVolY = 0; + pData->dims.iVolZ = 0; + pData->dims.iProjAngles = 0; + pData->dims.iProjU = 0; + pData->dims.iProjV = 0; + pData->dims.iRaysPerDetDim = 1; + pData->dims.iRaysPerVoxelDim = 1; + + pData->projs = 0; + + pData->initialized = false; + pData->setStartReconstruction = false; + + pData->useVolumeMask = false; + pData->useSinogramMask = false; +} + +AstraSIRT3d::~AstraSIRT3d() +{ + delete[] pData->angles; + pData->angles = 0; + + delete[] pData->projs; + pData->projs = 0; + + cudaFree(pData->D_projData.ptr); + pData->D_projData.ptr = 0; + + cudaFree(pData->D_volumeData.ptr); + pData->D_volumeData.ptr = 0; + + cudaFree(pData->D_maskData.ptr); + pData->D_maskData.ptr = 0; + + cudaFree(pData->D_smaskData.ptr); + pData->D_smaskData.ptr = 0; + + delete pData; + pData = 0; +} + +bool AstraSIRT3d::setReconstructionGeometry(unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ/*, + float fPixelSize = 1.0f*/) +{ + if (pData->initialized) + return false; + + pData->dims.iVolX = iVolX; + pData->dims.iVolY = iVolY; + pData->dims.iVolZ = iVolZ; + + return (iVolX > 0 && iVolY > 0 && iVolZ > 0); +} + + +bool AstraSIRT3d::setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection* projs) +{ + if (pData->initialized) + return false; + + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0) + return false; + + pData->parprojs = new SPar3DProjection[iProjAngles]; + memcpy(pData->parprojs, projs, iProjAngles * sizeof(projs[0])); + + pData->projType = PROJ_PARALLEL; + + return true; +} + +bool AstraSIRT3d::setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fDetUSize, + float fDetVSize, + const float *pfAngles) +{ + if (pData->initialized) + return false; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SPar3DProjection* p = genPar3DProjections(iProjAngles, + iProjU, iProjV, + fDetUSize, fDetVSize, + pfAngles); + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + pData->parprojs = p; + pData->projType = PROJ_PARALLEL; + + return true; +} + + + +bool AstraSIRT3d::setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection* projs) +{ + if (pData->initialized) + return false; + + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0) + return false; + + pData->projs = new SConeProjection[iProjAngles]; + memcpy(pData->projs, projs, iProjAngles * sizeof(projs[0])); + + pData->projType = PROJ_CONE; + + return true; +} + +bool AstraSIRT3d::setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles) +{ + if (pData->initialized) + return false; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SConeProjection* p = genConeProjections(iProjAngles, + iProjU, iProjV, + fOriginSourceDistance, + fOriginDetectorDistance, + fDetUSize, fDetVSize, + pfAngles); + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + pData->projs = p; + pData->projType = PROJ_CONE; + + return true; +} + +bool AstraSIRT3d::enableSuperSampling(unsigned int iVoxelSuperSampling, + unsigned int iDetectorSuperSampling) +{ + if (pData->initialized) + return false; + + if (iVoxelSuperSampling == 0 || iDetectorSuperSampling == 0) + return false; + + pData->dims.iRaysPerVoxelDim = iVoxelSuperSampling; + pData->dims.iRaysPerDetDim = iDetectorSuperSampling; + + return true; +} + +bool AstraSIRT3d::enableVolumeMask() +{ + if (pData->initialized) + return false; + + bool ok = pData->sirt.enableVolumeMask(); + pData->useVolumeMask = ok; + + return ok; +} + +bool AstraSIRT3d::enableSinogramMask() +{ + if (pData->initialized) + return false; + + bool ok = pData->sirt.enableSinogramMask(); + pData->useSinogramMask = ok; + + return ok; +} + +bool AstraSIRT3d::setGPUIndex(int index) +{ + cudaSetDevice(index); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + return true; +} + +bool AstraSIRT3d::init() +{ + fprintf(stderr, "001: %d\n", true); + if (pData->initialized) + return false; + fprintf(stderr, "002: %d\n", true); + + if (pData->dims.iVolX == 0 || pData->dims.iProjAngles == 0) + return false; + fprintf(stderr, "003: %d\n", true); + + bool ok; + + if (pData->projType == PROJ_PARALLEL) { + ok = pData->sirt.setPar3DGeometry(pData->dims, pData->parprojs); + } else { + ok = pData->sirt.setConeGeometry(pData->dims, pData->projs); + } + fprintf(stderr, "004: %d\n", ok); + + if (!ok) + return false; + + ok = pData->sirt.init(); + if (!ok) + return false; + fprintf(stderr, "005: %d\n", ok); + + pData->D_volumeData = allocateVolumeData(pData->dims); + ok = pData->D_volumeData.ptr; + if (!ok) + return false; + fprintf(stderr, "006: %d\n", ok); + + fprintf(stderr, "proj: %d %d %d\n", pData->dims.iProjAngles, pData->dims.iProjU, pData->dims.iProjV); + pData->D_projData = allocateProjectionData(pData->dims); + ok = pData->D_projData.ptr; + if (!ok) { + cudaFree(pData->D_volumeData.ptr); + pData->D_volumeData.ptr = 0; + return false; + } + fprintf(stderr, "007: %d\n", ok); + + if (pData->useVolumeMask) { + pData->D_maskData = allocateVolumeData(pData->dims); + ok = pData->D_maskData.ptr; + if (!ok) { + cudaFree(pData->D_volumeData.ptr); + cudaFree(pData->D_projData.ptr); + pData->D_volumeData.ptr = 0; + pData->D_projData.ptr = 0; + return false; + } + } + + if (pData->useSinogramMask) { + pData->D_smaskData = allocateProjectionData(pData->dims); + ok = pData->D_smaskData.ptr; + if (!ok) { + cudaFree(pData->D_volumeData.ptr); + cudaFree(pData->D_projData.ptr); + cudaFree(pData->D_maskData.ptr); + pData->D_volumeData.ptr = 0; + pData->D_projData.ptr = 0; + pData->D_maskData.ptr = 0; + return false; + } + } + fprintf(stderr, "008: %d\n", ok); + + pData->initialized = true; + + return true; +} + +bool AstraSIRT3d::setMinConstraint(float fMin) +{ + if (!pData->initialized) + return false; + return pData->sirt.setMinConstraint(fMin); +} + +bool AstraSIRT3d::setMaxConstraint(float fMax) +{ + if (!pData->initialized) + return false; + return pData->sirt.setMaxConstraint(fMax); +} + +bool AstraSIRT3d::setSinogram(const float* pfSinogram, + unsigned int iSinogramPitch) +{ + if (!pData->initialized) + return false; + if (!pfSinogram) + return false; + + bool ok = copyProjectionsToDevice(pfSinogram, pData->D_projData, pData->dims, iSinogramPitch); + + if (!ok) + return false; + + ok = pData->sirt.setBuffers(pData->D_volumeData, pData->D_projData); + if (!ok) + return false; + + pData->setStartReconstruction = false; + + return true; +} + +bool AstraSIRT3d::setVolumeMask(const float* pfMask, unsigned int iMaskPitch) +{ + if (!pData->initialized) + return false; + if (!pData->useVolumeMask) + return false; + if (!pfMask) + return false; + + bool ok = copyVolumeToDevice(pfMask, pData->D_maskData, + pData->dims, iMaskPitch); + if (!ok) + return false; + + ok = pData->sirt.setVolumeMask(pData->D_maskData); + if (!ok) + return false; + + return true; +} + +bool AstraSIRT3d::setSinogramMask(const float* pfMask, unsigned int iMaskPitch) +{ + if (!pData->initialized) + return false; + if (!pData->useSinogramMask) + return false; + if (!pfMask) + return false; + + bool ok = copyProjectionsToDevice(pfMask, pData->D_smaskData, pData->dims, iMaskPitch); + + if (!ok) + return false; + + ok = pData->sirt.setSinogramMask(pData->D_smaskData); + if (!ok) + return false; + + return true; +} + +bool AstraSIRT3d::setStartReconstruction(const float* pfReconstruction, + unsigned int iReconstructionPitch) +{ + if (!pData->initialized) + return false; + if (!pfReconstruction) + return false; + + bool ok = copyVolumeToDevice(pfReconstruction, pData->D_volumeData, + pData->dims, iReconstructionPitch); + if (!ok) + return false; + + pData->setStartReconstruction = true; + + return true; +} + +bool AstraSIRT3d::iterate(unsigned int iIterations) +{ + if (!pData->initialized) + return false; + + if (!pData->setStartReconstruction) + zeroVolumeData(pData->D_volumeData, pData->dims); + + bool ok = pData->sirt.iterate(iIterations); + if (!ok) + return false; + + return true; +} + +bool AstraSIRT3d::getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const +{ + if (!pData->initialized) + return false; + + bool ok = copyVolumeFromDevice(pfReconstruction, pData->D_volumeData, + pData->dims, iReconstructionPitch); + if (!ok) + return false; + + return true; +} + +void AstraSIRT3d::signalAbort() +{ + if (!pData->initialized) + return; + + pData->sirt.signalAbort(); +} + +float AstraSIRT3d::computeDiffNorm() +{ + if (!pData->initialized) + return 0.0f; // FIXME: Error? + + return pData->sirt.computeDiffNorm(); +} + + + + +class AstraCGLS3d_internal { +public: + SDimensions3D dims; + CUDAProjectionType3d projType; + + float* angles; + float fOriginSourceDistance; + float fOriginDetectorDistance; + float fSourceZ; + float fDetSize; + + SConeProjection* projs; + SPar3DProjection* parprojs; + + float fPixelSize; + + bool initialized; + bool setStartReconstruction; + + bool useVolumeMask; + bool useSinogramMask; + + // Input/output + cudaPitchedPtr D_projData; + cudaPitchedPtr D_volumeData; + cudaPitchedPtr D_maskData; + cudaPitchedPtr D_smaskData; + + CGLS cgls; +}; + +AstraCGLS3d::AstraCGLS3d() +{ + pData = new AstraCGLS3d_internal(); + + pData->angles = 0; + pData->D_projData.ptr = 0; + pData->D_volumeData.ptr = 0; + pData->D_maskData.ptr = 0; + pData->D_smaskData.ptr = 0; + + pData->dims.iVolX = 0; + pData->dims.iVolY = 0; + pData->dims.iVolZ = 0; + pData->dims.iProjAngles = 0; + pData->dims.iProjU = 0; + pData->dims.iProjV = 0; + pData->dims.iRaysPerDetDim = 1; + pData->dims.iRaysPerVoxelDim = 1; + + pData->projs = 0; + + pData->initialized = false; + pData->setStartReconstruction = false; + + pData->useVolumeMask = false; + pData->useSinogramMask = false; +} + +AstraCGLS3d::~AstraCGLS3d() +{ + delete[] pData->angles; + pData->angles = 0; + + delete[] pData->projs; + pData->projs = 0; + + cudaFree(pData->D_projData.ptr); + pData->D_projData.ptr = 0; + + cudaFree(pData->D_volumeData.ptr); + pData->D_volumeData.ptr = 0; + + cudaFree(pData->D_maskData.ptr); + pData->D_maskData.ptr = 0; + + cudaFree(pData->D_smaskData.ptr); + pData->D_smaskData.ptr = 0; + + delete pData; + pData = 0; +} + +bool AstraCGLS3d::setReconstructionGeometry(unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ/*, + float fPixelSize = 1.0f*/) +{ + if (pData->initialized) + return false; + + pData->dims.iVolX = iVolX; + pData->dims.iVolY = iVolY; + pData->dims.iVolZ = iVolZ; + + return (iVolX > 0 && iVolY > 0 && iVolZ > 0); +} + + +bool AstraCGLS3d::setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection* projs) +{ + if (pData->initialized) + return false; + + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0) + return false; + + pData->parprojs = new SPar3DProjection[iProjAngles]; + memcpy(pData->parprojs, projs, iProjAngles * sizeof(projs[0])); + + pData->projType = PROJ_PARALLEL; + + return true; +} + +bool AstraCGLS3d::setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fDetUSize, + float fDetVSize, + const float *pfAngles) +{ + if (pData->initialized) + return false; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SPar3DProjection* p = genPar3DProjections(iProjAngles, + iProjU, iProjV, + fDetUSize, fDetVSize, + pfAngles); + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + pData->parprojs = p; + pData->projType = PROJ_PARALLEL; + + return true; +} + + + +bool AstraCGLS3d::setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection* projs) +{ + if (pData->initialized) + return false; + + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0) + return false; + + pData->projs = new SConeProjection[iProjAngles]; + memcpy(pData->projs, projs, iProjAngles * sizeof(projs[0])); + + pData->projType = PROJ_CONE; + + return true; +} + +bool AstraCGLS3d::setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles) +{ + if (pData->initialized) + return false; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SConeProjection* p = genConeProjections(iProjAngles, + iProjU, iProjV, + fOriginSourceDistance, + fOriginDetectorDistance, + fDetUSize, fDetVSize, + pfAngles); + + pData->dims.iProjAngles = iProjAngles; + pData->dims.iProjU = iProjU; + pData->dims.iProjV = iProjV; + + pData->projs = p; + pData->projType = PROJ_CONE; + + return true; +} + +bool AstraCGLS3d::enableSuperSampling(unsigned int iVoxelSuperSampling, + unsigned int iDetectorSuperSampling) +{ + if (pData->initialized) + return false; + + if (iVoxelSuperSampling == 0 || iDetectorSuperSampling == 0) + return false; + + pData->dims.iRaysPerVoxelDim = iVoxelSuperSampling; + pData->dims.iRaysPerDetDim = iDetectorSuperSampling; + + return true; +} + +bool AstraCGLS3d::enableVolumeMask() +{ + if (pData->initialized) + return false; + + bool ok = pData->cgls.enableVolumeMask(); + pData->useVolumeMask = ok; + + return ok; +} + +#if 0 +bool AstraCGLS3d::enableSinogramMask() +{ + if (pData->initialized) + return false; + + bool ok = pData->cgls.enableSinogramMask(); + pData->useSinogramMask = ok; + + return ok; +} +#endif + +bool AstraCGLS3d::setGPUIndex(int index) +{ + cudaSetDevice(index); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + return true; +} + +bool AstraCGLS3d::init() +{ + fprintf(stderr, "001: %d\n", true); + if (pData->initialized) + return false; + fprintf(stderr, "002: %d\n", true); + + if (pData->dims.iVolX == 0 || pData->dims.iProjAngles == 0) + return false; + fprintf(stderr, "003: %d\n", true); + + bool ok; + + if (pData->projType == PROJ_PARALLEL) { + ok = pData->cgls.setPar3DGeometry(pData->dims, pData->parprojs); + } else { + ok = pData->cgls.setConeGeometry(pData->dims, pData->projs); + } + fprintf(stderr, "004: %d\n", ok); + + if (!ok) + return false; + + ok = pData->cgls.init(); + if (!ok) + return false; + fprintf(stderr, "005: %d\n", ok); + + pData->D_volumeData = allocateVolumeData(pData->dims); + ok = pData->D_volumeData.ptr; + if (!ok) + return false; + fprintf(stderr, "006: %d\n", ok); + + fprintf(stderr, "proj: %d %d %d\n", pData->dims.iProjAngles, pData->dims.iProjU, pData->dims.iProjV); + pData->D_projData = allocateProjectionData(pData->dims); + ok = pData->D_projData.ptr; + if (!ok) { + cudaFree(pData->D_volumeData.ptr); + pData->D_volumeData.ptr = 0; + return false; + } + fprintf(stderr, "007: %d\n", ok); + + if (pData->useVolumeMask) { + pData->D_maskData = allocateVolumeData(pData->dims); + ok = pData->D_maskData.ptr; + if (!ok) { + cudaFree(pData->D_volumeData.ptr); + cudaFree(pData->D_projData.ptr); + pData->D_volumeData.ptr = 0; + pData->D_projData.ptr = 0; + return false; + } + } + + if (pData->useSinogramMask) { + pData->D_smaskData = allocateProjectionData(pData->dims); + ok = pData->D_smaskData.ptr; + if (!ok) { + cudaFree(pData->D_volumeData.ptr); + cudaFree(pData->D_projData.ptr); + cudaFree(pData->D_maskData.ptr); + pData->D_volumeData.ptr = 0; + pData->D_projData.ptr = 0; + pData->D_maskData.ptr = 0; + return false; + } + } + fprintf(stderr, "008: %d\n", ok); + + pData->initialized = true; + + return true; +} + +#if 0 +bool AstraCGLS3d::setMinConstraint(float fMin) +{ + if (!pData->initialized) + return false; + return pData->cgls.setMinConstraint(fMin); +} + +bool AstraCGLS3d::setMaxConstraint(float fMax) +{ + if (!pData->initialized) + return false; + return pData->cgls.setMaxConstraint(fMax); +} +#endif + +bool AstraCGLS3d::setSinogram(const float* pfSinogram, + unsigned int iSinogramPitch) +{ + if (!pData->initialized) + return false; + if (!pfSinogram) + return false; + + bool ok = copyProjectionsToDevice(pfSinogram, pData->D_projData, pData->dims, iSinogramPitch); + + if (!ok) + return false; + + ok = pData->cgls.setBuffers(pData->D_volumeData, pData->D_projData); + if (!ok) + return false; + + pData->setStartReconstruction = false; + + return true; +} + +bool AstraCGLS3d::setVolumeMask(const float* pfMask, unsigned int iMaskPitch) +{ + if (!pData->initialized) + return false; + if (!pData->useVolumeMask) + return false; + if (!pfMask) + return false; + + bool ok = copyVolumeToDevice(pfMask, pData->D_maskData, + pData->dims, iMaskPitch); + if (!ok) + return false; + + ok = pData->cgls.setVolumeMask(pData->D_maskData); + if (!ok) + return false; + + return true; +} + +#if 0 +bool AstraCGLS3d::setSinogramMask(const float* pfMask, unsigned int iMaskPitch) +{ + if (!pData->initialized) + return false; + if (!pData->useSinogramMask) + return false; + if (!pfMask) + return false; + + bool ok = copyProjectionsToDevice(pfMask, pData->D_smaskData, pData->dims, iMaskPitch); + + if (!ok) + return false; + + ok = pData->cgls.setSinogramMask(pData->D_smaskData); + if (!ok) + return false; + + return true; +} +#endif + +bool AstraCGLS3d::setStartReconstruction(const float* pfReconstruction, + unsigned int iReconstructionPitch) +{ + if (!pData->initialized) + return false; + if (!pfReconstruction) + return false; + + bool ok = copyVolumeToDevice(pfReconstruction, pData->D_volumeData, + pData->dims, iReconstructionPitch); + if (!ok) + return false; + + pData->setStartReconstruction = true; + + return true; +} + +bool AstraCGLS3d::iterate(unsigned int iIterations) +{ + if (!pData->initialized) + return false; + + if (!pData->setStartReconstruction) + zeroVolumeData(pData->D_volumeData, pData->dims); + + bool ok = pData->cgls.iterate(iIterations); + if (!ok) + return false; + + return true; +} + +bool AstraCGLS3d::getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const +{ + if (!pData->initialized) + return false; + + bool ok = copyVolumeFromDevice(pfReconstruction, pData->D_volumeData, + pData->dims, iReconstructionPitch); + if (!ok) + return false; + + return true; +} + +void AstraCGLS3d::signalAbort() +{ + if (!pData->initialized) + return; + + pData->cgls.signalAbort(); +} + +float AstraCGLS3d::computeDiffNorm() +{ + if (!pData->initialized) + return 0.0f; // FIXME: Error? + + return pData->cgls.computeDiffNorm(); +} + + + +bool astraCudaConeFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iDetectorSuperSampling) +{ + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SConeProjection* p = genConeProjections(iProjAngles, + iProjU, iProjV, + fOriginSourceDistance, + fOriginDetectorDistance, + fDetUSize, fDetVSize, + pfAngles); + + bool ok; + ok = astraCudaConeFP(pfVolume, pfProjections, iVolX, iVolY, iVolZ, + iProjAngles, iProjU, iProjV, p, iGPUIndex, iDetectorSuperSampling); + + delete[] p; + + return ok; +} + +bool astraCudaConeFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection *pfAngles, + int iGPUIndex, int iDetectorSuperSampling) +{ + SDimensions3D dims; + + dims.iVolX = iVolX; + dims.iVolY = iVolY; + dims.iVolZ = iVolZ; + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjU = iProjU; + dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + dims.iRaysPerDetDim = iDetectorSuperSampling; + + if (iDetectorSuperSampling == 0) + return false; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + cudaPitchedPtr D_volumeData = allocateVolumeData(dims); + bool ok = D_volumeData.ptr; + if (!ok) + return false; + + cudaPitchedPtr D_projData = allocateProjectionData(dims); + ok = D_projData.ptr; + if (!ok) { + cudaFree(D_volumeData.ptr); + return false; + } + + ok &= copyVolumeToDevice(pfVolume, D_volumeData, dims, dims.iVolX); + + ok &= zeroProjectionData(D_projData, dims); + + if (!ok) { + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + return false; + } + + ok &= ConeFP(D_volumeData, D_projData, dims, pfAngles, 1.0f); + + ok &= copyProjectionsFromDevice(pfProjections, D_projData, + dims, dims.iProjU); + + + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + + return ok; + +} + +bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iDetectorSuperSampling, + Cuda3DProjectionKernel projKernel) +{ + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SPar3DProjection* p = genPar3DProjections(iProjAngles, + iProjU, iProjV, + fDetUSize, fDetVSize, + pfAngles); + + bool ok; + ok = astraCudaPar3DFP(pfVolume, pfProjections, iVolX, iVolY, iVolZ, + iProjAngles, iProjU, iProjV, p, iGPUIndex, iDetectorSuperSampling, + projKernel); + + delete[] p; + + return ok; +} + + +bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection *pfAngles, + int iGPUIndex, int iDetectorSuperSampling, + Cuda3DProjectionKernel projKernel) +{ + SDimensions3D dims; + + dims.iVolX = iVolX; + dims.iVolY = iVolY; + dims.iVolZ = iVolZ; + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjU = iProjU; + dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + dims.iRaysPerDetDim = iDetectorSuperSampling; + + if (iDetectorSuperSampling == 0) + return false; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + + cudaPitchedPtr D_volumeData = allocateVolumeData(dims); + bool ok = D_volumeData.ptr; + if (!ok) + return false; + + cudaPitchedPtr D_projData = allocateProjectionData(dims); + ok = D_projData.ptr; + if (!ok) { + cudaFree(D_volumeData.ptr); + return false; + } + + ok &= copyVolumeToDevice(pfVolume, D_volumeData, dims, dims.iVolX); + + ok &= zeroProjectionData(D_projData, dims); + + if (!ok) { + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + return false; + } + + switch (projKernel) { + case ker3d_default: + ok &= Par3DFP(D_volumeData, D_projData, dims, pfAngles, 1.0f); + break; + case ker3d_sum_square_weights: + ok &= Par3DFP_SumSqW(D_volumeData, D_projData, dims, pfAngles, 1.0f); + break; + default: + assert(false); + } + + ok &= copyProjectionsFromDevice(pfProjections, D_projData, + dims, dims.iProjU); + + + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + + return ok; + +} + +bool astraCudaConeBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iVoxelSuperSampling) +{ + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SConeProjection* p = genConeProjections(iProjAngles, + iProjU, iProjV, + fOriginSourceDistance, + fOriginDetectorDistance, + fDetUSize, fDetVSize, + pfAngles); + + bool ok; + ok = astraCudaConeBP(pfVolume, pfProjections, iVolX, iVolY, iVolZ, + iProjAngles, iProjU, iProjV, p, iGPUIndex, iVoxelSuperSampling); + + delete[] p; + + return ok; +} + +bool astraCudaConeBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection *pfAngles, + int iGPUIndex, int iVoxelSuperSampling) +{ + SDimensions3D dims; + + dims.iVolX = iVolX; + dims.iVolY = iVolY; + dims.iVolZ = iVolZ; + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjU = iProjU; + dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + dims.iRaysPerVoxelDim = iVoxelSuperSampling; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + cudaPitchedPtr D_volumeData = allocateVolumeData(dims); + bool ok = D_volumeData.ptr; + if (!ok) + return false; + + cudaPitchedPtr D_projData = allocateProjectionData(dims); + ok = D_projData.ptr; + if (!ok) { + cudaFree(D_volumeData.ptr); + return false; + } + + ok &= copyProjectionsToDevice(pfProjections, D_projData, + dims, dims.iProjU); + + ok &= zeroVolumeData(D_volumeData, dims); + + if (!ok) { + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + return false; + } + + ok &= ConeBP(D_volumeData, D_projData, dims, pfAngles); + + ok &= copyVolumeFromDevice(pfVolume, D_volumeData, dims, dims.iVolX); + + + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + + return ok; + +} + +bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iVoxelSuperSampling) +{ + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + SPar3DProjection* p = genPar3DProjections(iProjAngles, + iProjU, iProjV, + fDetUSize, fDetVSize, + pfAngles); + + bool ok; + ok = astraCudaPar3DBP(pfVolume, pfProjections, iVolX, iVolY, iVolZ, + iProjAngles, iProjU, iProjV, p, iGPUIndex, iVoxelSuperSampling); + + delete[] p; + + return ok; +} + + +bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection *pfAngles, + int iGPUIndex, int iVoxelSuperSampling) +{ + SDimensions3D dims; + + dims.iVolX = iVolX; + dims.iVolY = iVolY; + dims.iVolZ = iVolZ; + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjU = iProjU; + dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + dims.iRaysPerVoxelDim = iVoxelSuperSampling; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + + cudaPitchedPtr D_volumeData = allocateVolumeData(dims); + bool ok = D_volumeData.ptr; + if (!ok) + return false; + + cudaPitchedPtr D_projData = allocateProjectionData(dims); + ok = D_projData.ptr; + if (!ok) { + cudaFree(D_volumeData.ptr); + return false; + } + + ok &= copyProjectionsToDevice(pfProjections, D_projData, + dims, dims.iProjU); + + ok &= zeroVolumeData(D_volumeData, dims); + + if (!ok) { + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + return false; + } + + ok &= Par3DBP(D_volumeData, D_projData, dims, pfAngles); + + ok &= copyVolumeFromDevice(pfVolume, D_volumeData, dims, dims.iVolX); + + + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + + return ok; + +} + + + +bool astraCudaFDK(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + bool bShortScan, + int iGPUIndex, int iVoxelSuperSampling) +{ + SDimensions3D dims; + + dims.iVolX = iVolX; + dims.iVolY = iVolY; + dims.iVolZ = iVolZ; + if (iVolX == 0 || iVolY == 0 || iVolZ == 0) + return false; + + dims.iProjAngles = iProjAngles; + dims.iProjU = iProjU; + dims.iProjV = iProjV; + + if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0) + return false; + + dims.iRaysPerVoxelDim = iVoxelSuperSampling; + + if (iVoxelSuperSampling == 0) + return false; + + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + + + cudaPitchedPtr D_volumeData = allocateVolumeData(dims); + bool ok = D_volumeData.ptr; + if (!ok) + return false; + + cudaPitchedPtr D_projData = allocateProjectionData(dims); + ok = D_projData.ptr; + if (!ok) { + cudaFree(D_volumeData.ptr); + return false; + } + + ok &= copyProjectionsToDevice(pfProjections, D_projData, dims, dims.iProjU); + + ok &= zeroVolumeData(D_volumeData, dims); + + if (!ok) { + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + return false; + } + + // TODO: Offer interface for SrcZ, DetZ + ok &= FDK(D_volumeData, D_projData, fOriginSourceDistance, + fOriginDetectorDistance, 0, 0, fDetUSize, fDetVSize, + dims, pfAngles, bShortScan); + + ok &= copyVolumeFromDevice(pfVolume, D_volumeData, dims, dims.iVolX); + + + cudaFree(D_volumeData.ptr); + cudaFree(D_projData.ptr); + + return ok; + +} + + + + +} diff --git a/cuda/3d/astra3d.h b/cuda/3d/astra3d.h new file mode 100644 index 0000000..5712f89 --- /dev/null +++ b/cuda/3d/astra3d.h @@ -0,0 +1,450 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_ASTRA3D_H +#define _CUDA_ASTRA3D_H + +#include "dims3d.h" + +namespace astra { + + +// TODO: Switch to a class hierarchy as with the 2D algorithms + + +enum Cuda3DProjectionKernel { + ker3d_default = 0, + ker3d_sum_square_weights +}; + + +class AstraSIRT3d_internal; + + +class _AstraExport AstraSIRT3d { +public: + + AstraSIRT3d(); + ~AstraSIRT3d(); + + // Set the number of pixels in the reconstruction rectangle, + // and the length of the edge of a pixel. + // Volume pixels are assumed to be square. + // This must be called before setting the projection geometry. + bool setReconstructionGeometry(unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ/*, + float fPixelSize = 1.0f*/); + + bool setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection* projs); + bool setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fSourceZ, + float fDetSize, + const float *pfAngles); + bool setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection* projs); + bool setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fSourceZ, + float fDetSize, + const float *pfAngles); + + // Enable supersampling. + // + // The number of rays used in FP is the square of iDetectorSuperSampling. + // The number of rays used in BP is the cube of iVoxelSuperSampling. + bool enableSuperSampling(unsigned int iVoxelSuperSampling, + unsigned int iDetectorSuperSampling); + + // Enable volume/sinogram masks + // + // This may optionally be called before init(). + // If it is called, setVolumeMask()/setSinogramMask() must be called between + // setSinogram() and iterate(). + bool enableVolumeMask(); + bool enableSinogramMask(); + + // Set GPU index + // + // This should be called before init(). Note that setting the GPU index + // in a thread which has already used the GPU may not work. + bool setGPUIndex(int index); + + // Allocate GPU buffers and + // precompute geometry-specific data. + // + // This must be called after calling setReconstructionGeometry() and + // setProjectionGeometry() or setFanProjectionGeometry(). + bool init(); + + // Setup input sinogram for a slice. + // pfSinogram must be a float array of size XXX + // NB: iSinogramPitch is measured in floats, not in bytes. + // + // This must be called after init(), and before iterate(). It may be + // called again after iterate()/getReconstruction() to start a new slice. + // + // pfSinogram will only be read from during this call. + bool setSinogram(const float* pfSinogram, unsigned int iSinogramPitch); + + // Setup volume mask for a slice. + // pfMask must be a float array of size XXX + // NB: iMaskPitch is measured in floats, not in bytes. + // + // It may only contain the exact values 0.0f and 1.0f. Only volume pixels + // for which pfMask[z] is 1.0f are processed. + bool setVolumeMask(const float* pfMask, unsigned int iMaskPitch); + + // Setup sinogram mask for a slice. + // pfMask must be a float array of size XXX + // NB: iMaskPitch is measured in floats, not in bytes. + // + // It may only contain the exact values 0.0f and 1.0f. Only sinogram pixels + // for which pfMask[z] is 1.0f are processed. + bool setSinogramMask(const float* pfMask, unsigned int iMaskPitch); + + // Set the starting reconstruction for SIRT. + // pfReconstruction must be a float array of size XXX + // NB: iReconstructionPitch is measured in floats, not in bytes. + // + // This may be called between setSinogram() and iterate(). + // If this function is not called before iterate(), SIRT will start + // from a zero reconstruction. + // + // pfReconstruction will only be read from during this call. + bool setStartReconstruction(const float* pfReconstruction, + unsigned int iReconstructionPitch); + + // Enable min/max constraint. + // + // These may optionally be called between init() and iterate() + bool setMinConstraint(float fMin); + bool setMaxConstraint(float fMax); + + // Perform a number of (additive) SIRT iterations. + // This must be called after setSinogram(). + // + // If called multiple times, without calls to setSinogram() or + // setStartReconstruction() in between, iterate() will continue from + // the result of the previous call. + // Calls to getReconstruction() are allowed between calls to iterate() and + // do not change the state. + bool iterate(unsigned int iIterations); + + // Get the reconstructed slice. + // pfReconstruction must be a float array of size XXX + // NB: iReconstructionPitch is measured in floats, not in bytes. + // + // This may be called after iterate(). + bool getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const; + + // Compute the norm of the difference of the FP of the current + // reconstruction and the sinogram. (This performs one FP.) + // It can be called after iterate(). + float computeDiffNorm(); + + // Signal the algorithm that it should abort after the current iteration. + // This is intended to be called from another thread. + void signalAbort(); + +protected: + AstraSIRT3d_internal *pData; +}; + + +class AstraCGLS3d_internal; + + +class _AstraExport AstraCGLS3d { +public: + + AstraCGLS3d(); + ~AstraCGLS3d(); + + // Set the number of pixels in the reconstruction rectangle, + // and the length of the edge of a pixel. + // Volume pixels are assumed to be square. + // This must be called before setting the projection geometry. + bool setReconstructionGeometry(unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ/*, + float fPixelSize = 1.0f*/); + + bool setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection* projs); + bool setConeGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fSourceZ, + float fDetSize, + const float *pfAngles); + bool setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection* projs); + bool setPar3DGeometry(unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fSourceZ, + float fDetSize, + const float *pfAngles); + + // Enable supersampling. + // + // The number of rays used in FP is the square of iDetectorSuperSampling. + // The number of rays used in BP is the cube of iVoxelSuperSampling. + bool enableSuperSampling(unsigned int iVoxelSuperSampling, + unsigned int iDetectorSuperSampling); + + // Enable volume/sinogram masks + // + // This may optionally be called before init(). + // If it is called, setVolumeMask()/setSinogramMask() must be called between + // setSinogram() and iterate(). + bool enableVolumeMask(); + //bool enableSinogramMask(); + + // Set GPU index + // + // This should be called before init(). Note that setting the GPU index + // in a thread which has already used the GPU may not work. + bool setGPUIndex(int index); + + // Allocate GPU buffers and + // precompute geometry-specific data. + // + // This must be called after calling setReconstructionGeometry() and + // setProjectionGeometry() or setFanProjectionGeometry(). + bool init(); + + // Setup input sinogram for a slice. + // pfSinogram must be a float array of size XXX + // NB: iSinogramPitch is measured in floats, not in bytes. + // + // This must be called after init(), and before iterate(). It may be + // called again after iterate()/getReconstruction() to start a new slice. + // + // pfSinogram will only be read from during this call. + bool setSinogram(const float* pfSinogram, unsigned int iSinogramPitch); + + // Setup volume mask for a slice. + // pfMask must be a float array of size XXX + // NB: iMaskPitch is measured in floats, not in bytes. + // + // It may only contain the exact values 0.0f and 1.0f. Only volume pixels + // for which pfMask[z] is 1.0f are processed. + bool setVolumeMask(const float* pfMask, unsigned int iMaskPitch); + + // Setup sinogram mask for a slice. + // pfMask must be a float array of size XXX + // NB: iMaskPitch is measured in floats, not in bytes. + // + // It may only contain the exact values 0.0f and 1.0f. Only sinogram pixels + // for which pfMask[z] is 1.0f are processed. + //bool setSinogramMask(const float* pfMask, unsigned int iMaskPitch); + + // Set the starting reconstruction for SIRT. + // pfReconstruction must be a float array of size XXX + // NB: iReconstructionPitch is measured in floats, not in bytes. + // + // This may be called between setSinogram() and iterate(). + // If this function is not called before iterate(), SIRT will start + // from a zero reconstruction. + // + // pfReconstruction will only be read from during this call. + bool setStartReconstruction(const float* pfReconstruction, + unsigned int iReconstructionPitch); + + // Enable min/max constraint. + // + // These may optionally be called between init() and iterate() + //bool setMinConstraint(float fMin); + //bool setMaxConstraint(float fMax); + + // Perform a number of (additive) SIRT iterations. + // This must be called after setSinogram(). + // + // If called multiple times, without calls to setSinogram() or + // setStartReconstruction() in between, iterate() will continue from + // the result of the previous call. + // Calls to getReconstruction() are allowed between calls to iterate() and + // do not change the state. + bool iterate(unsigned int iIterations); + + // Get the reconstructed slice. + // pfReconstruction must be a float array of size XXX + // NB: iReconstructionPitch is measured in floats, not in bytes. + // + // This may be called after iterate(). + bool getReconstruction(float* pfReconstruction, + unsigned int iReconstructionPitch) const; + + // Compute the norm of the difference of the FP of the current + // reconstruction and the sinogram. (This performs one FP.) + // It can be called after iterate(). + float computeDiffNorm(); + + // Signal the algorithm that it should abort after the current iteration. + // This is intended to be called from another thread. + void signalAbort(); + +protected: + AstraCGLS3d_internal *pData; +}; + + + +_AstraExport bool astraCudaConeFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iDetectorSuperSampling); + +_AstraExport bool astraCudaConeFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection *pfAngles, + int iGPUIndex, int iDetectorSuperSampling); + +_AstraExport bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iDetectorSuperSampling, + Cuda3DProjectionKernel projKernel); + +_AstraExport bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection *pfAngles, + int iGPUIndex, int iDetectorSuperSampling, + Cuda3DProjectionKernel projKernel); + + +_AstraExport bool astraCudaConeBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iVoxelSuperSampling); + +_AstraExport bool astraCudaConeBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SConeProjection *pfAngles, + int iGPUIndex, int iVoxelSuperSampling); + +_AstraExport bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + int iGPUIndex, int iVoxelSuperSampling); + +_AstraExport bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + const SPar3DProjection *pfAngles, + int iGPUIndex, int iVoxelSuperSampling); + +_AstraExport bool astraCudaFDK(float* pfVolume, const float* pfProjections, + unsigned int iVolX, + unsigned int iVolY, + unsigned int iVolZ, + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles, + bool bShortScan, + int iGPUIndex, int iVoxelSuperSampling); + +} + + +#endif diff --git a/cuda/3d/cgls3d.cu b/cuda/3d/cgls3d.cu new file mode 100644 index 0000000..72bb9cd --- /dev/null +++ b/cuda/3d/cgls3d.cu @@ -0,0 +1,428 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "cgls3d.h" +#include "util3d.h" +#include "arith3d.h" +#include "cone_fp.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +namespace astraCUDA3d { + +CGLS::CGLS() : ReconAlgo3D() +{ + D_maskData.ptr = 0; + D_smaskData.ptr = 0; + + D_sinoData.ptr = 0; + D_volumeData.ptr = 0; + + D_r.ptr = 0; + D_w.ptr = 0; + D_z.ptr = 0; + D_p.ptr = 0; + + useVolumeMask = false; + useSinogramMask = false; +} + + +CGLS::~CGLS() +{ + reset(); +} + +void CGLS::reset() +{ + cudaFree(D_r.ptr); + cudaFree(D_w.ptr); + cudaFree(D_z.ptr); + cudaFree(D_p.ptr); + + D_maskData.ptr = 0; + D_smaskData.ptr = 0; + + D_sinoData.ptr = 0; + D_volumeData.ptr = 0; + + D_r.ptr = 0; + D_w.ptr = 0; + D_z.ptr = 0; + D_p.ptr = 0; + + useVolumeMask = false; + useSinogramMask = false; + + sliceInitialized = false; + + ReconAlgo3D::reset(); +} + +bool CGLS::enableVolumeMask() +{ + useVolumeMask = true; + return true; +} + +bool CGLS::enableSinogramMask() +{ + useSinogramMask = true; + return true; +} + + +bool CGLS::init() +{ + D_z = allocateVolumeData(dims); + D_p = allocateVolumeData(dims); + D_r = allocateProjectionData(dims); + D_w = allocateProjectionData(dims); + + // TODO: check if allocations succeeded + return true; +} + +bool CGLS::setVolumeMask(cudaPitchedPtr& _D_maskData) +{ + assert(useVolumeMask); + + D_maskData = _D_maskData; + + return true; +} + +bool CGLS::setSinogramMask(cudaPitchedPtr& _D_smaskData) +{ + return false; +#if 0 + // TODO: Implement this + assert(useSinogramMask); + + D_smaskData = _D_smaskData; + return true; +#endif +} + +bool CGLS::setBuffers(cudaPitchedPtr& _D_volumeData, + cudaPitchedPtr& _D_projData) +{ + D_volumeData = _D_volumeData; + D_sinoData = _D_projData; + + fprintf(stderr, "Reconstruction buffer: %p\n", (void*)D_volumeData.ptr); + + sliceInitialized = false; + + return true; +} + +bool CGLS::iterate(unsigned int iterations) +{ + shouldAbort = false; + + if (!sliceInitialized) { + + // copy sinogram + duplicateProjectionData(D_r, D_sinoData, dims); + + // r = sino - A*x + if (useVolumeMask) { + duplicateVolumeData(D_z, D_volumeData, dims); + processVol3D<opMul>(D_z, D_maskData, dims); + callFP(D_z, D_r, -1.0f); + } else { + callFP(D_volumeData, D_r, -1.0f); + } + + // p = A'*r + zeroVolumeData(D_p, dims); + callBP(D_p, D_r); + if (useVolumeMask) + processVol3D<opMul>(D_p, D_maskData, dims); + + gamma = dotProduct3D(D_p, dims.iVolX, dims.iVolY, dims.iVolZ); + + sliceInitialized = true; + + } + + + // iteration + for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + + // w = A*p + zeroProjectionData(D_w, dims); + callFP(D_p, D_w, 1.0f); + + // alpha = gamma / <w,w> + float ww = dotProduct3D(D_w, dims.iProjU, dims.iProjAngles, dims.iProjV); + float alpha = gamma / ww; + + // x += alpha*p + processVol3D<opAddScaled>(D_volumeData, D_p, alpha, dims); + + // r -= alpha*w + processSino3D<opAddScaled>(D_r, D_w, -alpha, dims); + + // z = A'*r + zeroVolumeData(D_z, dims); + callBP(D_z, D_r); + if (useVolumeMask) + processVol3D<opMul>(D_z, D_maskData, dims); + + float beta = 1.0f / gamma; + gamma = dotProduct3D(D_z, dims.iVolX, dims.iVolY, dims.iVolZ); + + beta *= gamma; + + // p = z + beta*p + processVol3D<opScaleAndAdd>(D_p, D_z, beta, dims); + } + + return true; +} + +float CGLS::computeDiffNorm() +{ + // We can use w and z as temporary storage here since they're not + // used outside of iterations. + + // copy sinogram to w + duplicateProjectionData(D_w, D_sinoData, dims); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + duplicateVolumeData(D_z, D_volumeData, dims); + processVol3D<opMul>(D_z, D_maskData, dims); + callFP(D_z, D_w, -1.0f); + } else { + callFP(D_volumeData, D_w, -1.0f); + } + + float s = dotProduct3D(D_w, dims.iProjU, dims.iProjAngles, dims.iProjV); + return sqrt(s); +} + + +bool doCGLS(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_sinoData, + cudaPitchedPtr& D_maskData, + const SDimensions3D& dims, const SConeProjection* angles, + unsigned int iterations) +{ + CGLS cgls; + bool ok = true; + + ok &= cgls.setConeGeometry(dims, angles); + if (D_maskData.ptr) + ok &= cgls.enableVolumeMask(); + + if (!ok) + return false; + + ok = cgls.init(); + if (!ok) + return false; + + if (D_maskData.ptr) + ok &= cgls.setVolumeMask(D_maskData); + + ok &= cgls.setBuffers(D_volumeData, D_sinoData); + if (!ok) + return false; + + ok = cgls.iterate(iterations); + + return ok; +} + +} + +#ifdef STANDALONE + +using namespace astraCUDA3d; + +int main() +{ + SDimensions3D dims; + dims.iVolX = 256; + dims.iVolY = 256; + dims.iVolZ = 256; + dims.iProjAngles = 100; + dims.iProjU = 512; + dims.iProjV = 512; + dims.iRaysPerDet = 1; + + SConeProjection angle[100]; + angle[0].fSrcX = -2905.6; + angle[0].fSrcY = 0; + angle[0].fSrcZ = 0; + + angle[0].fDetSX = 694.4; + angle[0].fDetSY = -122.4704; + angle[0].fDetSZ = -122.4704; + + angle[0].fDetUX = 0; + angle[0].fDetUY = .4784; + //angle[0].fDetUY = .5; + angle[0].fDetUZ = 0; + + angle[0].fDetVX = 0; + angle[0].fDetVY = 0; + angle[0].fDetVZ = .4784; + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0) + for (int i = 1; i < 100; ++i) { + angle[i] = angle[0]; + ROTATE0(Src, i, i*2*M_PI/100); + ROTATE0(DetS, i, i*2*M_PI/100); + ROTATE0(DetU, i, i*2*M_PI/100); + ROTATE0(DetV, i, i*2*M_PI/100); + } +#undef ROTATE0 + + + cudaPitchedPtr volData = allocateVolumeData(dims); + cudaPitchedPtr projData = allocateProjectionData(dims); + zeroProjectionData(projData, dims); + + float* pbuf = new float[100*512*512]; + copyProjectionsFromDevice(pbuf, projData, dims); + copyProjectionsToDevice(pbuf, projData, dims); + delete[] pbuf; + +#if 0 + float* slice = new float[256*256]; + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = 256*sizeof(float); + ptr.xsize = 256*sizeof(float); + ptr.ysize = 256; + + for (unsigned int i = 0; i < 256; ++i) { + for (unsigned int y = 0; y < 256; ++y) + for (unsigned int x = 0; x < 256; ++x) + slice[y*256+x] = (i-127.5)*(i-127.5)+(y-127.5)*(y-127.5)+(x-127.5)*(x-127.5) < 4900 ? 1.0f : 0.0f; + + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); + } + astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f); + +#else + + for (int i = 0; i < 100; ++i) { + char fname[32]; + sprintf(fname, "Tiffs/%04d.png", 4*i); + unsigned int w,h; + float* bufp = loadImage(fname, w,h); + + for (int j = 0; j < 512*512; ++j) { + float v = bufp[j]; + if (v > 236.0f) v = 236.0f; + v = logf(236.0f / v); + bufp[j] = 256*v; + } + + for (int j = 0; j < 512; ++j) { + cudaMemcpy(((float*)projData.ptr)+100*512*j+512*i, bufp+512*j, 512*sizeof(float), cudaMemcpyHostToDevice); + } + + delete[] bufp; + + } +#endif + +#if 0 + float* bufs = new float[100*512]; + + for (int i = 0; i < 512; ++i) { + cudaMemcpy(bufs, ((float*)projData.ptr)+100*512*i, 100*512*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize); + + char fname[20]; + sprintf(fname, "sino%03d.png", i); + saveImage(fname, 100, 512, bufs); + } + + float* bufp = new float[512*512]; + + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+100*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "proj%03d.png", i); + saveImage(fname, 512, 512, bufp); + } +#endif + + zeroVolumeData(volData, dims); + + cudaPitchedPtr maskData; + maskData.ptr = 0; + + astraCUDA3d::doCGLS(volData, projData, maskData, dims, angle, 50); +#if 1 + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + char fname[20]; + sprintf(fname, "vol%03d.png", i); + saveImage(fname, 256, 256, buf); + } +#endif + + return 0; +} +#endif + diff --git a/cuda/3d/cgls3d.h b/cuda/3d/cgls3d.h new file mode 100644 index 0000000..d16b571 --- /dev/null +++ b/cuda/3d/cgls3d.h @@ -0,0 +1,114 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_CGLS3D_H +#define _CUDA_CGLS3D_H + +#include "util3d.h" +#include "algo3d.h" + +namespace astraCUDA3d { + +class _AstraExport CGLS : public ReconAlgo3D { +public: + CGLS(); + ~CGLS(); + +// bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs); + + + bool enableVolumeMask(); + bool enableSinogramMask(); + + // init should be called after setting all geometry + bool init(); + + // setVolumeMask should be called after init and before iterate, + // but only if enableVolumeMask was called before init. + // It may be called again after iterate. + bool setVolumeMask(cudaPitchedPtr& D_maskData); + + // setSinogramMask should be called after init and before iterate, + // but only if enableSinogramMask was called before init. + // It may be called again after iterate. + bool setSinogramMask(cudaPitchedPtr& D_smaskData); + + + // setBuffers should be called after init and before iterate. + // It may be called again after iterate. + bool setBuffers(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_projData); + + + // set Min/Max constraints. They may be called at any time, and will affect + // any iterate() calls afterwards. + bool setMinConstraint(float fMin) { return false; } + bool setMaxConstraint(float fMax) { return false; } + + // iterate should be called after init and setBuffers. + // It may be called multiple times. + bool iterate(unsigned int iterations); + + // Compute the norm of the difference of the FP of the current reconstruction + // and the sinogram. (This performs one FP.) + // It can be called after iterate. + float computeDiffNorm(); + +protected: + void reset(); + + bool useVolumeMask; + bool useSinogramMask; + + cudaPitchedPtr D_maskData; + cudaPitchedPtr D_smaskData; + + // Input/output + cudaPitchedPtr D_sinoData; + cudaPitchedPtr D_volumeData; + + // Temporary buffers + cudaPitchedPtr D_r; + cudaPitchedPtr D_w; + cudaPitchedPtr D_z; + cudaPitchedPtr D_p; + + float gamma; + + bool sliceInitialized; +}; + +_AstraExport bool doCGLS(cudaPitchedPtr D_volumeData, unsigned int volumePitch, + cudaPitchedPtr D_projData, unsigned int projPitch, + cudaPitchedPtr D_maskData, unsigned int maskPitch, + const SDimensions3D& dims, const SConeProjection* projs, + unsigned int iterations); + +} + +#endif diff --git a/cuda/3d/cone_bp.cu b/cuda/3d/cone_bp.cu new file mode 100644 index 0000000..7f8e320 --- /dev/null +++ b/cuda/3d/cone_bp.cu @@ -0,0 +1,481 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include <cuda.h> +#include "util3d.h" + +#ifdef STANDALONE +#include "cone_fp.h" +#include "testutil.h" +#endif + +#include "dims3d.h" + +typedef texture<float, 3, cudaReadModeElementType> texture3D; + +static texture3D gT_coneProjTexture; + +namespace astraCUDA3d { + +static const unsigned int g_volBlockZ = 16; + +static const unsigned int g_anglesPerBlock = 64; +static const unsigned int g_volBlockX = 32; +static const unsigned int g_volBlockY = 16; + +static const unsigned g_MaxAngles = 1024; + +__constant__ float gC_Cux[g_MaxAngles]; +__constant__ float gC_Cuy[g_MaxAngles]; +__constant__ float gC_Cuz[g_MaxAngles]; +__constant__ float gC_Cuc[g_MaxAngles]; +__constant__ float gC_Cvx[g_MaxAngles]; +__constant__ float gC_Cvy[g_MaxAngles]; +__constant__ float gC_Cvz[g_MaxAngles]; +__constant__ float gC_Cvc[g_MaxAngles]; +__constant__ float gC_Cdx[g_MaxAngles]; +__constant__ float gC_Cdy[g_MaxAngles]; +__constant__ float gC_Cdz[g_MaxAngles]; +__constant__ float gC_Cdc[g_MaxAngles]; + + +bool bindProjDataTexture(const cudaArray* array) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_coneProjTexture.addressMode[0] = cudaAddressModeClamp; + gT_coneProjTexture.addressMode[1] = cudaAddressModeClamp; + gT_coneProjTexture.addressMode[2] = cudaAddressModeClamp; + gT_coneProjTexture.filterMode = cudaFilterModeLinear; + gT_coneProjTexture.normalized = false; + + cudaBindTextureToArray(gT_coneProjTexture, array, channelDesc); + + // TODO: error value? + + return true; +} + + +__global__ void dev_cone_BP(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims) +{ + float* volData = (float*)D_volData; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + + // threadIdx: x = rel x + // y = rel y + + // blockIdx: x = x + y + // y = z + + + // TO TRY: precompute part of detector intersection formulas in shared mem? + // TO TRY: inner loop over z, gather ray values in shared mem + + const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x; + const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y; + + if (X >= dims.iVolX) + return; + if (Y >= dims.iVolY) + return; + + const int startZ = blockIdx.y * g_volBlockZ; + int endZ = startZ + g_volBlockZ; + if (endZ > dims.iVolZ) + endZ = dims.iVolZ; + + float fX = X - 0.5f*dims.iVolX + 0.5f; + float fY = Y - 0.5f*dims.iVolY + 0.5f; + float fZ = startZ - 0.5f*dims.iVolZ + 0.5f; + + for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f) + { + + float fVal = 0.0f; + float fAngle = startAngle + 0.5f; + + for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f) + { + + const float fCux = gC_Cux[angle]; + const float fCuy = gC_Cuy[angle]; + const float fCuz = gC_Cuz[angle]; + const float fCuc = gC_Cuc[angle]; + const float fCvx = gC_Cvx[angle]; + const float fCvy = gC_Cvy[angle]; + const float fCvz = gC_Cvz[angle]; + const float fCvc = gC_Cvc[angle]; + const float fCdx = gC_Cdx[angle]; + const float fCdy = gC_Cdy[angle]; + const float fCdz = gC_Cdz[angle]; + const float fCdc = gC_Cdc[angle]; + + const float fUNum = fCuc + fX * fCux + fY * fCuy + fZ * fCuz; + const float fVNum = fCvc + fX * fCvx + fY * fCvy + fZ * fCvz; + const float fDen = fCdc + fX * fCdx + fY * fCdy + fZ * fCdz; + + const float fU = fUNum / fDen + 1.0f; + const float fV = fVNum / fDen + 1.0f; + + fVal += tex3D(gT_coneProjTexture, fU, fAngle, fV); + + } + + volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal; + } + +} + +// supersampling version +__global__ void dev_cone_BP_SS(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims) +{ + float* volData = (float*)D_volData; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + + // threadIdx: x = rel x + // y = rel y + + // blockIdx: x = x + y + // y = z + + + // TO TRY: precompute part of detector intersection formulas in shared mem? + // TO TRY: inner loop over z, gather ray values in shared mem + + const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x; + const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y; + + if (X >= dims.iVolX) + return; + if (Y >= dims.iVolY) + return; + + const int startZ = blockIdx.y * g_volBlockZ; + int endZ = startZ + g_volBlockZ; + if (endZ > dims.iVolZ) + endZ = dims.iVolZ; + + float fX = X - 0.5f*dims.iVolX + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim; + float fY = Y - 0.5f*dims.iVolY + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim; + float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim; + const float fSubStep = 1.0f/dims.iRaysPerVoxelDim; + + for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f) + { + + float fVal = 0.0f; + float fAngle = startAngle + 0.5f; + + for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f) + { + + const float fCux = gC_Cux[angle]; + const float fCuy = gC_Cuy[angle]; + const float fCuz = gC_Cuz[angle]; + const float fCuc = gC_Cuc[angle]; + const float fCvx = gC_Cvx[angle]; + const float fCvy = gC_Cvy[angle]; + const float fCvz = gC_Cvz[angle]; + const float fCvc = gC_Cvc[angle]; + const float fCdx = gC_Cdx[angle]; + const float fCdy = gC_Cdy[angle]; + const float fCdz = gC_Cdz[angle]; + const float fCdc = gC_Cdc[angle]; + + float fXs = fX; + for (int iSubX = 0; iSubX < dims.iRaysPerVoxelDim; ++iSubX) { + float fYs = fY; + for (int iSubY = 0; iSubY < dims.iRaysPerVoxelDim; ++iSubY) { + float fZs = fZ; + for (int iSubZ = 0; iSubZ < dims.iRaysPerVoxelDim; ++iSubZ) { + + const float fUNum = fCuc + fXs * fCux + fYs * fCuy + fZs * fCuz; + const float fVNum = fCvc + fXs * fCvx + fYs * fCvy + fZs * fCvz; + const float fDen = fCdc + fXs * fCdx + fYs * fCdy + fZs * fCdz; + + const float fU = fUNum / fDen + 1.0f; + const float fV = fVNum / fDen + 1.0f; + + fVal += tex3D(gT_coneProjTexture, fU, fAngle, fV); + + fZs += fSubStep; + } + fYs += fSubStep; + } + fXs += fSubStep; + } + + } + + volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal / (dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim); + } + +} + + +bool ConeBP_Array(cudaPitchedPtr D_volumeData, + cudaArray *D_projArray, + const SDimensions3D& dims, const SConeProjection* angles) +{ + bindProjDataTexture(D_projArray); + + + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(expr,name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = (expr) ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT( (angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetVY - (angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetVZ , Cux ); + TRANSFER_TO_CONSTANT( (angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetVZ -(angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetVX , Cuy ); + TRANSFER_TO_CONSTANT( (angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetVX - (angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetVY , Cuz ); + TRANSFER_TO_CONSTANT( (angles[i].fDetSY*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVY)*angles[i].fSrcX - (angles[i].fDetSX*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVX)*angles[i].fSrcY + (angles[i].fDetSX*angles[i].fDetVY - angles[i].fDetSY*angles[i].fDetVX)*angles[i].fSrcZ , Cuc ); + + TRANSFER_TO_CONSTANT( (angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetUZ-(angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetUY, Cvx ); + TRANSFER_TO_CONSTANT( (angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetUX - (angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetUZ , Cvy ); + TRANSFER_TO_CONSTANT((angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetUY-(angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetUX , Cvz ); + TRANSFER_TO_CONSTANT( -(angles[i].fDetSY*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUY)*angles[i].fSrcX + (angles[i].fDetSX*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUX)*angles[i].fSrcY - (angles[i].fDetSX*angles[i].fDetUY - angles[i].fDetSY*angles[i].fDetUX)*angles[i].fSrcZ , Cvc ); + + TRANSFER_TO_CONSTANT( angles[i].fDetUY*angles[i].fDetVZ - angles[i].fDetUZ*angles[i].fDetVY , Cdx ); + TRANSFER_TO_CONSTANT( angles[i].fDetUZ*angles[i].fDetVX - angles[i].fDetUX*angles[i].fDetVZ , Cdy ); + TRANSFER_TO_CONSTANT( angles[i].fDetUX*angles[i].fDetVY - angles[i].fDetUY*angles[i].fDetVX , Cdz ); + TRANSFER_TO_CONSTANT( -angles[i].fSrcX * (angles[i].fDetUY*angles[i].fDetVZ - angles[i].fDetUZ*angles[i].fDetVY) - angles[i].fSrcY * (angles[i].fDetUZ*angles[i].fDetVX - angles[i].fDetUX*angles[i].fDetVZ) - angles[i].fSrcZ * (angles[i].fDetUX*angles[i].fDetVY - angles[i].fDetUY*angles[i].fDetVX) , Cdc ); + +#undef TRANSFER_TO_CONSTANT + + delete[] tmp; + + dim3 dimBlock(g_volBlockX, g_volBlockY); + + dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ); + + // timeval t; + // tic(t); + + for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) { + // printf("Calling BP: %d, %dx%d, %dx%d to %p\n", i, dimBlock.x, dimBlock.y, dimGrid.x, dimGrid.y, (void*)D_volumeData.ptr); + if (dims.iRaysPerVoxelDim == 1) + dev_cone_BP<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims); + else + dev_cone_BP_SS<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims); + } + + cudaTextForceKernelsCompletion(); + + // printf("%f\n", toc(t)); + + return true; +} + +bool ConeBP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SConeProjection* angles) +{ + // transfer projections to array + + cudaArray* cuArray = allocateProjectionArray(dims); + transferProjectionsToArray(D_projData, cuArray, dims); + + bool ret = ConeBP_Array(D_volumeData, cuArray, dims, angles); + + cudaFreeArray(cuArray); + + return ret; +} + + +} + +#ifdef STANDALONE +int main() +{ + SDimensions3D dims; + dims.iVolX = 256; + dims.iVolY = 256; + dims.iVolZ = 256; + dims.iProjAngles = 180; + dims.iProjU = 512; + dims.iProjV = 512; + dims.iRaysPerDet = 1; + + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPitchedPtr volData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&volData, extentV); + + cudaExtent extentP; + extentP.width = dims.iProjU*sizeof(float); + extentP.height = dims.iProjAngles; + extentP.depth = dims.iProjV; + + cudaPitchedPtr projData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&projData, extentP); + cudaMemset3D(projData, 0, extentP); + + float* slice = new float[256*256]; + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = 256*sizeof(float); + ptr.xsize = 256*sizeof(float); + ptr.ysize = 256; + + for (unsigned int i = 0; i < 256*256; ++i) + slice[i] = 1.0f; + for (unsigned int i = 0; i < 256; ++i) { + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); +#if 0 + if (i == 128) { + for (unsigned int j = 0; j < 256*256; ++j) + slice[j] = 0.0f; + } +#endif + } + + + SConeProjection angle[180]; + angle[0].fSrcX = -1536; + angle[0].fSrcY = 0; + angle[0].fSrcZ = 0; + + angle[0].fDetSX = 512; + angle[0].fDetSY = -256; + angle[0].fDetSZ = -256; + + angle[0].fDetUX = 0; + angle[0].fDetUY = 1; + angle[0].fDetUZ = 0; + + angle[0].fDetVX = 0; + angle[0].fDetVY = 0; + angle[0].fDetVZ = 1; + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0) + for (int i = 1; i < 180; ++i) { + angle[i] = angle[0]; + ROTATE0(Src, i, i*2*M_PI/180); + ROTATE0(DetS, i, i*2*M_PI/180); + ROTATE0(DetU, i, i*2*M_PI/180); + ROTATE0(DetV, i, i*2*M_PI/180); + } +#undef ROTATE0 + + astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f); +#if 0 + float* bufs = new float[180*512]; + + for (int i = 0; i < 512; ++i) { + cudaMemcpy(bufs, ((float*)projData.ptr)+180*512*i, 180*512*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize); + + char fname[20]; + sprintf(fname, "sino%03d.png", i); + saveImage(fname, 180, 512, bufs); + } + + float* bufp = new float[512*512]; + + for (int i = 0; i < 180; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "proj%03d.png", i); + saveImage(fname, 512, 512, bufp); + } +#endif + for (unsigned int i = 0; i < 256*256; ++i) + slice[i] = 0.0f; + for (unsigned int i = 0; i < 256; ++i) { + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); + } + + astraCUDA3d::ConeBP(volData, projData, dims, angle); +#if 0 + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", volData.pitch, volData.xsize, volData.ysize); + + char fname[20]; + sprintf(fname, "vol%03d.png", i); + saveImage(fname, 256, 256, buf); + } +#endif + +} +#endif diff --git a/cuda/3d/cone_bp.h b/cuda/3d/cone_bp.h new file mode 100644 index 0000000..c77714e --- /dev/null +++ b/cuda/3d/cone_bp.h @@ -0,0 +1,45 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_CONE_BP_H +#define _CUDA_CONE_BP_H + +namespace astraCUDA3d { + +_AstraExport bool ConeBP_Array(cudaPitchedPtr D_volumeData, + cudaArray *D_projArray, + const SDimensions3D& dims, const SConeProjection* angles); + +_AstraExport bool ConeBP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SConeProjection* angles); + + +} + +#endif diff --git a/cuda/3d/cone_fp.cu b/cuda/3d/cone_fp.cu new file mode 100644 index 0000000..40dca4f --- /dev/null +++ b/cuda/3d/cone_fp.cu @@ -0,0 +1,513 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include <cuda.h> +#include "util3d.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +#include "dims3d.h" + +typedef texture<float, 3, cudaReadModeElementType> texture3D; + +static texture3D gT_coneVolumeTexture; + +namespace astraCUDA3d { + +static const unsigned int g_anglesPerBlock = 4; + +// thickness of the slices we're splitting the volume up into +static const unsigned int g_blockSlices = 64; +static const unsigned int g_detBlockU = 32; +static const unsigned int g_detBlockV = 32; + +static const unsigned g_MaxAngles = 1024; +__constant__ float gC_SrcX[g_MaxAngles]; +__constant__ float gC_SrcY[g_MaxAngles]; +__constant__ float gC_SrcZ[g_MaxAngles]; +__constant__ float gC_DetSX[g_MaxAngles]; +__constant__ float gC_DetSY[g_MaxAngles]; +__constant__ float gC_DetSZ[g_MaxAngles]; +__constant__ float gC_DetUX[g_MaxAngles]; +__constant__ float gC_DetUY[g_MaxAngles]; +__constant__ float gC_DetUZ[g_MaxAngles]; +__constant__ float gC_DetVX[g_MaxAngles]; +__constant__ float gC_DetVY[g_MaxAngles]; +__constant__ float gC_DetVZ[g_MaxAngles]; + + +bool bindVolumeDataTexture(const cudaArray* array) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_coneVolumeTexture.addressMode[0] = cudaAddressModeClamp; + gT_coneVolumeTexture.addressMode[1] = cudaAddressModeClamp; + gT_coneVolumeTexture.addressMode[2] = cudaAddressModeClamp; + gT_coneVolumeTexture.filterMode = cudaFilterModeLinear; + gT_coneVolumeTexture.normalized = false; + + cudaBindTextureToArray(gT_coneVolumeTexture, array, channelDesc); + + // TODO: error value? + + return true; +} + + // threadIdx: x = ??? detector (u?) + // y = relative angle + + // blockIdx: x = ??? detector (u+v?) + // y = angle block + + +#define CONE_FP_BODY(c0,c1,c2) \ + int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \ + if (angle >= endAngle) \ + return; \ + \ + const float fSrcX = gC_SrcX[angle]; \ + const float fSrcY = gC_SrcY[angle]; \ + const float fSrcZ = gC_SrcZ[angle]; \ + const float fDetUX = gC_DetUX[angle]; \ + const float fDetUY = gC_DetUY[angle]; \ + const float fDetUZ = gC_DetUZ[angle]; \ + const float fDetVX = gC_DetVX[angle]; \ + const float fDetVY = gC_DetVY[angle]; \ + const float fDetVZ = gC_DetVZ[angle]; \ + const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \ + const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \ + const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \ + \ + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \ + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \ + int endDetectorV = startDetectorV + g_detBlockV; \ + if (endDetectorV > dims.iProjV) \ + endDetectorV = dims.iProjV; \ + \ + int endSlice = startSlice + g_blockSlices; \ + if (endSlice > dims.iVol##c0) \ + endSlice = dims.iVol##c0; \ + \ + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \ + { \ + /* Trace ray from Src to (detectorU,detectorV) from */ \ + /* X = startSlice to X = endSlice */ \ + \ + const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX; \ + const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY; \ + const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ; \ + \ + /* (x) ( 1) ( 0) */ \ + /* ray: (y) = (ay) * x + (by) */ \ + /* (z) (az) (bz) */ \ + \ + const float a##c1 = (fSrc##c1 - fDet##c1) / (fSrc##c0 - fDet##c0); \ + const float a##c2 = (fSrc##c2 - fDet##c2) / (fSrc##c0 - fDet##c0); \ + const float b##c1 = fSrc##c1 - a##c1 * fSrc##c0; \ + const float b##c2 = fSrc##c2 - a##c2 * fSrc##c0; \ + \ + const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \ + \ + float fVal = 0.0f; \ + \ + float f##c0 = startSlice + 1.5f; \ + float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f; \ + float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f; \ + \ + for (int s = startSlice; s < endSlice; ++s) \ + { \ + fVal += tex3D(gT_coneVolumeTexture, fX, fY, fZ); \ + f##c0 += 1.0f; \ + f##c1 += a##c1; \ + f##c2 += a##c2; \ + } \ + \ + fVal *= fDistCorr; \ + \ + D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal; \ + } + +#define CONE_FP_SS_BODY(c0,c1,c2) \ + int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \ + if (angle >= endAngle) \ + return; \ + \ + const float fSrcX = gC_SrcX[angle]; \ + const float fSrcY = gC_SrcY[angle]; \ + const float fSrcZ = gC_SrcZ[angle]; \ + const float fDetUX = gC_DetUX[angle]; \ + const float fDetUY = gC_DetUY[angle]; \ + const float fDetUZ = gC_DetUZ[angle]; \ + const float fDetVX = gC_DetVX[angle]; \ + const float fDetVY = gC_DetVY[angle]; \ + const float fDetVZ = gC_DetVZ[angle]; \ + const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \ + const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \ + const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \ + \ + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \ + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \ + int endDetectorV = startDetectorV + g_detBlockV; \ + if (endDetectorV > dims.iProjV) \ + endDetectorV = dims.iProjV; \ + \ + int endSlice = startSlice + g_blockSlices; \ + if (endSlice > dims.iVolX) \ + endSlice = dims.iVolX; \ + \ + const float fSubStep = 1.0f/dims.iRaysPerDetDim; \ + \ + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \ + { \ + /* Trace ray from Src to (detectorU,detectorV) from */ \ + /* X = startSlice to X = endSlice */ \ + \ + float fV = 0.0f; \ + \ + float fdU = detectorU - 0.5f + 0.5f*fSubStep; \ + for (int iSubU = 0; iSubU < dims.iRaysPerDetDim; ++iSubU, fdU+=fSubStep) { \ + float fdV = detectorV - 0.5f + 0.5f*fSubStep; \ + for (int iSubV = 0; iSubV < dims.iRaysPerDetDim; ++iSubV, fdV+=fSubStep) { \ + \ + const float fDetX = fDetSX + fdU*fDetUX + fdV*fDetVX; \ + const float fDetY = fDetSY + fdU*fDetUY + fdV*fDetVY; \ + const float fDetZ = fDetSZ + fdU*fDetUZ + fdV*fDetVZ; \ + \ + /* (x) ( 1) ( 0) */ \ + /* ray: (y) = (ay) * x + (by) */ \ + /* (z) (az) (bz) */ \ + \ + const float a##c1 = (fSrc##c1 - fDet##c1) / (fSrc##c0 - fDet##c0); \ + const float a##c2 = (fSrc##c2 - fDet##c2) / (fSrc##c0 - fDet##c0); \ + const float b##c1 = fSrc##c1 - a##c1 * fSrc##c0; \ + const float b##c2 = fSrc##c2 - a##c2 * fSrc##c0; \ + \ + const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \ + \ + float fVal = 0.0f; \ + \ + float f##c0 = startSlice + 1.5f; \ + float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f; \ + float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f; \ + \ + for (int s = startSlice; s < endSlice; ++s) \ + { \ + fVal += tex3D(gT_coneVolumeTexture, fX, fY, fZ); \ + f##c0 += 1.0f; \ + f##c1 += a##c1; \ + f##c2 += a##c2; \ + } \ + \ + fVal *= fDistCorr; \ + fV += fVal; \ + \ + } \ + } \ + \ + D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fV / (dims.iRaysPerDetDim * dims.iRaysPerDetDim);\ + } + + + + + +__global__ void FP_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +CONE_FP_BODY(X,Y,Z) +} + +__global__ void FP_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +CONE_FP_BODY(Y,X,Z) +} + +__global__ void FP_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +CONE_FP_BODY(Z,X,Y) +} + + +__global__ void FP_SS_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +CONE_FP_SS_BODY(X,Y,Z) +} + +__global__ void FP_SS_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +CONE_FP_SS_BODY(Y,X,Z) +} + +__global__ void FP_SS_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +CONE_FP_SS_BODY(Z,X,Y) +} + + + +bool ConeFP_Array(cudaArray *D_volArray, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SConeProjection* angles, + float fOutputScale) +{ + bindVolumeDataTexture(D_volArray); + + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT(SrcX); + TRANSFER_TO_CONSTANT(SrcY); + TRANSFER_TO_CONSTANT(SrcZ); + TRANSFER_TO_CONSTANT(DetSX); + TRANSFER_TO_CONSTANT(DetSY); + TRANSFER_TO_CONSTANT(DetSZ); + TRANSFER_TO_CONSTANT(DetUX); + TRANSFER_TO_CONSTANT(DetUY); + TRANSFER_TO_CONSTANT(DetUZ); + TRANSFER_TO_CONSTANT(DetVX); + TRANSFER_TO_CONSTANT(DetVY); + TRANSFER_TO_CONSTANT(DetVZ); + +#undef TRANSFER_TO_CONSTANT + + delete[] tmp; + + std::list<cudaStream_t> streams; + dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles + + // Run over all angles, grouping them into groups of the same + // orientation (roughly horizontal vs. roughly vertical). + // Start a stream of grids for each such group. + + unsigned int blockStart = 0; + unsigned int blockEnd = 0; + int blockDirection = 0; + + // timeval t; + // tic(t); + + for (unsigned int a = 0; a <= dims.iProjAngles; ++a) { + int dir; + if (a != dims.iProjAngles) { + float dX = fabsf(angles[a].fSrcX - (angles[a].fDetSX + dims.iProjU*angles[a].fDetUX*0.5f + dims.iProjV*angles[a].fDetVX*0.5f)); + float dY = fabsf(angles[a].fSrcY - (angles[a].fDetSY + dims.iProjU*angles[a].fDetUY*0.5f + dims.iProjV*angles[a].fDetVY*0.5f)); + float dZ = fabsf(angles[a].fSrcZ - (angles[a].fDetSZ + dims.iProjU*angles[a].fDetUZ*0.5f + dims.iProjV*angles[a].fDetVZ*0.5f)); + + if (dX >= dY && dX >= dZ) + dir = 0; + else if (dY >= dX && dY >= dZ) + dir = 1; + else + dir = 2; + } + + if (a == dims.iProjAngles || dir != blockDirection) { + // block done + + blockEnd = a; + if (blockStart != blockEnd) { + + dim3 dimGrid( + ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV), +(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock); + // TODO: check if we can't immediately + // destroy the stream after use + cudaStream_t stream; + cudaStreamCreate(&stream); + streams.push_back(stream); + + // printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y); + + if (blockDirection == 0) { + for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + FP_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else + FP_SS_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + } else if (blockDirection == 1) { + for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + FP_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else + FP_SS_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + } else if (blockDirection == 2) { + for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + FP_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else + FP_SS_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + } + + } + + blockDirection = dir; + blockStart = a; + } + } + + for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter) + cudaStreamDestroy(*iter); + + streams.clear(); + + cudaTextForceKernelsCompletion(); + + // printf("%f\n", toc(t)); + + return true; +} + +bool ConeFP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SConeProjection* angles, + float fOutputScale) +{ + // transfer volume to array + + cudaArray* cuArray = allocateVolumeArray(dims); + transferVolumeToArray(D_volumeData, cuArray, dims); + + bool ret = ConeFP_Array(cuArray, D_projData, dims, angles, fOutputScale); + + cudaFreeArray(cuArray); + + return ret; +} + + +} + +#ifdef STANDALONE +int main() +{ + SDimensions3D dims; + dims.iVolX = 256; + dims.iVolY = 256; + dims.iVolZ = 256; + dims.iProjAngles = 32; + dims.iProjU = 512; + dims.iProjV = 512; + dims.iRaysPerDet = 1; + + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPitchedPtr volData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&volData, extentV); + + cudaExtent extentP; + extentP.width = dims.iProjU*sizeof(float); + extentP.height = dims.iProjV; + extentP.depth = dims.iProjAngles; + + cudaPitchedPtr projData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&projData, extentP); + cudaMemset3D(projData, 0, extentP); + + float* slice = new float[256*256]; + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = 256*sizeof(float); + ptr.xsize = 256*sizeof(float); + ptr.ysize = 256; + + for (unsigned int i = 0; i < 256*256; ++i) + slice[i] = 1.0f; + for (unsigned int i = 0; i < 256; ++i) { + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaError err = cudaMemcpy3D(&p); + assert(!err); + } + + + SConeProjection angle[32]; + angle[0].fSrcX = -1536; + angle[0].fSrcY = 0; + angle[0].fSrcZ = 200; + + angle[0].fDetSX = 512; + angle[0].fDetSY = -256; + angle[0].fDetSZ = -256; + + angle[0].fDetUX = 0; + angle[0].fDetUY = 1; + angle[0].fDetUZ = 0; + + angle[0].fDetVX = 0; + angle[0].fDetVY = 0; + angle[0].fDetVZ = 1; + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0) + for (int i = 1; i < 32; ++i) { + angle[i] = angle[0]; + ROTATE0(Src, i, i*1*M_PI/180); + ROTATE0(DetS, i, i*1*M_PI/180); + ROTATE0(DetU, i, i*1*M_PI/180); + ROTATE0(DetV, i, i*1*M_PI/180); + } +#undef ROTATE0 + + astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f); + + float* buf = new float[512*512]; + + cudaMemcpy(buf, ((float*)projData.ptr)+512*512*8, 512*512*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize); + + saveImage("proj.png", 512, 512, buf); + + +} +#endif diff --git a/cuda/3d/cone_fp.h b/cuda/3d/cone_fp.h new file mode 100644 index 0000000..2a0463b --- /dev/null +++ b/cuda/3d/cone_fp.h @@ -0,0 +1,46 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_CONE_FP_H +#define _CUDA_CONE_FP_H + +namespace astraCUDA3d { + +_AstraExport bool ConeFP_Array(cudaArray *D_volArray, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SConeProjection* angles, + float fOutputScale); + +_AstraExport bool ConeFP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SConeProjection* angles, + float fOutputScale); + +} + +#endif diff --git a/cuda/3d/darthelper3d.cu b/cuda/3d/darthelper3d.cu new file mode 100644 index 0000000..68330a1 --- /dev/null +++ b/cuda/3d/darthelper3d.cu @@ -0,0 +1,229 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "util3d.h" +#include "dims3d.h" +#include "darthelper3d.h" +#include <cassert> + +namespace astraCUDA3d { + + + // ------------------------------------------------------------------------------------------------------------------------------------------------------------------- + __global__ void devDartSmoothing(cudaPitchedPtr out, cudaPitchedPtr in, float b, SDimensions3D dims) + { + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > 0 && x < dims.iVolX - 1 && y > 0 && y < dims.iVolY - 1) { + + float* d = (float*)in.ptr; + float* m = (float*)out.ptr; + + unsigned int index; + unsigned int p = (out.pitch >> 2); + + for (unsigned int z = 0; z <= dims.iVolZ-1; z++) { + + float res = 0.0f; + + // bottom slice + if (z > 0) { + index = ((z-1)*dims.iVolY + y) * p + x; + res += d[index-p-1] + d[index-p] + d[index-p+1] + + d[index -1] + d[index ] + d[index +1] + + d[index+p-1] + d[index+p] + d[index+p+1]; + } + + // top slice + if (z < dims.iVolZ-1) { + index = ((z+1)*dims.iVolY + y) * p + x; + res += d[index-p-1] + d[index-p] + d[index-p+1] + + d[index -1] + d[index ] + d[index +1] + + d[index+p-1] + d[index+p] + d[index+p+1]; + } + + // same slice + index = (z*dims.iVolY + y) * p + x; + res += d[index-p-1] + d[index-p] + d[index-p+1] + + d[index -1] + d[index +1] + + d[index+p-1] + d[index+p] + d[index+p+1]; + + // result + m[index] = (1.0f-b) * d[index] + b * 0.038461538f * res; + + } + + } + } + + // ------------------------------------------------------------------------------------------------------------------------------------------------------------------- + void dartSmoothing(float* out, const float* in, float b, unsigned int radius, SDimensions3D dims) + { + cudaPitchedPtr D_inData; + D_inData = allocateVolumeData(dims); + copyVolumeToDevice(in, D_inData, dims); + + cudaPitchedPtr D_outData; + D_outData = allocateVolumeData(dims); + copyVolumeToDevice(out, D_outData, dims); + + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+15)/16); + + devDartSmoothing<<<gridSize, blockSize>>>(D_outData, D_inData, b, dims); + + copyVolumeFromDevice(out, D_outData, dims); + + cudaFree(D_outData.ptr); + cudaFree(D_inData.ptr); + + } + + + // ------------------------------------------------------------------------------------------------------------------------------------------------------------------- + // CUDA function for the masking of DART with a radius == 1 + __global__ void devDartMasking(cudaPitchedPtr mask, cudaPitchedPtr in, unsigned int conn, SDimensions3D dims) + { + unsigned int x = threadIdx.x + 16*blockIdx.x; + unsigned int y = threadIdx.y + 16*blockIdx.y; + + // Sacrifice the border pixels to simplify the implementation. + if (x > 0 && x < dims.iVolX - 1 && y > 0 && y < dims.iVolY - 1) { + + float* d = (float*)in.ptr; + float* m = (float*)mask.ptr; + + unsigned int index; + unsigned int p = (in.pitch >> 2); + + for (unsigned int z = 0; z <= dims.iVolZ-1; z++) { + + unsigned int o2 = (z*dims.iVolY + y) * p + x; + + m[o2] = 0.0f; + + // bottom slice + if (z > 0) { + index = ((z-1)*dims.iVolY + y) * p + x; + if ((conn == 26 && + (d[index-p-1] != d[o2] || d[index-p] != d[o2] || d[index-p+1] != d[o2] || + d[index -1] != d[o2] || d[index ] != d[o2] || d[index +1] != d[o2] || + d[index+p-1] != d[o2] || d[index+p] != d[o2] || d[index+p+1] != d[o2] )) + || + (conn == 6 && d[index] != d[o2])) + { + m[o2] = 1.0f; + continue; + } + } + + // top slice + if (z < dims.iVolZ-1) { + index = ((z+1)*dims.iVolY + y) * p + x; + if ((conn == 26 && + (d[index-p-1] != d[o2] || d[index-p] != d[o2] || d[index-p+1] != d[o2] || + d[index -1] != d[o2] || d[index ] != d[o2] || d[index +1] != d[o2] || + d[index+p-1] != d[o2] || d[index+p] != d[o2] || d[index+p+1] != d[o2] )) + || + (conn == 6 && d[index] != d[o2])) + { + m[o2] = 1.0f; + continue; + } + } + + // other slices + index = (z*dims.iVolY + y) * p + x; + if ((conn == 26 && + (d[index-p-1] != d[o2] || d[index-p] != d[o2] || d[index-p+1] != d[o2] || + d[index -1] != d[o2] || d[index +1] != d[o2] || + d[index+p-1] != d[o2] || d[index+p] != d[o2] || d[index+p+1] != d[o2] )) + || + (conn == 6 && + ( d[index-p] != d[o2] || + d[index -1] != d[o2] || d[index +1] != d[o2] || + d[index+p] != d[o2] ))) + { + m[o2] = 1.0f; + continue; + } + + } + + } + } + + + + // ------------------------------------------------------------------------------------------------------------------------------------------------------------------- + void dartMasking(float* mask, const float* segmentation, unsigned int conn, unsigned int radius, unsigned int threshold, SDimensions3D dims) + { + cudaPitchedPtr D_maskData; + D_maskData = allocateVolumeData(dims); + copyVolumeToDevice(mask, D_maskData, dims); + + cudaPitchedPtr D_segmentationData; + D_segmentationData = allocateVolumeData(dims); + copyVolumeToDevice(segmentation, D_segmentationData, dims); + + dim3 blockSize(16,16); + dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+15)/16); + + if (threshold == 1 && radius == 1) + devDartMasking<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, dims); + //else if (threshold > 1 && radius == 1) + // devADartMask<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, threshold, pitch, width, height, 1, 1); + //else if (threshold == 1 && radius > 1) + // devDartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, pitch, width, height, 1, 1); + //else + // devADartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, threshold, pitch, width, height, 1, 1); + + copyVolumeFromDevice(mask, D_maskData, dims); + + cudaFree(D_maskData.ptr); + cudaFree(D_segmentationData.ptr); + + } + // ------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + bool setGPUIndex(int iGPUIndex) + { + cudaSetDevice(iGPUIndex); + cudaError_t err = cudaGetLastError(); + + // Ignore errors caused by calling cudaSetDevice multiple times + if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess) + return false; + + return true; + } + + +} diff --git a/cuda/3d/darthelper3d.h b/cuda/3d/darthelper3d.h new file mode 100644 index 0000000..7899629 --- /dev/null +++ b/cuda/3d/darthelper3d.h @@ -0,0 +1,46 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_DARTHELPER3_H +#define _CUDA_DARTHELPER3_H + +#include <cuda.h> +#include <driver_types.h> +#include "util3d.h" +#include "algo3d.h" + +namespace astraCUDA3d { + + void dartSmoothing(float* out, const float* in, float b, unsigned int radius, SDimensions3D dims); + void dartMasking(float* out, const float* in, unsigned int conn, unsigned int radius, unsigned int threshold, SDimensions3D dims); + + bool setGPUIndex(int index); + +} + +#endif diff --git a/cuda/3d/dims3d.h b/cuda/3d/dims3d.h new file mode 100644 index 0000000..ec3c4a3 --- /dev/null +++ b/cuda/3d/dims3d.h @@ -0,0 +1,84 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_CONE_DIMS_H +#define _CUDA_CONE_DIMS_H + +namespace astra { + +struct SConeProjection { + // the source + double fSrcX, fSrcY, fSrcZ; + + // the origin ("bottom left") of the (flat-panel) detector + double fDetSX, fDetSY, fDetSZ; + + // the U-edge of a detector pixel + double fDetUX, fDetUY, fDetUZ; + + // the V-edge of a detector pixel + double fDetVX, fDetVY, fDetVZ; +}; + +struct SPar3DProjection { + // the ray direction + double fRayX, fRayY, fRayZ; + + // the origin ("bottom left") of the (flat-panel) detector + double fDetSX, fDetSY, fDetSZ; + + // the U-edge of a detector pixel + double fDetUX, fDetUY, fDetUZ; + + // the V-edge of a detector pixel + double fDetVX, fDetVY, fDetVZ; +}; + +} + + +namespace astraCUDA3d { + +using astra::SConeProjection; +using astra::SPar3DProjection; + +struct SDimensions3D { + unsigned int iVolX; + unsigned int iVolY; + unsigned int iVolZ; + unsigned int iProjAngles; + unsigned int iProjU; // number of detectors in the U direction + unsigned int iProjV; // number of detectors in the V direction + unsigned int iRaysPerDetDim; + unsigned int iRaysPerVoxelDim; +}; + +} + +#endif + diff --git a/cuda/3d/fdk.cu b/cuda/3d/fdk.cu new file mode 100644 index 0000000..ad0604c --- /dev/null +++ b/cuda/3d/fdk.cu @@ -0,0 +1,646 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include <cuda.h> +#include "util3d.h" + +#ifdef STANDALONE +#include "cone_fp.h" +#include "testutil.h" +#endif + +#include "dims3d.h" +#include "../2d/fft.h" + +typedef texture<float, 3, cudaReadModeElementType> texture3D; + +static texture3D gT_coneProjTexture; + +namespace astraCUDA3d { + +static const unsigned int g_volBlockZ = 16; + +static const unsigned int g_anglesPerBlock = 64; +static const unsigned int g_volBlockX = 32; +static const unsigned int g_volBlockY = 16; + +static const unsigned int g_anglesPerWeightBlock = 16; +static const unsigned int g_detBlockU = 32; +static const unsigned int g_detBlockV = 32; + +static const unsigned g_MaxAngles = 2048; + +__constant__ float gC_angle_sin[g_MaxAngles]; +__constant__ float gC_angle_cos[g_MaxAngles]; +__constant__ float gC_angle[g_MaxAngles]; + + +// per-detector u/v shifts? + +static bool bindProjDataTexture(const cudaArray* array) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_coneProjTexture.addressMode[0] = cudaAddressModeClamp; + gT_coneProjTexture.addressMode[1] = cudaAddressModeClamp; + gT_coneProjTexture.addressMode[2] = cudaAddressModeClamp; + gT_coneProjTexture.filterMode = cudaFilterModeLinear; + gT_coneProjTexture.normalized = false; + + cudaBindTextureToArray(gT_coneProjTexture, array, channelDesc); + + // TODO: error value? + + return true; +} + + +__global__ void devBP_FDK(void* D_volData, unsigned int volPitch, int startAngle, float fSrcOrigin, float fDetOrigin, float fSrcZ, float fDetZ, float fInvDetUSize, float fInvDetVSize, const SDimensions3D dims) +{ + float* volData = (float*)D_volData; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + + // threadIdx: x = rel x + // y = rel y + + // blockIdx: x = x + y + // y = z + + + // TO TRY: precompute part of detector intersection formulas in shared mem? + // TO TRY: inner loop over z, gather ray values in shared mem + + const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x; + const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y; + + if (X > dims.iVolX) + return; + if (Y > dims.iVolY) + return; + + const int startZ = blockIdx.y * g_volBlockZ; + int endZ = startZ + g_volBlockZ; + if (endZ > dims.iVolZ) + endZ = dims.iVolZ; + + float fX = X - 0.5f*dims.iVolX + 0.5f; + float fY = Y - 0.5f*dims.iVolY + 0.5f; + float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - fSrcZ; + + const float fU_base = 0.5f*dims.iProjU - 0.5f + 1.5f; + const float fV_base = 0.5f*dims.iProjV - 0.5f + 1.5f + (fDetZ-fSrcZ); + + // Note re. fZ/rV_base: the computations below are all relative to the + // optical axis, so we do the Z-adjustments beforehand. + + for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f) + { + + float fVal = 0.0f; + float fAngle = startAngle + 0.5f; + + for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f) + { + + const float cos_theta = gC_angle_cos[angle]; + const float sin_theta = gC_angle_sin[angle]; + + const float fR = fSrcOrigin; + const float fD = fR - fX * sin_theta + fY * cos_theta; + float fWeight = fR / fD; + fWeight *= fWeight; + + const float fScaleFactor = (fR + fDetOrigin) / fD; + const float fU = fU_base + (fX*cos_theta+fY*sin_theta) * fScaleFactor * fInvDetUSize; + const float fV = fV_base + fZ * fScaleFactor * fInvDetVSize; + + fVal += tex3D(gT_coneProjTexture, fU, fAngle, fV); + + } + + volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal; +// projData[(angle*dims.iProjV+detectorV)*projPitch+detectorU] = 10.0f; +// if (threadIdx.x == 0 && threadIdx.y == 0) { printf("%d,%d,%d [%d / %d] -> %f\n", angle, detectorU, detectorV, (angle*dims.iProjV+detectorV)*projPitch+detectorU, projPitch, projData[(angle*dims.iProjV+detectorV)*projPitch+detectorU]); } + } + +} + + +bool FDK_BP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + float fSrcOrigin, float fDetOrigin, + float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize, + const SDimensions3D& dims, const float* angles) +{ + // transfer projections to array + + cudaArray* cuArray = allocateProjectionArray(dims); + transferProjectionsToArray(D_projData, cuArray, dims); + + bindProjDataTexture(cuArray); + + float* angle_sin = new float[dims.iProjAngles]; + float* angle_cos = new float[dims.iProjAngles]; + + for (unsigned int i = 0; i < dims.iProjAngles; ++i) { + angle_sin[i] = sinf(angles[i]); + angle_cos[i] = cosf(angles[i]); + } + cudaError_t e1 = cudaMemcpyToSymbol(gC_angle_sin, angle_sin, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + cudaError_t e2 = cudaMemcpyToSymbol(gC_angle_cos, angle_cos, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); + assert(e1 == cudaSuccess); + assert(e2 == cudaSuccess); + + delete[] angle_sin; + delete[] angle_cos; + + dim3 dimBlock(g_volBlockX, g_volBlockY); + + dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ); + + // timeval t; + // tic(t); + + for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) { + devBP_FDK<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, 1.0f / fDetUSize, 1.0f / fDetVSize, dims); + } + + cudaTextForceKernelsCompletion(); + + cudaFreeArray(cuArray); + + // printf("%f\n", toc(t)); + + return true; +} + +__global__ void devFDK_preweight(void* D_projData, unsigned int projPitch, unsigned int startAngle, unsigned int endAngle, float fSrcOrigin, float fDetOrigin, float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize, const SDimensions3D dims) +{ + float* projData = (float*)D_projData; + int angle = startAngle + blockIdx.y * g_anglesPerWeightBlock + threadIdx.y; + if (angle >= endAngle) + return; + + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; + int endDetectorV = startDetectorV + g_detBlockV; + if (endDetectorV > dims.iProjV) + endDetectorV = dims.iProjV; + + // We need the length of the central ray and the length of the ray(s) to + // our detector pixel(s). + + const float fCentralRayLength = fSrcOrigin + fDetOrigin; + + const float fU = (detectorU - 0.5f*dims.iProjU + 0.5f) * fDetUSize; + + const float fT = fCentralRayLength * fCentralRayLength + fU * fU; + + float fV = (startDetectorV - 0.5f*dims.iProjV + 0.5f) * fDetVSize + fDetZ - fSrcZ; + + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) + { + const float fRayLength = sqrtf(fT + fV * fV); + + const float fWeight = fCentralRayLength / fRayLength; + + projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] *= fWeight; + + fV += 1.0f; + } +} + +__global__ void devFDK_ParkerWeight(void* D_projData, unsigned int projPitch, unsigned int startAngle, unsigned int endAngle, float fSrcOrigin, float fDetOrigin, float fSrcZ, float fDetZ, float fDetUSize, float fCentralFanAngle, const SDimensions3D dims) +{ + float* projData = (float*)D_projData; + int angle = startAngle + blockIdx.y * g_anglesPerWeightBlock + threadIdx.y; + if (angle >= endAngle) + return; + + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; + int endDetectorV = startDetectorV + g_detBlockV; + if (endDetectorV > dims.iProjV) + endDetectorV = dims.iProjV; + + // We need the length of the central ray and the length of the projection + // of our ray onto the central slice + + const float fCentralRayLength = fSrcOrigin + fDetOrigin; + + // TODO: Detector pixel size + const float fU = (detectorU - 0.5f*dims.iProjU + 0.5f) * fDetUSize; + + //const float fGamma = atanf(fU / fCentralRayLength); + //const float fBeta = gC_angle[angle]; + const float fGamma = atanf(fU / fCentralRayLength); + const float fBeta = -gC_angle[angle]; + + // compute the weight depending on the location in the central fan's radon + // space + float fWeight; + + if (fBeta <= 0.0f) { + fWeight = 0.0f; + } else if (fBeta <= 2.0f*(fCentralFanAngle + fGamma)) { + fWeight = sinf((M_PI / 4.0f) * fBeta / (fCentralFanAngle + fGamma)); + fWeight *= fWeight; + } else if (fBeta <= M_PI + 2*fGamma) { + fWeight = 1.0f; + } else if (fBeta <= M_PI + 2*fCentralFanAngle) { + fWeight = sinf((M_PI / 4.0f) * (M_PI + 2.0f*fCentralFanAngle - fBeta) / (fCentralFanAngle - fGamma)); + fWeight *= fWeight; + } else { + fWeight = 0.0f; + } + + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) + { + + projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] *= fWeight; + + } +} + + + +// Perform the FDK pre-weighting and filtering +bool FDK_Filter(cudaPitchedPtr D_projData, + cufftComplex * D_filter, + float fSrcOrigin, float fDetOrigin, + float fSrcZ, float fDetZ, + float fDetUSize, float fDetVSize, bool bShortScan, + const SDimensions3D& dims, const float* angles) +{ + // The pre-weighting factor for a ray is the cosine of the angle between + // the central line and the ray. + + dim3 dimBlock(g_detBlockU, g_anglesPerWeightBlock); + dim3 dimGrid( ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV), + (dims.iProjAngles+g_anglesPerWeightBlock-1)/g_anglesPerWeightBlock); + + int projPitch = D_projData.pitch/sizeof(float); + + devFDK_preweight<<<dimGrid, dimBlock>>>(D_projData.ptr, projPitch, 0, dims.iProjAngles, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, fDetUSize, fDetVSize, dims); + + cudaTextForceKernelsCompletion(); + + if (bShortScan) { + // We do short-scan Parker weighting + + cudaError_t e1 = cudaMemcpyToSymbol(gC_angle, angles, + dims.iProjAngles*sizeof(float), 0, + cudaMemcpyHostToDevice); + assert(!e1); + + // TODO: detector pixel size! + float fCentralFanAngle = atanf((dims.iProjU*0.5f) / + (fSrcOrigin + fDetOrigin)); + + devFDK_ParkerWeight<<<dimGrid, dimBlock>>>(D_projData.ptr, projPitch, 0, dims.iProjAngles, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, fDetUSize, fCentralFanAngle, dims); + + } + + cudaTextForceKernelsCompletion(); + + + // The filtering is a regular ramp filter per detector line. + + int iPaddedDetCount = calcNextPowerOfTwo(2 * dims.iProjU); + int iHalfFFTSize = calcFFTFourSize(iPaddedDetCount); + + + + // We process one sinogram at a time. + float* D_sinoData = (float*)D_projData.ptr; + + cufftComplex * D_sinoFFT = NULL; + allocateComplexOnDevice(dims.iProjAngles, iHalfFFTSize, &D_sinoFFT); + + bool ok = true; + + for (int v = 0; v < dims.iProjV; ++v) { + + ok = runCudaFFT(dims.iProjAngles, D_sinoData, projPitch, 0, + dims.iProjU, iPaddedDetCount, iHalfFFTSize, + D_sinoFFT); + + if (!ok) break; + + applyFilter(dims.iProjAngles, iHalfFFTSize, D_sinoFFT, D_filter); + + + ok = runCudaIFFT(dims.iProjAngles, D_sinoFFT, D_sinoData, projPitch, + 0, dims.iProjU, iPaddedDetCount, iHalfFFTSize); + + if (!ok) break; + + D_sinoData += (dims.iProjAngles * projPitch); + } + + freeComplexOnDevice(D_sinoFFT); + + return ok; +} + + +bool FDK(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + float fSrcOrigin, float fDetOrigin, + float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize, + const SDimensions3D& dims, const float* angles, bool bShortScan) +{ + bool ok; + // Generate filter + // TODO: Check errors + cufftComplex * D_filter; + int iPaddedDetCount = calcNextPowerOfTwo(2 * dims.iProjU); + int iHalfFFTSize = calcFFTFourSize(iPaddedDetCount); + + cufftComplex *pHostFilter = new cufftComplex[dims.iProjAngles * iHalfFFTSize]; + memset(pHostFilter, 0, sizeof(cufftComplex) * dims.iProjAngles * iHalfFFTSize); + + genFilter(FILTER_RAMLAK, 1.0f, dims.iProjAngles, pHostFilter, iPaddedDetCount, iHalfFFTSize); + + allocateComplexOnDevice(dims.iProjAngles, iHalfFFTSize, &D_filter); + uploadComplexArrayToDevice(dims.iProjAngles, iHalfFFTSize, pHostFilter, D_filter); + + delete [] pHostFilter; + + + // Perform filtering + + ok = FDK_Filter(D_projData, D_filter, fSrcOrigin, fDetOrigin, + fSrcZ, fDetZ, fDetUSize, fDetVSize, + bShortScan, dims, angles); + + // Clean up filter + freeComplexOnDevice(D_filter); + + + if (!ok) + return false; + + // Perform BP + + ok = FDK_BP(D_volumeData, D_projData, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, + fDetUSize, fDetVSize, dims, angles); + + if (!ok) + return false; + + return true; +} + + +} + +#ifdef STANDALONE +void dumpVolume(const char* filespec, const cudaPitchedPtr& data, const SDimensions3D& dims, float fMin, float fMax) +{ + float* buf = new float[dims.iVolX*dims.iVolY]; + unsigned int pitch = data.pitch / sizeof(float); + + for (int i = 0; i < dims.iVolZ; ++i) { + cudaMemcpy2D(buf, dims.iVolX*sizeof(float), ((float*)data.ptr)+pitch*dims.iVolY*i, data.pitch, dims.iVolX*sizeof(float), dims.iVolY, cudaMemcpyDeviceToHost); + + char fname[512]; + sprintf(fname, filespec, dims.iVolZ-i-1); + saveImage(fname, dims.iVolY, dims.iVolX, buf, fMin, fMax); + } +} + +void dumpSinograms(const char* filespec, const cudaPitchedPtr& data, const SDimensions3D& dims, float fMin, float fMax) +{ + float* bufs = new float[dims.iProjAngles*dims.iProjU]; + unsigned int pitch = data.pitch / sizeof(float); + + for (int i = 0; i < dims.iProjV; ++i) { + cudaMemcpy2D(bufs, dims.iProjU*sizeof(float), ((float*)data.ptr)+pitch*dims.iProjAngles*i, data.pitch, dims.iProjU*sizeof(float), dims.iProjAngles, cudaMemcpyDeviceToHost); + + char fname[512]; + sprintf(fname, filespec, i); + saveImage(fname, dims.iProjAngles, dims.iProjU, bufs, fMin, fMax); + } +} + +void dumpProjections(const char* filespec, const cudaPitchedPtr& data, const SDimensions3D& dims, float fMin, float fMax) +{ + float* bufp = new float[dims.iProjV*dims.iProjU]; + unsigned int pitch = data.pitch / sizeof(float); + + for (int i = 0; i < dims.iProjAngles; ++i) { + for (int j = 0; j < dims.iProjV; ++j) { + cudaMemcpy(bufp+dims.iProjU*j, ((float*)data.ptr)+pitch*dims.iProjAngles*j+pitch*i, dims.iProjU*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[512]; + sprintf(fname, filespec, i); + saveImage(fname, dims.iProjV, dims.iProjU, bufp, fMin, fMax); + } +} + + + + +int main() +{ +#if 0 + SDimensions3D dims; + dims.iVolX = 512; + dims.iVolY = 512; + dims.iVolZ = 512; + dims.iProjAngles = 180; + dims.iProjU = 1024; + dims.iProjV = 1024; + dims.iRaysPerDet = 1; + + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPitchedPtr volData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&volData, extentV); + + cudaExtent extentP; + extentP.width = dims.iProjU*sizeof(float); + extentP.height = dims.iProjAngles; + extentP.depth = dims.iProjV; + + cudaPitchedPtr projData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&projData, extentP); + cudaMemset3D(projData, 0, extentP); + +#if 0 + float* slice = new float[256*256]; + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = 256*sizeof(float); + ptr.xsize = 256*sizeof(float); + ptr.ysize = 256; + + for (unsigned int i = 0; i < 256*256; ++i) + slice[i] = 1.0f; + for (unsigned int i = 0; i < 256; ++i) { + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); +#if 0 + if (i == 128) { + for (unsigned int j = 0; j < 256*256; ++j) + slice[j] = 0.0f; + } +#endif + } +#endif + + SConeProjection angle[180]; + angle[0].fSrcX = -1536; + angle[0].fSrcY = 0; + angle[0].fSrcZ = 0; + + angle[0].fDetSX = 1024; + angle[0].fDetSY = -512; + angle[0].fDetSZ = 512; + + angle[0].fDetUX = 0; + angle[0].fDetUY = 1; + angle[0].fDetUZ = 0; + + angle[0].fDetVX = 0; + angle[0].fDetVY = 0; + angle[0].fDetVZ = -1; + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0) + for (int i = 1; i < 180; ++i) { + angle[i] = angle[0]; + ROTATE0(Src, i, i*2*M_PI/180); + ROTATE0(DetS, i, i*2*M_PI/180); + ROTATE0(DetU, i, i*2*M_PI/180); + ROTATE0(DetV, i, i*2*M_PI/180); + } +#undef ROTATE0 + + astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f); + + //dumpSinograms("sino%03d.png", projData, dims, 0, 512); + //dumpProjections("proj%03d.png", projData, dims, 0, 512); + + astraCUDA3d::zeroVolumeData(volData, dims); + + float* angles = new float[dims.iProjAngles]; + for (int i = 0; i < 180; ++i) + angles[i] = i*2*M_PI/180; + + astraCUDA3d::FDK(volData, projData, 1536, 512, 0, 0, dims, angles); + + dumpVolume("vol%03d.png", volData, dims, -20, 100); + + +#else + + SDimensions3D dims; + dims.iVolX = 1000; + dims.iVolY = 999; + dims.iVolZ = 500; + dims.iProjAngles = 376; + dims.iProjU = 1024; + dims.iProjV = 524; + dims.iRaysPerDet = 1; + + float* angles = new float[dims.iProjAngles]; + for (int i = 0; i < dims.iProjAngles; ++i) + angles[i] = -i*(M_PI)/360; + + cudaPitchedPtr volData = astraCUDA3d::allocateVolumeData(dims); + cudaPitchedPtr projData = astraCUDA3d::allocateProjectionData(dims); + astraCUDA3d::zeroProjectionData(projData, dims); + astraCUDA3d::zeroVolumeData(volData, dims); + + timeval t; + tic(t); + + for (int i = 0; i < dims.iProjAngles; ++i) { + char fname[256]; + sprintf(fname, "/home/wpalenst/tmp/Elke/proj%04d.png", i); + unsigned int w,h; + float* bufp = loadImage(fname, w,h); + + int pitch = projData.pitch / sizeof(float); + for (int j = 0; j < dims.iProjV; ++j) { + cudaMemcpy(((float*)projData.ptr)+dims.iProjAngles*pitch*j+pitch*i, bufp+dims.iProjU*j, dims.iProjU*sizeof(float), cudaMemcpyHostToDevice); + } + + delete[] bufp; + } + printf("Load time: %f\n", toc(t)); + + //dumpSinograms("sino%03d.png", projData, dims, -8.0f, 256.0f); + //astraCUDA3d::FDK(volData, projData, 7350, 62355, 0, 10, dims, angles); + //astraCUDA3d::FDK(volData, projData, 7350, -380, 0, 10, dims, angles); + + tic(t); + + astraCUDA3d::FDK(volData, projData, 7383.29867, 0, 0, 10, dims, angles); + + printf("FDK time: %f\n", toc(t)); + tic(t); + + dumpVolume("vol%03d.png", volData, dims, -65.9f, 200.0f); + //dumpVolume("vol%03d.png", volData, dims, 0.0f, 256.0f); + printf("Save time: %f\n", toc(t)); + +#endif + + +} +#endif diff --git a/cuda/3d/fdk.h b/cuda/3d/fdk.h new file mode 100644 index 0000000..5443b19 --- /dev/null +++ b/cuda/3d/fdk.h @@ -0,0 +1,43 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_FDK_H +#define _CUDA_FDK_H + +namespace astraCUDA3d { + +bool FDK(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + float fSrcOrigin, float fDetOrigin, + float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize, + const SDimensions3D& dims, const float* angles, bool bShortScan); + + +} + +#endif diff --git a/cuda/3d/par3d_bp.cu b/cuda/3d/par3d_bp.cu new file mode 100644 index 0000000..872b1eb --- /dev/null +++ b/cuda/3d/par3d_bp.cu @@ -0,0 +1,464 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include <cuda.h> +#include "util3d.h" + +#ifdef STANDALONE +#include "par3d_fp.h" +#include "testutil.h" +#endif + +#include "dims3d.h" + +typedef texture<float, 3, cudaReadModeElementType> texture3D; + +static texture3D gT_par3DProjTexture; + +namespace astraCUDA3d { + +static const unsigned int g_volBlockZ = 16; + +static const unsigned int g_anglesPerBlock = 64; +static const unsigned int g_volBlockX = 32; +static const unsigned int g_volBlockY = 16; + +static const unsigned g_MaxAngles = 1024; + +__constant__ float gC_Cux[g_MaxAngles]; +__constant__ float gC_Cuy[g_MaxAngles]; +__constant__ float gC_Cuz[g_MaxAngles]; +__constant__ float gC_Cuc[g_MaxAngles]; +__constant__ float gC_Cvx[g_MaxAngles]; +__constant__ float gC_Cvy[g_MaxAngles]; +__constant__ float gC_Cvz[g_MaxAngles]; +__constant__ float gC_Cvc[g_MaxAngles]; + + +static bool bindProjDataTexture(const cudaArray* array) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_par3DProjTexture.addressMode[0] = cudaAddressModeClamp; + gT_par3DProjTexture.addressMode[1] = cudaAddressModeClamp; + gT_par3DProjTexture.addressMode[2] = cudaAddressModeClamp; + gT_par3DProjTexture.filterMode = cudaFilterModeLinear; + gT_par3DProjTexture.normalized = false; + + cudaBindTextureToArray(gT_par3DProjTexture, array, channelDesc); + + // TODO: error value? + + return true; +} + + +__global__ void dev_par3D_BP(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims) +{ + float* volData = (float*)D_volData; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + + // threadIdx: x = rel x + // y = rel y + + // blockIdx: x = x + y + // y = z + + + // TO TRY: precompute part of detector intersection formulas in shared mem? + // TO TRY: inner loop over z, gather ray values in shared mem + + const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x; + const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y; + + if (X >= dims.iVolX) + return; + if (Y >= dims.iVolY) + return; + + const int startZ = blockIdx.y * g_volBlockZ; + int endZ = startZ + g_volBlockZ; + if (endZ > dims.iVolZ) + endZ = dims.iVolZ; + + float fX = X - 0.5f*dims.iVolX + 0.5f; + float fY = Y - 0.5f*dims.iVolY + 0.5f; + float fZ = startZ - 0.5f*dims.iVolZ + 0.5f; + + for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f) + { + + float fVal = 0.0f; + float fAngle = startAngle + 0.5f; + + for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f) + { + + const float fCux = gC_Cux[angle]; + const float fCuy = gC_Cuy[angle]; + const float fCuz = gC_Cuz[angle]; + const float fCuc = gC_Cuc[angle]; + const float fCvx = gC_Cvx[angle]; + const float fCvy = gC_Cvy[angle]; + const float fCvz = gC_Cvz[angle]; + const float fCvc = gC_Cvc[angle]; + + const float fUNum = fCuc + fX * fCux + fY * fCuy + fZ * fCuz; + const float fVNum = fCvc + fX * fCvx + fY * fCvy + fZ * fCvz; + + const float fU = fUNum + 1.0f; + const float fV = fVNum + 1.0f; + + fVal += tex3D(gT_par3DProjTexture, fU, fAngle, fV); // TODO: check order + + } + + volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal; + } + +} + +// supersampling version +__global__ void dev_par3D_BP_SS(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims) +{ + float* volData = (float*)D_volData; + + int endAngle = startAngle + g_anglesPerBlock; + if (endAngle > dims.iProjAngles) + endAngle = dims.iProjAngles; + + // threadIdx: x = rel x + // y = rel y + + // blockIdx: x = x + y + // y = z + + + // TO TRY: precompute part of detector intersection formulas in shared mem? + // TO TRY: inner loop over z, gather ray values in shared mem + + const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x; + const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y; + + if (X >= dims.iVolX) + return; + if (Y >= dims.iVolY) + return; + + const int startZ = blockIdx.y * g_volBlockZ; + int endZ = startZ + g_volBlockZ; + if (endZ > dims.iVolZ) + endZ = dims.iVolZ; + + float fX = X - 0.5f*dims.iVolX + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim; + float fY = Y - 0.5f*dims.iVolY + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim; + float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim; + + const float fSubStep = 1.0f/dims.iRaysPerVoxelDim; + + for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f) + { + + float fVal = 0.0f; + float fAngle = startAngle + 0.5f; + + for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f) + { + const float fCux = gC_Cux[angle]; + const float fCuy = gC_Cuy[angle]; + const float fCuz = gC_Cuz[angle]; + const float fCuc = gC_Cuc[angle]; + const float fCvx = gC_Cvx[angle]; + const float fCvy = gC_Cvy[angle]; + const float fCvz = gC_Cvz[angle]; + const float fCvc = gC_Cvc[angle]; + + float fXs = fX; + for (int iSubX = 0; iSubX < dims.iRaysPerVoxelDim; ++iSubX) { + float fYs = fY; + for (int iSubY = 0; iSubY < dims.iRaysPerVoxelDim; ++iSubY) { + float fZs = fZ; + for (int iSubZ = 0; iSubZ < dims.iRaysPerVoxelDim; ++iSubZ) { + + const float fUNum = fCuc + fXs * fCux + fYs * fCuy + fZs * fCuz; + const float fVNum = fCvc + fXs * fCvx + fYs * fCvy + fZs * fCvz; + + const float fU = fUNum + 1.0f; + const float fV = fVNum + 1.0f; + + fVal += tex3D(gT_par3DProjTexture, fU, fAngle, fV); // TODO: check order + fZs += fSubStep; + } + fYs += fSubStep; + } + fXs += fSubStep; + } + + } + + volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal / (dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim); + } + +} + +bool Par3DBP_Array(cudaPitchedPtr D_volumeData, + cudaArray *D_projArray, + const SDimensions3D& dims, const SPar3DProjection* angles) +{ + bindProjDataTexture(D_projArray); + + + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(expr,name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = (expr) ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + +#define DENOM (angles[i].fRayX*angles[i].fDetUY*angles[i].fDetVZ - angles[i].fRayX*angles[i].fDetUZ*angles[i].fDetVY - angles[i].fRayY*angles[i].fDetUX*angles[i].fDetVZ + angles[i].fRayY*angles[i].fDetUZ*angles[i].fDetVX + angles[i].fRayZ*angles[i].fDetUX*angles[i].fDetVY - angles[i].fRayZ*angles[i].fDetUY*angles[i].fDetVX) + + + TRANSFER_TO_CONSTANT( ( - (angles[i].fRayY*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVY)) / DENOM , Cux ); + TRANSFER_TO_CONSTANT( ( (angles[i].fRayX*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVX)) / DENOM , Cuy ); + TRANSFER_TO_CONSTANT( (- (angles[i].fRayX*angles[i].fDetVY - angles[i].fRayY*angles[i].fDetVX) ) / DENOM , Cuz ); + TRANSFER_TO_CONSTANT( (-(angles[i].fDetSY*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVY)*angles[i].fRayX + (angles[i].fRayY*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVY)*angles[i].fDetSX - (angles[i].fRayY*angles[i].fDetSZ - angles[i].fRayZ*angles[i].fDetSY)*angles[i].fDetVX) / DENOM , Cuc ); + + TRANSFER_TO_CONSTANT( ((angles[i].fRayY*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUY) ) / DENOM , Cvx ); + TRANSFER_TO_CONSTANT( (- (angles[i].fRayX*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUX) ) / DENOM , Cvy ); + TRANSFER_TO_CONSTANT( ((angles[i].fRayX*angles[i].fDetUY - angles[i].fRayY*angles[i].fDetUX) ) / DENOM , Cvz ); + TRANSFER_TO_CONSTANT( ((angles[i].fDetSY*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUY)*angles[i].fRayX - (angles[i].fRayY*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUY)*angles[i].fDetSX + (angles[i].fRayY*angles[i].fDetSZ - angles[i].fRayZ*angles[i].fDetSY)*angles[i].fDetUX ) / DENOM , Cvc ); + +#undef TRANSFER_TO_CONSTANT +#undef DENOM + + delete[] tmp; + + dim3 dimBlock(g_volBlockX, g_volBlockY); + + dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ); + + // timeval t; + // tic(t); + + for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) { + // printf("Calling BP: %d, %dx%d, %dx%d to %p\n", i, dimBlock.x, dimBlock.y, dimGrid.x, dimGrid.y, (void*)D_volumeData.ptr); + if (dims.iRaysPerVoxelDim == 1) + dev_par3D_BP<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims); + else + dev_par3D_BP_SS<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims); + } + + cudaTextForceKernelsCompletion(); + + // printf("%f\n", toc(t)); + + return true; +} + +bool Par3DBP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles) +{ + // transfer projections to array + + cudaArray* cuArray = allocateProjectionArray(dims); + transferProjectionsToArray(D_projData, cuArray, dims); + + bool ret = Par3DBP_Array(D_volumeData, cuArray, dims, angles); + + cudaFreeArray(cuArray); + + return ret; +} + + +} + +#ifdef STANDALONE +int main() +{ + SDimensions3D dims; + dims.iVolX = 256; + dims.iVolY = 256; + dims.iVolZ = 256; + dims.iProjAngles = 180; + dims.iProjU = 512; + dims.iProjV = 512; + dims.iRaysPerDet = 1; + + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPitchedPtr volData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&volData, extentV); + + cudaExtent extentP; + extentP.width = dims.iProjU*sizeof(float); + extentP.height = dims.iProjAngles; + extentP.depth = dims.iProjV; + + cudaPitchedPtr projData; // pitch, ptr, xsize, ysize + + cudaMalloc3D(&projData, extentP); + cudaMemset3D(projData, 0, extentP); + + float* slice = new float[256*256]; + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = 256*sizeof(float); + ptr.xsize = 256*sizeof(float); + ptr.ysize = 256; + + for (unsigned int i = 0; i < 256*256; ++i) + slice[i] = 1.0f; + for (unsigned int i = 0; i < 256; ++i) { + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); +#if 0 + if (i == 128) { + for (unsigned int j = 0; j < 256*256; ++j) + slice[j] = 0.0f; + } +#endif + } + + + SPar3DProjection angle[180]; + angle[0].fRayX = 1; + angle[0].fRayY = 0; + angle[0].fRayZ = 0; + + angle[0].fDetSX = 512; + angle[0].fDetSY = -256; + angle[0].fDetSZ = -256; + + angle[0].fDetUX = 0; + angle[0].fDetUY = 1; + angle[0].fDetUZ = 0; + + angle[0].fDetVX = 0; + angle[0].fDetVY = 0; + angle[0].fDetVZ = 1; + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0) + for (int i = 1; i < 180; ++i) { + angle[i] = angle[0]; + ROTATE0(Ray, i, i*2*M_PI/180); + ROTATE0(DetS, i, i*2*M_PI/180); + ROTATE0(DetU, i, i*2*M_PI/180); + ROTATE0(DetV, i, i*2*M_PI/180); + } +#undef ROTATE0 + + astraCUDA3d::Par3DFP(volData, projData, dims, angle, 1.0f); +#if 1 + float* bufs = new float[180*512]; + + for (int i = 0; i < 512; ++i) { + cudaMemcpy(bufs, ((float*)projData.ptr)+180*512*i, 180*512*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize); + + char fname[20]; + sprintf(fname, "sino%03d.png", i); + saveImage(fname, 180, 512, bufs, 0, 512); + } + + float* bufp = new float[512*512]; + + for (int i = 0; i < 180; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "proj%03d.png", i); + saveImage(fname, 512, 512, bufp, 0, 512); + } +#endif + for (unsigned int i = 0; i < 256*256; ++i) + slice[i] = 0.0f; + for (unsigned int i = 0; i < 256; ++i) { + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); + } + + astraCUDA3d::Par3DBP(volData, projData, dims, angle); +#if 1 + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", volData.pitch, volData.xsize, volData.ysize); + + char fname[20]; + sprintf(fname, "vol%03d.png", i); + saveImage(fname, 256, 256, buf, 0, 60000); + } +#endif + +} +#endif diff --git a/cuda/3d/par3d_bp.h b/cuda/3d/par3d_bp.h new file mode 100644 index 0000000..399a3cb --- /dev/null +++ b/cuda/3d/par3d_bp.h @@ -0,0 +1,45 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_PAR3D_BP_H +#define _CUDA_PAR3D_BP_H + +namespace astraCUDA3d { + +_AstraExport bool Par3DBP_Array(cudaPitchedPtr D_volumeData, + cudaArray *D_projArray, + const SDimensions3D& dims, const SPar3DProjection* angles); + +_AstraExport bool Par3DBP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles); + + +} + +#endif diff --git a/cuda/3d/par3d_fp.cu b/cuda/3d/par3d_fp.cu new file mode 100644 index 0000000..6bf9037 --- /dev/null +++ b/cuda/3d/par3d_fp.cu @@ -0,0 +1,814 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include <iostream> +#include <list> + +#include <cuda.h> +#include "util3d.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +#include "dims3d.h" + +typedef texture<float, 3, cudaReadModeElementType> texture3D; + +static texture3D gT_par3DVolumeTexture; + +namespace astraCUDA3d { + +static const unsigned int g_anglesPerBlock = 4; + +// thickness of the slices we're splitting the volume up into +static const unsigned int g_blockSlices = 64; +static const unsigned int g_detBlockU = 32; +static const unsigned int g_detBlockV = 32; + +static const unsigned g_MaxAngles = 1024; +__constant__ float gC_RayX[g_MaxAngles]; +__constant__ float gC_RayY[g_MaxAngles]; +__constant__ float gC_RayZ[g_MaxAngles]; +__constant__ float gC_DetSX[g_MaxAngles]; +__constant__ float gC_DetSY[g_MaxAngles]; +__constant__ float gC_DetSZ[g_MaxAngles]; +__constant__ float gC_DetUX[g_MaxAngles]; +__constant__ float gC_DetUY[g_MaxAngles]; +__constant__ float gC_DetUZ[g_MaxAngles]; +__constant__ float gC_DetVX[g_MaxAngles]; +__constant__ float gC_DetVY[g_MaxAngles]; +__constant__ float gC_DetVZ[g_MaxAngles]; + + +static bool bindVolumeDataTexture(const cudaArray* array) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + + gT_par3DVolumeTexture.addressMode[0] = cudaAddressModeClamp; + gT_par3DVolumeTexture.addressMode[1] = cudaAddressModeClamp; + gT_par3DVolumeTexture.addressMode[2] = cudaAddressModeClamp; + gT_par3DVolumeTexture.filterMode = cudaFilterModeLinear; + gT_par3DVolumeTexture.normalized = false; + + cudaBindTextureToArray(gT_par3DVolumeTexture, array, channelDesc); + + // TODO: error value? + + return true; +} + + + +// threadIdx: x = u detector +// y = relative angle +// blockIdx: x = u/v detector +// y = angle block + +#define PAR3D_FP_BODY(c0,c1,c2) \ + int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \ + if (angle >= endAngle) \ + return; \ + \ + const float fRayX = gC_RayX[angle]; \ + const float fRayY = gC_RayY[angle]; \ + const float fRayZ = gC_RayZ[angle]; \ + const float fDetUX = gC_DetUX[angle]; \ + const float fDetUY = gC_DetUY[angle]; \ + const float fDetUZ = gC_DetUZ[angle]; \ + const float fDetVX = gC_DetVX[angle]; \ + const float fDetVY = gC_DetVY[angle]; \ + const float fDetVZ = gC_DetVZ[angle]; \ + const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \ + const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \ + const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \ + \ + \ + \ + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \ + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \ + int endDetectorV = startDetectorV + g_detBlockV; \ + if (endDetectorV > dims.iProjV) \ + endDetectorV = dims.iProjV; \ + \ + int endSlice = startSlice + g_blockSlices; \ + if (endSlice > dims.iVol##c0) \ + endSlice = dims.iVol##c0; \ + \ + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \ + { \ + /* Trace ray in direction Ray to (detectorU,detectorV) from */ \ + /* X = startSlice to X = endSlice */ \ + \ + const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX; \ + const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY; \ + const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ; \ + \ + /* (x) ( 1) ( 0) */ \ + /* ray: (y) = (ay) * x + (by) */ \ + /* (z) (az) (bz) */ \ + \ + const float a##c1 = fRay##c1 / fRay##c0; \ + const float a##c2 = fRay##c2 / fRay##c0; \ + const float b##c1 = fDet##c1 - a##c1 * fDet##c0; \ + const float b##c2 = fDet##c2 - a##c2 * fDet##c0; \ + \ + const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \ + \ + float fVal = 0.0f; \ + \ + float f##c0 = startSlice + 1.5f; \ + float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f;\ + float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f;\ + \ + for (int s = startSlice; s < endSlice; ++s) \ + { \ + fVal += tex3D(gT_par3DVolumeTexture, fX, fY, fZ); \ + f##c0 += 1.0f; \ + f##c1 += a##c1; \ + f##c2 += a##c2; \ + } \ + \ + fVal *= fDistCorr; \ + \ + D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal; \ + } + + + +// Supersampling version +#define PAR3D_FP_SS_BODY(c0,c1,c2) \ + int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \ + if (angle >= endAngle) \ + return; \ + \ + const float fRayX = gC_RayX[angle]; \ + const float fRayY = gC_RayY[angle]; \ + const float fRayZ = gC_RayZ[angle]; \ + const float fDetUX = gC_DetUX[angle]; \ + const float fDetUY = gC_DetUY[angle]; \ + const float fDetUZ = gC_DetUZ[angle]; \ + const float fDetVX = gC_DetVX[angle]; \ + const float fDetVY = gC_DetVY[angle]; \ + const float fDetVZ = gC_DetVZ[angle]; \ + const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \ + const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \ + const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \ + \ + \ + \ + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \ + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \ + int endDetectorV = startDetectorV + g_detBlockV; \ + if (endDetectorV > dims.iProjV) \ + endDetectorV = dims.iProjV; \ + \ + int endSlice = startSlice + g_blockSlices; \ + if (endSlice > dims.iVol##c0) \ + endSlice = dims.iVol##c0; \ + \ + const float fSubStep = 1.0f/dims.iRaysPerDetDim; \ + \ + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \ + { \ + \ + float fV = 0.0f; \ + \ + float fdU = detectorU - 0.5f + 0.5f*fSubStep; \ + for (int iSubU = 0; iSubU < dims.iRaysPerDetDim; ++iSubU, fdU+=fSubStep) { \ + float fdV = detectorV - 0.5f + 0.5f*fSubStep; \ + for (int iSubV = 0; iSubV < dims.iRaysPerDetDim; ++iSubV, fdV+=fSubStep) { \ + \ + /* Trace ray in direction Ray to (detectorU,detectorV) from */ \ + /* X = startSlice to X = endSlice */ \ + \ + const float fDetX = fDetSX + fdU*fDetUX + fdV*fDetVX; \ + const float fDetY = fDetSY + fdU*fDetUY + fdV*fDetVY; \ + const float fDetZ = fDetSZ + fdU*fDetUZ + fdV*fDetVZ; \ + \ + /* (x) ( 1) ( 0) */ \ + /* ray: (y) = (ay) * x + (by) */ \ + /* (z) (az) (bz) */ \ + \ + const float a##c1 = fRay##c1 / fRay##c0; \ + const float a##c2 = fRay##c2 / fRay##c0; \ + const float b##c1 = fDet##c1 - a##c1 * fDet##c0; \ + const float b##c2 = fDet##c2 - a##c2 * fDet##c0; \ + \ + const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \ + \ + float fVal = 0.0f; \ + \ + float f##c0 = startSlice + 1.5f; \ + float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f;\ + float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f;\ + \ + for (int s = startSlice; s < endSlice; ++s) \ + { \ + fVal += tex3D(gT_par3DVolumeTexture, fX, fY, fZ); \ + f##c0 += 1.0f; \ + f##c1 += a##c1; \ + f##c2 += a##c2; \ + } \ + \ + fVal *= fDistCorr; \ + fV += fVal; \ + \ + } \ + } \ + \ + D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fV / (dims.iRaysPerDetDim * dims.iRaysPerDetDim);\ + } + + + +__global__ void par3D_FP_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_BODY(X,Y,Z) +} + +__global__ void par3D_FP_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_BODY(Y,X,Z) +} + +__global__ void par3D_FP_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_BODY(Z,X,Y) +} + +__global__ void par3D_FP_SS_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_SS_BODY(X,Y,Z) +} + +__global__ void par3D_FP_SS_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_SS_BODY(Y,X,Z) +} + +__global__ void par3D_FP_SS_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_SS_BODY(Z,X,Y) +} + + +__device__ float dirWeights(float fX, float fN) { + if (fX <= 0.5f) // outside image on left + return 0.0f; + if (fX <= 1.5f) // half outside image on left + return (fX - 0.5f) * (fX - 0.5f); + if (fX <= fN + 0.5f) { // inside image + float t = fX - 0.5f - floorf(fX - 0.5f); + return t*t + (1-t)*(1-t); + } + if (fX <= fN + 1.5f) // half outside image on right + return (fN + 1.5f - fX) * (fN + 1.5f - fX); + return 0.0f; // outside image on right +} + +#define PAR3D_FP_SUMSQW_BODY(c0,c1,c2) \ + int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \ + if (angle >= endAngle) \ + return; \ + \ + const float fRayX = gC_RayX[angle]; \ + const float fRayY = gC_RayY[angle]; \ + const float fRayZ = gC_RayZ[angle]; \ + const float fDetUX = gC_DetUX[angle]; \ + const float fDetUY = gC_DetUY[angle]; \ + const float fDetUZ = gC_DetUZ[angle]; \ + const float fDetVX = gC_DetVX[angle]; \ + const float fDetVY = gC_DetVY[angle]; \ + const float fDetVZ = gC_DetVZ[angle]; \ + const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \ + const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \ + const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \ + \ + \ + \ + const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \ + const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \ + int endDetectorV = startDetectorV + g_detBlockV; \ + if (endDetectorV > dims.iProjV) \ + endDetectorV = dims.iProjV; \ + \ + int endSlice = startSlice + g_blockSlices; \ + if (endSlice > dims.iVol##c0) \ + endSlice = dims.iVol##c0; \ + \ + for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \ + { \ + /* Trace ray in direction Ray to (detectorU,detectorV) from */ \ + /* X = startSlice to X = endSlice */ \ + \ + const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX; \ + const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY; \ + const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ; \ + \ + /* (x) ( 1) ( 0) */ \ + /* ray: (y) = (ay) * x + (by) */ \ + /* (z) (az) (bz) */ \ + \ + const float a##c1 = fRay##c1 / fRay##c0; \ + const float a##c2 = fRay##c2 / fRay##c0; \ + const float b##c1 = fDet##c1 - a##c1 * fDet##c0; \ + const float b##c2 = fDet##c2 - a##c2 * fDet##c0; \ + \ + const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \ + \ + float fVal = 0.0f; \ + \ + float f##c0 = startSlice + 1.5f; \ + float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f;\ + float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f;\ + \ + for (int s = startSlice; s < endSlice; ++s) \ + { \ + fVal += dirWeights(f##c1, dims.iVol##c1) * dirWeights(f##c2, dims.iVol##c2) * fDistCorr * fDistCorr; \ + f##c0 += 1.0f; \ + f##c1 += a##c1; \ + f##c2 += a##c2; \ + } \ + \ + D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal; \ + } + +// Supersampling version +// TODO + + +__global__ void par3D_FP_SumSqW_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_SUMSQW_BODY(X,Y,Z) +} + +__global__ void par3D_FP_SumSqW_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_SUMSQW_BODY(Y,X,Z) +} + +__global__ void par3D_FP_SumSqW_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale) +{ +PAR3D_FP_SUMSQW_BODY(Z,X,Y) +} + + + +bool Par3DFP_Array(cudaArray *D_volArray, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles, + float fOutputScale) +{ + + bindVolumeDataTexture(D_volArray); + + + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT(RayX); + TRANSFER_TO_CONSTANT(RayY); + TRANSFER_TO_CONSTANT(RayZ); + TRANSFER_TO_CONSTANT(DetSX); + TRANSFER_TO_CONSTANT(DetSY); + TRANSFER_TO_CONSTANT(DetSZ); + TRANSFER_TO_CONSTANT(DetUX); + TRANSFER_TO_CONSTANT(DetUY); + TRANSFER_TO_CONSTANT(DetUZ); + TRANSFER_TO_CONSTANT(DetVX); + TRANSFER_TO_CONSTANT(DetVY); + TRANSFER_TO_CONSTANT(DetVZ); + +#undef TRANSFER_TO_CONSTANT + + delete[] tmp; + + std::list<cudaStream_t> streams; + dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles + + // Run over all angles, grouping them into groups of the same + // orientation (roughly horizontal vs. roughly vertical). + // Start a stream of grids for each such group. + + unsigned int blockStart = 0; + unsigned int blockEnd = 0; + int blockDirection = 0; + + // timeval t; + // tic(t); + + for (unsigned int a = 0; a <= dims.iProjAngles; ++a) { + int dir; + if (a != dims.iProjAngles) { + float dX = fabsf(angles[a].fRayX); + float dY = fabsf(angles[a].fRayY); + float dZ = fabsf(angles[a].fRayZ); + + if (dX >= dY && dX >= dZ) + dir = 0; + else if (dY >= dX && dY >= dZ) + dir = 1; + else + dir = 2; + } + + if (a == dims.iProjAngles || dir != blockDirection) { + // block done + + blockEnd = a; + if (blockStart != blockEnd) { + + dim3 dimGrid( + ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV), +(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock); + // TODO: check if we can't immediately + // destroy the stream after use + cudaStream_t stream; + cudaStreamCreate(&stream); + streams.push_back(stream); + + // printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y); + + if (blockDirection == 0) { + for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + par3D_FP_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else + par3D_FP_SS_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + } else if (blockDirection == 1) { + for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + par3D_FP_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else + par3D_FP_SS_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + } else if (blockDirection == 2) { + for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + par3D_FP_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else + par3D_FP_SS_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + } + + } + + blockDirection = dir; + blockStart = a; + } + } + + for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter) + cudaStreamDestroy(*iter); + + streams.clear(); + + cudaTextForceKernelsCompletion(); + + + // printf("%f\n", toc(t)); + + return true; +} + +bool Par3DFP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles, + float fOutputScale) +{ + // transfer volume to array + cudaArray* cuArray = allocateVolumeArray(dims); + transferVolumeToArray(D_volumeData, cuArray, dims); + + bool ret = Par3DFP_Array(cuArray, D_projData, dims, angles, fOutputScale); + + cudaFreeArray(cuArray); + + return ret; +} + + + +bool Par3DFP_SumSqW(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles, + float fOutputScale) +{ + // transfer angles to constant memory + float* tmp = new float[dims.iProjAngles]; + +#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0) + + TRANSFER_TO_CONSTANT(RayX); + TRANSFER_TO_CONSTANT(RayY); + TRANSFER_TO_CONSTANT(RayZ); + TRANSFER_TO_CONSTANT(DetSX); + TRANSFER_TO_CONSTANT(DetSY); + TRANSFER_TO_CONSTANT(DetSZ); + TRANSFER_TO_CONSTANT(DetUX); + TRANSFER_TO_CONSTANT(DetUY); + TRANSFER_TO_CONSTANT(DetUZ); + TRANSFER_TO_CONSTANT(DetVX); + TRANSFER_TO_CONSTANT(DetVY); + TRANSFER_TO_CONSTANT(DetVZ); + +#undef TRANSFER_TO_CONSTANT + + delete[] tmp; + + std::list<cudaStream_t> streams; + dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles + + // Run over all angles, grouping them into groups of the same + // orientation (roughly horizontal vs. roughly vertical). + // Start a stream of grids for each such group. + + unsigned int blockStart = 0; + unsigned int blockEnd = 0; + int blockDirection = 0; + + // timeval t; + // tic(t); + + for (unsigned int a = 0; a <= dims.iProjAngles; ++a) { + int dir; + if (a != dims.iProjAngles) { + float dX = fabsf(angles[a].fRayX); + float dY = fabsf(angles[a].fRayY); + float dZ = fabsf(angles[a].fRayZ); + + if (dX >= dY && dX >= dZ) + dir = 0; + else if (dY >= dX && dY >= dZ) + dir = 1; + else + dir = 2; + } + + if (a == dims.iProjAngles || dir != blockDirection) { + // block done + + blockEnd = a; + if (blockStart != blockEnd) { + + dim3 dimGrid( + ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV), +(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock); + // TODO: check if we can't immediately + // destroy the stream after use + cudaStream_t stream; + cudaStreamCreate(&stream); + streams.push_back(stream); + + // printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y); + + if (blockDirection == 0) { + for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + par3D_FP_SumSqW_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else +#if 0 + par3D_FP_SS_SumSqW_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); +#else + assert(false); +#endif + } else if (blockDirection == 1) { + for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + par3D_FP_SumSqW_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else +#if 0 + par3D_FP_SS_SumSqW_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); +#else + assert(false); +#endif + } else if (blockDirection == 2) { + for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices) + if (dims.iRaysPerDetDim == 1) + par3D_FP_SumSqW_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); + else +#if 0 + par3D_FP_SS_SumSqW_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale); +#else + assert(false); +#endif + } + + } + + blockDirection = dir; + blockStart = a; + } + } + + for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter) + cudaStreamDestroy(*iter); + + streams.clear(); + + cudaTextForceKernelsCompletion(); + + + // printf("%f\n", toc(t)); + + return true; +} + + + + + + + +} + +#ifdef STANDALONE + +using namespace astraCUDA3d; + +int main() +{ + cudaSetDevice(1); + + + SDimensions3D dims; + dims.iVolX = 500; + dims.iVolY = 500; + dims.iVolZ = 81; + dims.iProjAngles = 241; + dims.iProjU = 600; + dims.iProjV = 100; + dims.iRaysPerDet = 1; + + SPar3DProjection base; + base.fRayX = 1.0f; + base.fRayY = 0.0f; + base.fRayZ = 0.1f; + + base.fDetSX = 0.0f; + base.fDetSY = -300.0f; + base.fDetSZ = -50.0f; + + base.fDetUX = 0.0f; + base.fDetUY = 1.0f; + base.fDetUZ = 0.0f; + + base.fDetVX = 0.0f; + base.fDetVY = 0.0f; + base.fDetVZ = 1.0f; + + SPar3DProjection angle[dims.iProjAngles]; + + cudaPitchedPtr volData; // pitch, ptr, xsize, ysize + + volData = allocateVolumeData(dims); + + cudaPitchedPtr projData; // pitch, ptr, xsize, ysize + + projData = allocateProjectionData(dims); + + unsigned int ix = 500,iy = 500; + + float* buf = new float[dims.iProjU*dims.iProjV]; + + float* slice = new float[dims.iVolX*dims.iVolY]; + for (int i = 0; i < dims.iVolX*dims.iVolY; ++i) + slice[i] = 1.0f; + + for (unsigned int a = 0; a < 241; a += dims.iProjAngles) { + + zeroProjectionData(projData, dims); + + for (int y = 0; y < iy; y += dims.iVolY) { + for (int x = 0; x < ix; x += dims.iVolX) { + + timeval st; + tic(st); + + for (int z = 0; z < dims.iVolZ; ++z) { +// char sfn[256]; +// sprintf(sfn, "/home/wpalenst/projects/cone_simulation/phantom_4096/mouse_fem_phantom_%04d.png", 30+z); +// float* slice = loadSubImage(sfn, x, y, dims.iVolX, dims.iVolY); + + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = dims.iVolX*sizeof(float); + ptr.xsize = dims.iVolX*sizeof(float); + ptr.ysize = dims.iVolY; + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, z }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaError err = cudaMemcpy3D(&p); + assert(!err); +// delete[] slice; + } + + printf("Load: %f\n", toc(st)); + +#if 0 + + cudaPos zp = { 0, 0, 0 }; + + cudaPitchedPtr t; + t.ptr = new float[1024*1024]; + t.pitch = 1024*4; + t.xsize = 1024*4; + t.ysize = 1024; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = volData; + p.extent = extentS; + p.dstArray = 0; + p.dstPtr = t; + p.dstPos = zp; + p.kind = cudaMemcpyDeviceToHost; + cudaError err = cudaMemcpy3D(&p); + assert(!err); + + char fn[32]; + sprintf(fn, "t%d%d.png", x / dims.iVolX, y / dims.iVolY); + saveImage(fn, 1024, 1024, (float*)t.ptr); + saveImage("s.png", 4096, 4096, slice); + delete[] (float*)t.ptr; +#endif + + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); angle[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); angle[i].f##name##Z = base.f##name##Z; } while(0) +#define SHIFT(name,i,x,y) do { angle[i].f##name##X += x; angle[i].f##name##Y += y; } while(0) + for (int i = 0; i < dims.iProjAngles; ++i) { + ROTATE0(Ray, i, (a+i)*.8*M_PI/180); + ROTATE0(DetS, i, (a+i)*.8*M_PI/180); + ROTATE0(DetU, i, (a+i)*.8*M_PI/180); + ROTATE0(DetV, i, (a+i)*.8*M_PI/180); + + +// SHIFT(Src, i, (-x+1536), (-y+1536)); +// SHIFT(DetS, i, (-x+1536), (-y+1536)); + } +#undef ROTATE0 +#undef SHIFT + tic(st); + + astraCUDA3d::Par3DFP(volData, projData, dims, angle, 1.0f); + + printf("FP: %f\n", toc(st)); + + } + } + for (unsigned int aa = 0; aa < dims.iProjAngles; ++aa) { + for (unsigned int v = 0; v < dims.iProjV; ++v) + cudaMemcpy(buf+v*dims.iProjU, ((float*)projData.ptr)+(v*dims.iProjAngles+aa)*(projData.pitch/sizeof(float)), dims.iProjU*sizeof(float), cudaMemcpyDeviceToHost); + + char fname[32]; + sprintf(fname, "proj%03d.png", a+aa); + saveImage(fname, dims.iProjV, dims.iProjU, buf, 0.0f, 1000.0f); + } + } + + delete[] buf; + +} +#endif diff --git a/cuda/3d/par3d_fp.h b/cuda/3d/par3d_fp.h new file mode 100644 index 0000000..7208361 --- /dev/null +++ b/cuda/3d/par3d_fp.h @@ -0,0 +1,51 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_PAR3D_FP_H +#define _CUDA_PAR3D_FP_H + +namespace astraCUDA3d { + +_AstraExport bool Par3DFP_Array(cudaArray *D_volArray, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles, + float fOutputScale); + +_AstraExport bool Par3DFP(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles, + float fOutputScale); + +_AstraExport bool Par3DFP_SumSqW(cudaPitchedPtr D_volumeData, + cudaPitchedPtr D_projData, + const SDimensions3D& dims, const SPar3DProjection* angles, + float fOutputScale); + +} + +#endif diff --git a/cuda/3d/sirt3d.cu b/cuda/3d/sirt3d.cu new file mode 100644 index 0000000..f615204 --- /dev/null +++ b/cuda/3d/sirt3d.cu @@ -0,0 +1,533 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> + +#include "sirt3d.h" +#include "util3d.h" +#include "arith3d.h" +#include "cone_fp.h" + +#ifdef STANDALONE +#include "testutil.h" +#endif + +namespace astraCUDA3d { + +SIRT::SIRT() : ReconAlgo3D() +{ + D_maskData.ptr = 0; + D_smaskData.ptr = 0; + + D_sinoData.ptr = 0; + D_volumeData.ptr = 0; + + D_projData.ptr = 0; + D_tmpData.ptr = 0; + + D_lineWeight.ptr = 0; + D_pixelWeight.ptr = 0; + + useVolumeMask = false; + useSinogramMask = false; + + useMinConstraint = false; + useMaxConstraint = false; +} + + +SIRT::~SIRT() +{ + reset(); +} + +void SIRT::reset() +{ + cudaFree(D_projData.ptr); + cudaFree(D_tmpData.ptr); + cudaFree(D_lineWeight.ptr); + cudaFree(D_pixelWeight.ptr); + + D_maskData.ptr = 0; + D_smaskData.ptr = 0; + + D_sinoData.ptr = 0; + D_volumeData.ptr = 0; + + D_projData.ptr = 0; + D_tmpData.ptr = 0; + + D_lineWeight.ptr = 0; + D_pixelWeight.ptr = 0; + + useVolumeMask = false; + useSinogramMask = false; + + ReconAlgo3D::reset(); +} + +bool SIRT::enableVolumeMask() +{ + useVolumeMask = true; + return true; +} + +bool SIRT::enableSinogramMask() +{ + useSinogramMask = true; + return true; +} + + +bool SIRT::init() +{ + D_pixelWeight = allocateVolumeData(dims); + zeroVolumeData(D_pixelWeight, dims); + + D_tmpData = allocateVolumeData(dims); + zeroVolumeData(D_tmpData, dims); + + D_projData = allocateProjectionData(dims); + zeroProjectionData(D_projData, dims); + + D_lineWeight = allocateProjectionData(dims); + zeroProjectionData(D_lineWeight, dims); + + // We can't precompute lineWeights and pixelWeights when using a mask + if (!useVolumeMask && !useSinogramMask) + precomputeWeights(); + + // TODO: check if allocations succeeded + return true; +} + +bool SIRT::setMinConstraint(float fMin) +{ + fMinConstraint = fMin; + useMinConstraint = true; + return true; +} + +bool SIRT::setMaxConstraint(float fMax) +{ + fMaxConstraint = fMax; + useMaxConstraint = true; + return true; +} + +bool SIRT::precomputeWeights() +{ + zeroProjectionData(D_lineWeight, dims); + if (useVolumeMask) { + callFP(D_maskData, D_lineWeight, 1.0f); + } else { + processVol3D<opSet>(D_tmpData, 1.0f, dims); + callFP(D_tmpData, D_lineWeight, 1.0f); + } + processSino3D<opInvert>(D_lineWeight, dims); + + if (useSinogramMask) { + // scale line weights with sinogram mask to zero out masked sinogram pixels + processSino3D<opMul>(D_lineWeight, D_smaskData, dims); + } + + zeroVolumeData(D_pixelWeight, dims); + + if (useSinogramMask) { + callBP(D_pixelWeight, D_smaskData); + } else { + processSino3D<opSet>(D_projData, 1.0f, dims); + callBP(D_pixelWeight, D_projData); + } +#if 0 + float* bufp = new float[512*512]; + + for (int i = 0; i < 180; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)D_projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "ray%03d.png", i); + saveImage(fname, 512, 512, bufp); + } +#endif + +#if 0 + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)D_pixelWeight.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + char fname[20]; + sprintf(fname, "pix%03d.png", i); + saveImage(fname, 256, 256, buf); + } +#endif + processVol3D<opInvert>(D_pixelWeight, dims); + + if (useVolumeMask) { + // scale pixel weights with mask to zero out masked pixels + processVol3D<opMul>(D_pixelWeight, D_maskData, dims); + } + + return true; +} + + +bool SIRT::setVolumeMask(cudaPitchedPtr& _D_maskData) +{ + assert(useVolumeMask); + + D_maskData = _D_maskData; + + return true; +} + +bool SIRT::setSinogramMask(cudaPitchedPtr& _D_smaskData) +{ + assert(useSinogramMask); + + D_smaskData = _D_smaskData; + + return true; +} + +bool SIRT::setBuffers(cudaPitchedPtr& _D_volumeData, + cudaPitchedPtr& _D_projData) +{ + D_volumeData = _D_volumeData; + D_sinoData = _D_projData; + + fprintf(stderr, "Reconstruction buffer: %p\n", (void*)D_volumeData.ptr); + + return true; +} + +bool SIRT::iterate(unsigned int iterations) +{ + shouldAbort = false; + + if (useVolumeMask || useSinogramMask) + precomputeWeights(); + +#if 0 + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)D_pixelWeight.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + char fname[20]; + sprintf(fname, "pix%03d.png", i); + saveImage(fname, 256, 256, buf); + } +#endif +#if 0 + float* bufp = new float[512*512]; + + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)D_lineWeight.ptr)+100*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "ray%03d.png", i); + saveImage(fname, 512, 512, bufp); + } +#endif + + + // iteration + for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) { + // copy sinogram to projection data + duplicateProjectionData(D_projData, D_sinoData, dims); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + duplicateVolumeData(D_tmpData, D_volumeData, dims); + processVol3D<opMul>(D_tmpData, D_maskData, dims); + callFP(D_tmpData, D_projData, -1.0f); + } else { + callFP(D_volumeData, D_projData, -1.0f); + } + + processSino3D<opMul>(D_projData, D_lineWeight, dims); + + zeroVolumeData(D_tmpData, dims); +#if 0 + float* bufp = new float[512*512]; + printf("Dumping projData: %p\n", (void*)D_projData.ptr); + for (int i = 0; i < 180; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)D_projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "diff%03d.png", i); + saveImage(fname, 512, 512, bufp); + } +#endif + + + callBP(D_tmpData, D_projData); +#if 0 + printf("Dumping tmpData: %p\n", (void*)D_tmpData.ptr); + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)D_tmpData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + char fname[20]; + sprintf(fname, "add%03d.png", i); + saveImage(fname, 256, 256, buf); + } +#endif + + + processVol3D<opAddMul>(D_volumeData, D_tmpData, D_pixelWeight, dims); + + if (useMinConstraint) + processVol3D<opClampMin>(D_volumeData, fMinConstraint, dims); + if (useMaxConstraint) + processVol3D<opClampMax>(D_volumeData, fMaxConstraint, dims); + } + + return true; +} + +float SIRT::computeDiffNorm() +{ + // copy sinogram to projection data + duplicateProjectionData(D_projData, D_sinoData, dims); + + // do FP, subtracting projection from sinogram + if (useVolumeMask) { + duplicateVolumeData(D_tmpData, D_volumeData, dims); + processVol3D<opMul>(D_tmpData, D_maskData, dims); + callFP(D_tmpData, D_projData, -1.0f); + } else { + callFP(D_volumeData, D_projData, -1.0f); + } + + float s = dotProduct3D(D_projData, dims.iProjU, dims.iProjAngles, dims.iProjV); + return sqrt(s); +} + + +bool doSIRT(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_sinoData, + cudaPitchedPtr& D_maskData, + const SDimensions3D& dims, const SConeProjection* angles, + unsigned int iterations) +{ + SIRT sirt; + bool ok = true; + + ok &= sirt.setConeGeometry(dims, angles); + if (D_maskData.ptr) + ok &= sirt.enableVolumeMask(); + + if (!ok) + return false; + + ok = sirt.init(); + if (!ok) + return false; + + if (D_maskData.ptr) + ok &= sirt.setVolumeMask(D_maskData); + + ok &= sirt.setBuffers(D_volumeData, D_sinoData); + if (!ok) + return false; + + ok = sirt.iterate(iterations); + + return ok; +} + +} + +#ifdef STANDALONE + +using namespace astraCUDA3d; + +int main() +{ + SDimensions3D dims; + dims.iVolX = 256; + dims.iVolY = 256; + dims.iVolZ = 256; + dims.iProjAngles = 100; + dims.iProjU = 512; + dims.iProjV = 512; + dims.iRaysPerDet = 1; + + SConeProjection angle[100]; + angle[0].fSrcX = -2905.6; + angle[0].fSrcY = 0; + angle[0].fSrcZ = 0; + + angle[0].fDetSX = 694.4; + angle[0].fDetSY = -122.4704; + angle[0].fDetSZ = -122.4704; + + angle[0].fDetUX = 0; + angle[0].fDetUY = .4784; + //angle[0].fDetUY = .5; + angle[0].fDetUZ = 0; + + angle[0].fDetVX = 0; + angle[0].fDetVY = 0; + angle[0].fDetVZ = .4784; + +#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0) + for (int i = 1; i < 100; ++i) { + angle[i] = angle[0]; + ROTATE0(Src, i, i*2*M_PI/100); + ROTATE0(DetS, i, i*2*M_PI/100); + ROTATE0(DetU, i, i*2*M_PI/100); + ROTATE0(DetV, i, i*2*M_PI/100); + } +#undef ROTATE0 + + + cudaPitchedPtr volData = allocateVolumeData(dims); + cudaPitchedPtr projData = allocateProjectionData(dims); + zeroProjectionData(projData, dims); + + float* pbuf = new float[100*512*512]; + copyProjectionsFromDevice(pbuf, projData, dims); + copyProjectionsToDevice(pbuf, projData, dims); + delete[] pbuf; + +#if 0 + float* slice = new float[256*256]; + cudaPitchedPtr ptr; + ptr.ptr = slice; + ptr.pitch = 256*sizeof(float); + ptr.xsize = 256*sizeof(float); + ptr.ysize = 256; + + for (unsigned int i = 0; i < 256; ++i) { + for (unsigned int y = 0; y < 256; ++y) + for (unsigned int x = 0; x < 256; ++x) + slice[y*256+x] = (i-127.5)*(i-127.5)+(y-127.5)*(y-127.5)+(x-127.5)*(x-127.5) < 4900 ? 1.0f : 0.0f; + + cudaExtent extentS; + extentS.width = dims.iVolX*sizeof(float); + extentS.height = dims.iVolY; + extentS.depth = 1; + cudaPos sp = { 0, 0, 0 }; + cudaPos dp = { 0, 0, i }; + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = sp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = dp; + p.dstPtr = volData; + p.extent = extentS; + p.kind = cudaMemcpyHostToDevice; + cudaMemcpy3D(&p); + } + astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f); + +#else + + for (int i = 0; i < 100; ++i) { + char fname[32]; + sprintf(fname, "Tiffs/%04d.png", 4*i); + unsigned int w,h; + float* bufp = loadImage(fname, w,h); + + for (int j = 0; j < 512*512; ++j) { + float v = bufp[j]; + if (v > 236.0f) v = 236.0f; + v = logf(236.0f / v); + bufp[j] = 256*v; + } + + for (int j = 0; j < 512; ++j) { + cudaMemcpy(((float*)projData.ptr)+100*512*j+512*i, bufp+512*j, 512*sizeof(float), cudaMemcpyHostToDevice); + } + + delete[] bufp; + + } +#endif + +#if 0 + float* bufs = new float[100*512]; + + for (int i = 0; i < 512; ++i) { + cudaMemcpy(bufs, ((float*)projData.ptr)+100*512*i, 100*512*sizeof(float), cudaMemcpyDeviceToHost); + + printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize); + + char fname[20]; + sprintf(fname, "sino%03d.png", i); + saveImage(fname, 100, 512, bufs); + } + + float* bufp = new float[512*512]; + + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < 512; ++j) { + cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+100*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost); + } + + char fname[20]; + sprintf(fname, "proj%03d.png", i); + saveImage(fname, 512, 512, bufp); + } +#endif + + zeroVolumeData(volData, dims); + + cudaPitchedPtr maskData; + maskData.ptr = 0; + + astraCUDA3d::doSIRT(volData, projData, maskData, dims, angle, 50); +#if 1 + float* buf = new float[256*256]; + + for (int i = 0; i < 256; ++i) { + cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost); + + char fname[20]; + sprintf(fname, "vol%03d.png", i); + saveImage(fname, 256, 256, buf); + } +#endif + + return 0; +} +#endif + diff --git a/cuda/3d/sirt3d.h b/cuda/3d/sirt3d.h new file mode 100644 index 0000000..c3752c2 --- /dev/null +++ b/cuda/3d/sirt3d.h @@ -0,0 +1,118 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_SIRT3D_H +#define _CUDA_SIRT3D_H + +#include "util3d.h" +#include "algo3d.h" + +namespace astraCUDA3d { + +class _AstraExport SIRT : public ReconAlgo3D { +public: + SIRT(); + ~SIRT(); + +// bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs); + + + bool enableVolumeMask(); + bool enableSinogramMask(); + + // init should be called after setting all geometry + bool init(); + + // setVolumeMask should be called after init and before iterate, + // but only if enableVolumeMask was called before init. + // It may be called again after iterate. + bool setVolumeMask(cudaPitchedPtr& D_maskData); + + // setSinogramMask should be called after init and before iterate, + // but only if enableSinogramMask was called before init. + // It may be called again after iterate. + bool setSinogramMask(cudaPitchedPtr& D_smaskData); + + + // setBuffers should be called after init and before iterate. + // It may be called again after iterate. + bool setBuffers(cudaPitchedPtr& D_volumeData, + cudaPitchedPtr& D_projData); + + + // set Min/Max constraints. They may be called at any time, and will affect + // any iterate() calls afterwards. + bool setMinConstraint(float fMin); + bool setMaxConstraint(float fMax); + + // iterate should be called after init and setBuffers. + // It may be called multiple times. + bool iterate(unsigned int iterations); + + // Compute the norm of the difference of the FP of the current reconstruction + // and the sinogram. (This performs one FP.) + // It can be called after iterate. + float computeDiffNorm(); + +protected: + void reset(); + bool precomputeWeights(); + + bool useVolumeMask; + bool useSinogramMask; + + bool useMinConstraint; + bool useMaxConstraint; + float fMinConstraint; + float fMaxConstraint; + + cudaPitchedPtr D_maskData; + cudaPitchedPtr D_smaskData; + + // Input/output + cudaPitchedPtr D_sinoData; + cudaPitchedPtr D_volumeData; + + // Temporary buffers + cudaPitchedPtr D_projData; + cudaPitchedPtr D_tmpData; + + // Geometry-specific precomputed data + cudaPitchedPtr D_lineWeight; + cudaPitchedPtr D_pixelWeight; +}; + +bool doSIRT(cudaPitchedPtr D_volumeData, unsigned int volumePitch, + cudaPitchedPtr D_projData, unsigned int projPitch, + cudaPitchedPtr D_maskData, unsigned int maskPitch, + const SDimensions3D& dims, const SConeProjection* projs, + unsigned int iterations); + +} + +#endif diff --git a/cuda/3d/util3d.cu b/cuda/3d/util3d.cu new file mode 100644 index 0000000..81ea823 --- /dev/null +++ b/cuda/3d/util3d.cu @@ -0,0 +1,514 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <cstdio> +#include <cassert> +#include "util3d.h" +#include "../2d/util.h" + +namespace astraCUDA3d { + + +cudaPitchedPtr allocateVolumeData(const SDimensions3D& dims) +{ + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPitchedPtr volData; + + cudaError err = cudaMalloc3D(&volData, extentV); + if (err != cudaSuccess) { + astraCUDA::reportCudaError(err); + fprintf(stderr, "Failed to allocate %dx%dx%d GPU buffer\n", dims.iVolX, dims.iVolY, dims.iVolZ); + volData.ptr = 0; + // TODO: return 0 somehow? + } + + return volData; +} +cudaPitchedPtr allocateProjectionData(const SDimensions3D& dims) +{ + cudaExtent extentP; + extentP.width = dims.iProjU*sizeof(float); + extentP.height = dims.iProjAngles; + extentP.depth = dims.iProjV; + + cudaPitchedPtr projData; + + cudaError err = cudaMalloc3D(&projData, extentP); + if (err != cudaSuccess) { + astraCUDA::reportCudaError(err); + fprintf(stderr, "Failed to allocate %dx%dx%d GPU buffer\n", dims.iProjU, dims.iProjAngles, dims.iProjV); + projData.ptr = 0; + // TODO: return 0 somehow? + } + + return projData; +} +bool zeroVolumeData(cudaPitchedPtr& D_data, const SDimensions3D& dims) +{ + char* t = (char*)D_data.ptr; + cudaError err; + + for (unsigned int z = 0; z < dims.iVolZ; ++z) { + err = cudaMemset2D(t, D_data.pitch, 0, dims.iVolX*sizeof(float), dims.iVolY); + ASTRA_CUDA_ASSERT(err); + t += D_data.pitch * dims.iVolY; + } + return true; +} +bool zeroProjectionData(cudaPitchedPtr& D_data, const SDimensions3D& dims) +{ + char* t = (char*)D_data.ptr; + cudaError err; + + for (unsigned int z = 0; z < dims.iProjV; ++z) { + err = cudaMemset2D(t, D_data.pitch, 0, dims.iProjU*sizeof(float), dims.iProjAngles); + ASTRA_CUDA_ASSERT(err); + t += D_data.pitch * dims.iProjAngles; + } + + return true; +} +bool copyVolumeToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch) +{ + if (!pitch) + pitch = dims.iVolX; + + cudaPitchedPtr ptr; + ptr.ptr = (void*)data; // const cast away + ptr.pitch = pitch*sizeof(float); + ptr.xsize = dims.iVolX*sizeof(float); + ptr.ysize = dims.iVolY; + + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPos zp = { 0, 0, 0 }; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = zp; + p.dstPtr = D_data; + p.extent = extentV; + p.kind = cudaMemcpyHostToDevice; + + cudaError err; + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + return err == cudaSuccess; +} + +bool copyProjectionsToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch) +{ + if (!pitch) + pitch = dims.iProjU; + + cudaPitchedPtr ptr; + ptr.ptr = (void*)data; // const cast away + ptr.pitch = pitch*sizeof(float); + ptr.xsize = dims.iProjU*sizeof(float); + ptr.ysize = dims.iProjAngles; + + cudaExtent extentV; + extentV.width = dims.iProjU*sizeof(float); + extentV.height = dims.iProjAngles; + extentV.depth = dims.iProjV; + + cudaPos zp = { 0, 0, 0 }; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = ptr; + p.dstArray = 0; + p.dstPos = zp; + p.dstPtr = D_data; + p.extent = extentV; + p.kind = cudaMemcpyHostToDevice; + + cudaError err; + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + return err == cudaSuccess; +} + +bool copyVolumeFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch) +{ + if (!pitch) + pitch = dims.iVolX; + + cudaPitchedPtr ptr; + ptr.ptr = data; + ptr.pitch = pitch*sizeof(float); + ptr.xsize = dims.iVolX*sizeof(float); + ptr.ysize = dims.iVolY; + + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPos zp = { 0, 0, 0 }; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = D_data; + p.dstArray = 0; + p.dstPos = zp; + p.dstPtr = ptr; + p.extent = extentV; + p.kind = cudaMemcpyDeviceToHost; + + cudaError err; + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + return err == cudaSuccess; +} +bool copyProjectionsFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch) +{ + if (!pitch) + pitch = dims.iProjU; + + cudaPitchedPtr ptr; + ptr.ptr = data; + ptr.pitch = pitch*sizeof(float); + ptr.xsize = dims.iProjU*sizeof(float); + ptr.ysize = dims.iProjAngles; + + cudaExtent extentV; + extentV.width = dims.iProjU*sizeof(float); + extentV.height = dims.iProjAngles; + extentV.depth = dims.iProjV; + + cudaPos zp = { 0, 0, 0 }; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = D_data; + p.dstArray = 0; + p.dstPos = zp; + p.dstPtr = ptr; + p.extent = extentV; + p.kind = cudaMemcpyDeviceToHost; + + cudaError err; + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + return err == cudaSuccess; +} + +bool duplicateVolumeData(cudaPitchedPtr& D_dst, const cudaPitchedPtr& D_src, const SDimensions3D& dims) +{ + cudaExtent extentV; + extentV.width = dims.iVolX*sizeof(float); + extentV.height = dims.iVolY; + extentV.depth = dims.iVolZ; + + cudaPos zp = { 0, 0, 0 }; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = D_src; + p.dstArray = 0; + p.dstPos = zp; + p.dstPtr = D_dst; + p.extent = extentV; + p.kind = cudaMemcpyDeviceToDevice; + + cudaError err; + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + return err == cudaSuccess; +} +bool duplicateProjectionData(cudaPitchedPtr& D_dst, const cudaPitchedPtr& D_src, const SDimensions3D& dims) +{ + cudaExtent extentV; + extentV.width = dims.iProjU*sizeof(float); + extentV.height = dims.iProjAngles; + extentV.depth = dims.iProjV; + + cudaPos zp = { 0, 0, 0 }; + + cudaMemcpy3DParms p; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = D_src; + p.dstArray = 0; + p.dstPos = zp; + p.dstPtr = D_dst; + p.extent = extentV; + p.kind = cudaMemcpyDeviceToDevice; + + cudaError err; + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + return err == cudaSuccess; +} + + + +// TODO: Consider using a single array of size max(proj,volume) (per dim) +// instead of allocating a new one each time + +// TODO: Figure out a faster way of zeroing the padding? + +cudaArray* allocateVolumeArray(const SDimensions3D& dims) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + cudaArray* cuArray; + cudaExtent extentA; + extentA.width = dims.iVolX+2; + extentA.height = dims.iVolY+2; + extentA.depth = dims.iVolZ+2; + cudaError err = cudaMalloc3DArray(&cuArray, &channelDesc, extentA); + if (err != cudaSuccess) { + astraCUDA::reportCudaError(err); + fprintf(stderr, "Failed to allocate %dx%dx%d GPU array\n", dims.iVolX, dims.iVolY, dims.iVolZ); + return 0; + } + + zeroVolumeArray(cuArray, dims); + + return cuArray; +} +cudaArray* allocateProjectionArray(const SDimensions3D& dims) +{ + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>(); + cudaArray* cuArray; + cudaExtent extentA; + extentA.width = dims.iProjU+2; + extentA.height = dims.iProjAngles; + extentA.depth = dims.iProjV+2; + cudaError err = cudaMalloc3DArray(&cuArray, &channelDesc, extentA); + + if (err != cudaSuccess) { + astraCUDA::reportCudaError(err); + fprintf(stderr, "Failed to allocate %dx%dx%d GPU array\n", dims.iProjU, dims.iProjAngles, dims.iProjV); + return 0; + } + + zeroProjectionArray(cuArray, dims); + + return cuArray; +} +bool zeroVolumeArray(cudaArray* array, const SDimensions3D& dims) +{ + cudaPitchedPtr zeroBuf; + cudaExtent extentS; + extentS.width = sizeof(float)*(dims.iVolX+2); + extentS.height = dims.iVolY+2; + extentS.depth = 1; + + cudaExtent extentA; + extentA.width = dims.iVolX+2; + extentA.height = dims.iVolY+2; + extentA.depth = 1; + + + + cudaError err; + err = cudaMalloc3D(&zeroBuf, extentS); + ASTRA_CUDA_ASSERT(err); + err = cudaMemset2D(zeroBuf.ptr, zeroBuf.pitch, 0, sizeof(float)*(dims.iVolX+2), dims.iVolY+2); + ASTRA_CUDA_ASSERT(err); + + // zero array + for (unsigned int i = 0; i < dims.iVolZ+2; ++i) { + cudaMemcpy3DParms p; + cudaPos zp = {0, 0, 0}; + cudaPos dp = {0, 0, i}; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = zeroBuf; + p.dstArray = array; + p.dstPtr.ptr = 0; + p.dstPtr.pitch = 0; + p.dstPtr.xsize = 0; + p.dstPtr.ysize = 0; + p.dstPos = dp; + p.extent = extentA; + p.kind = cudaMemcpyDeviceToDevice; + + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + } + cudaFree(zeroBuf.ptr); + + // TODO: check errors + + return true; +} +bool zeroProjectionArray(cudaArray* array, const SDimensions3D& dims) +{ + cudaPitchedPtr zeroBuf; + cudaExtent extentS; + extentS.width = sizeof(float)*(dims.iProjU+2); + extentS.height = dims.iProjAngles; + extentS.depth = 1; + cudaExtent extentA; + extentA.width = dims.iProjU+2; + extentA.height = dims.iProjAngles; + extentA.depth = 1; + + + cudaError err; + err = cudaMalloc3D(&zeroBuf, extentS); + ASTRA_CUDA_ASSERT(err); + err = cudaMemset2D(zeroBuf.ptr, zeroBuf.pitch, 0, sizeof(float)*(dims.iProjU+2), dims.iProjAngles); + ASTRA_CUDA_ASSERT(err); + + for (unsigned int i = 0; i < dims.iProjV+2; ++i) { + cudaMemcpy3DParms p; + cudaPos zp = {0, 0, 0}; + cudaPos dp = {0, 0, i}; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = zeroBuf; + p.dstArray = array; + p.dstPtr.ptr = 0; + p.dstPtr.pitch = 0; + p.dstPtr.xsize = 0; + p.dstPtr.ysize = 0; + p.dstPos = dp; + p.extent = extentA; + p.kind = cudaMemcpyDeviceToDevice; + + err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + } + cudaFree(zeroBuf.ptr); + + // TODO: check errors + return true; +} + + +bool transferVolumeToArray(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims) +{ + cudaExtent extentA; + extentA.width = dims.iVolX; + extentA.height = dims.iVolY; + extentA.depth = dims.iVolZ; + + cudaMemcpy3DParms p; + cudaPos zp = {0, 0, 0}; + cudaPos dp = {1, 1, 1}; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = D_volumeData; + p.dstArray = array; + p.dstPtr.ptr = 0; + p.dstPtr.pitch = 0; + p.dstPtr.xsize = 0; + p.dstPtr.ysize = 0; + p.dstPos = dp; + p.extent = extentA; + p.kind = cudaMemcpyDeviceToDevice; + + cudaError err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + // TODO: check errors + + return true; +} +bool transferProjectionsToArray(cudaPitchedPtr D_projData, cudaArray* array, const SDimensions3D& dims) +{ + cudaExtent extentA; + extentA.width = dims.iProjU; + extentA.height = dims.iProjAngles; + extentA.depth = dims.iProjV; + + cudaMemcpy3DParms p; + cudaPos zp = {0, 0, 0}; + cudaPos dp = {1, 0, 1}; + p.srcArray = 0; + p.srcPos = zp; + p.srcPtr = D_projData; + p.dstArray = array; + p.dstPtr.ptr = 0; + p.dstPtr.pitch = 0; + p.dstPtr.xsize = 0; + p.dstPtr.ysize = 0; + p.dstPos = dp; + p.extent = extentA; + p.kind = cudaMemcpyDeviceToDevice; + + cudaError err = cudaMemcpy3D(&p); + ASTRA_CUDA_ASSERT(err); + + // TODO: check errors + + return true; +} + + +float dotProduct3D(cudaPitchedPtr data, unsigned int x, unsigned int y, + unsigned int z) +{ + return astraCUDA::dotProduct2D((float*)data.ptr, data.pitch/sizeof(float), x, y*z, 0, 0); +} + + +bool cudaTextForceKernelsCompletion() +{ + cudaError_t returnedCudaError = cudaThreadSynchronize(); + + if(returnedCudaError != cudaSuccess) { + fprintf(stderr, "Failed to force completion of cuda kernels: %d: %s.\n", returnedCudaError, cudaGetErrorString(returnedCudaError)); + return false; + } + + return true; +} + +int calcNextPowerOfTwo(int _iValue) +{ + int iOutput = 1; + while(iOutput < _iValue) + iOutput *= 2; + return iOutput; +} + +} diff --git a/cuda/3d/util3d.h b/cuda/3d/util3d.h new file mode 100644 index 0000000..cf04a18 --- /dev/null +++ b/cuda/3d/util3d.h @@ -0,0 +1,69 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _CUDA_UTIL3D_H +#define _CUDA_UTIL3D_H + +#include <cuda.h> +#include "dims3d.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#include "../2d/util.h" + +namespace astraCUDA3d { + +cudaPitchedPtr allocateVolumeData(const SDimensions3D& dims); +cudaPitchedPtr allocateProjectionData(const SDimensions3D& dims); +bool zeroVolumeData(cudaPitchedPtr& D_data, const SDimensions3D& dims); +bool zeroProjectionData(cudaPitchedPtr& D_data, const SDimensions3D& dims); +bool copyVolumeToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0); +bool copyProjectionsToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0); +bool copyVolumeFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0); +bool copyProjectionsFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0); +bool duplicateVolumeData(cudaPitchedPtr& D_dest, const cudaPitchedPtr& D_src, const SDimensions3D& dims); +bool duplicateProjectionData(cudaPitchedPtr& D_dest, const cudaPitchedPtr& D_src, const SDimensions3D& dims); + + +bool transferProjectionsToArray(cudaPitchedPtr D_projData, cudaArray* array, const SDimensions3D& dims); +bool transferVolumeToArray(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims); +bool zeroProjectionArray(cudaArray* array, const SDimensions3D& dims); +bool zeroVolumeArray(cudaArray* array, const SDimensions3D& dims); +cudaArray* allocateProjectionArray(const SDimensions3D& dims); +cudaArray* allocateVolumeArray(const SDimensions3D& dims); + +bool cudaTextForceKernelsCompletion(); + +float dotProduct3D(cudaPitchedPtr data, unsigned int x, unsigned int y, unsigned int z); + +int calcNextPowerOfTwo(int _iValue); + +} + +#endif diff --git a/include/astra/Algorithm.h b/include/astra/Algorithm.h new file mode 100644 index 0000000..d4c73f9 --- /dev/null +++ b/include/astra/Algorithm.h @@ -0,0 +1,135 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_ALGORITHM +#define _INC_ASTRA_ALGORITHM + +#include <boost/any.hpp> + +#include "Globals.h" +#include "Config.h" + +namespace astra { + +/** + * This class contains the interface for an algorithm implementation. + */ +class _AstraExport CAlgorithm { + +public: + + /** Default constructor, containing no code. + */ + CAlgorithm(); + + /** Destructor. + */ + virtual ~CAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg) = 0; + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0) = 0; + + /** Has this class been initialized? + * + * @return initialized + */ + bool isInitialized(); + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const; + + /** Signal the algorithm it should abort soon. + * This is intended to be called from a different thread + * while the algorithm is running. There are no guarantees + * on how soon the algorithm will abort. The state of the + * algorithm object will be consistent (so it is safe to delete it + * normally afterwards), but the algorithm's output is undefined. + * + * Note that specific algorithms may give guarantees on their + * state after an abort. Check their documentation for details. + */ + virtual void signalAbort() { m_bShouldAbort = true; } + +protected: + + //< Has this class been initialized? + bool m_bIsInitialized; + + //< If this is set, the algorithm should try to abort as soon as possible. + volatile bool m_bShouldAbort; + +private: + /** + * Private copy constructor to prevent CAlgorithms from being copied. + */ + CAlgorithm(const CAlgorithm&); + + /** + * Private assignment operator to prevent CAlgorithms from being copied. + */ + CAlgorithm& operator=(const CAlgorithm&); + + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CAlgorithm>; + +}; + +// inline functions +inline std::string CAlgorithm::description() const { return "Algorithm"; }; +inline bool CAlgorithm::isInitialized() { return m_bIsInitialized; } + +} // end namespace + +#endif diff --git a/include/astra/AlgorithmTypelist.h b/include/astra/AlgorithmTypelist.h new file mode 100644 index 0000000..615c143 --- /dev/null +++ b/include/astra/AlgorithmTypelist.h @@ -0,0 +1,108 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_ALGORITHMTYPELIST +#define _INC_ASTRA_ALGORITHMTYPELIST + +#include "Algorithm.h" +#include "TypeList.h" + +#include "ArtAlgorithm.h" +#include "SirtAlgorithm.h" +#include "SartAlgorithm.h" +#include "ForwardProjectionAlgorithm.h" +#include "BackProjectionAlgorithm.h" +#include "FilteredBackProjectionAlgorithm.h" +#include "CudaBackProjectionAlgorithm.h" +#include "CudaSartAlgorithm.h" +#include "CudaSirtAlgorithm.h" +#include "CudaCglsAlgorithm.h" +#include "CudaEMAlgorithm.h" +#include "CudaForwardProjectionAlgorithm.h" +#include "CglsAlgorithm.h" +#include "CudaCglsAlgorithm3D.h" +#include "CudaSirtAlgorithm3D.h" +#include "CudaForwardProjectionAlgorithm3D.h" +#include "CudaBackProjectionAlgorithm3D.h" +#include "CudaFDKAlgorithm3D.h" +#include "CudaDartMaskAlgorithm.h" +#include "CudaDartMaskAlgorithm3D.h" +#include "CudaDartSmoothingAlgorithm.h" +#include "CudaDartSmoothingAlgorithm3D.h" +#include "CudaDataOperationAlgorithm.h" +#include "CudaRoiSelectAlgorithm.h" + +using namespace astra; + +#ifdef ASTRA_CUDA + +#include "CudaFilteredBackProjectionAlgorithm.h" + +typedef TYPELIST_25( + CArtAlgorithm, + CSartAlgorithm, + CSirtAlgorithm, + CCglsAlgorithm, + CBackProjectionAlgorithm, + CForwardProjectionAlgorithm, + CCudaSartAlgorithm, + CFilteredBackProjectionAlgorithm, + CCudaBackProjectionAlgorithm, + CCudaDartMaskAlgorithm, + CCudaDartMaskAlgorithm3D, + CCudaDartSmoothingAlgorithm, + CCudaDartSmoothingAlgorithm3D, + CCudaDataOperationAlgorithm, + CCudaRoiSelectAlgorithm, + CCudaSirtAlgorithm, + CCudaCglsAlgorithm, + CCudaEMAlgorithm, + CCudaForwardProjectionAlgorithm, + CCudaCglsAlgorithm3D, + CCudaFilteredBackProjectionAlgorithm, + CCudaFDKAlgorithm3D, + CCudaSirtAlgorithm3D, + CCudaForwardProjectionAlgorithm3D, + CCudaBackProjectionAlgorithm3D + ) + AlgorithmTypeList; +#else + +typedef TYPELIST_7( + CArtAlgorithm, + CSartAlgorithm, + CSirtAlgorithm, + CCglsAlgorithm, + CBackProjectionAlgorithm, + CForwardProjectionAlgorithm, + CFilteredBackProjectionAlgorithm + ) AlgorithmTypeList; + +#endif + +#endif diff --git a/include/astra/ArtAlgorithm.h b/include/astra/ArtAlgorithm.h new file mode 100644 index 0000000..bd02fc4 --- /dev/null +++ b/include/astra/ArtAlgorithm.h @@ -0,0 +1,196 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_ARTALGORITHM +#define _INC_ASTRA_ARTALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" +#include "ReconstructionAlgorithm2D.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +namespace astra { + +/** + * This class contains the implementation of the ART (Algebraic Reconstruction Technique) algorithm. + * + * The update step of pixel \f$v_j\f$ for ray \f$i\f$ and iteration \f$k\f$ is given by: + * \f[ + * v_j^{(k+1)} = v_j^{(k)} + \lambda \frac{p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}}{\sum_{k=1}^{N} w_{ik}^2} + * \f] + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.} + * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.} + * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} + * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} + * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + * \astra_xml_item_option{Lamda, float, 1, The relaxation factor.} + * \astra_xml_item_option{RayOrder, string, "sequential", the order in which the rays are updated. 'sequential' or 'custom'} + * \astra_xml_item_option{RayOrderList, n by 2 vector of float, not used, if RayOrder='custom': use this ray order. Each row consist of a projection id and detector id.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('ART');\n + * cfg.ProjectorId = proj_id;\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.MaskId = mask_id;\n + * cfg.option.UseMinConstraint = 'yes';\n + * cfg.option.UseMaxConstraint = 'yes';\n + * cfg.option.MaxConstraintValue = 1024;\n + * cfg.option.Lamda = 0.7;\n + * cfg.option.RayOrder = 'custom';\n + * cfg.option.RayOrderList = [0\,0; 0\,2; 1\,0];\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 1000);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + */ +class _AstraExport CArtAlgorithm : public CReconstructionAlgorithm2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - the projector is compatible with both data objects + * - the ray order list only contains valid values + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CArtAlgorithm(); + + /** Destructor. + */ + virtual ~CArtAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential ray order. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Clear this class. + */ + virtual void clear(); + + /** Set the relaxation factor. + * + * @param _fLambda Relaxation factor + */ + void setLambda(float32 _fLambda); + + /** Set the order in which the rays will be selected + * + * @param _piProjectionOrder Order of the rays, the projections. (size should be _piRayCount) + * @param _piDetectorOrder Order of the rays, the detectors. (size should be _piRayCount) + * @param _piRayCount Number of rays in the two previous arrays. + */ + void setRayOrder(int* _piProjectionOrder, int* _piDetectorOrder, int _piRayCount); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +protected: + + //< Relaxation Factor + float32 m_fLambda; + + //< Order of the rays, the projections. + int* m_piProjectionOrder; + //< Order of the rays, the detectors. + int* m_piDetectorOrder; + //< Number of rays specified in the ray order arrays. + int m_iRayCount; + //< Current index in the ray order arrays. + int m_iCurrentRay; + +}; + +// inline functions +inline std::string CArtAlgorithm::description() const { return CArtAlgorithm::type; }; + + +} // end namespace + +#endif diff --git a/include/astra/AstraObjectFactory.h b/include/astra/AstraObjectFactory.h new file mode 100644 index 0000000..784d698 --- /dev/null +++ b/include/astra/AstraObjectFactory.h @@ -0,0 +1,149 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_ASTRAOBJECTFACTORY +#define _INC_ASTRA_ASTRAOBJECTFACTORY + +#include "Globals.h" +#include "Config.h" +#include "Singleton.h" +#include "Utilities.h" +#include "TypeList.h" + +#include "ProjectorTypelist.h" + + +#include "AlgorithmTypelist.h" + + +namespace astra { + +/** + * This class contains functionality to create data objects based on their type or on a configuration object. + */ +template <typename T, typename TypeList> +class CAstraObjectFactory : public Singleton<CAstraObjectFactory<T, TypeList> > { + +public: + + /** A default constructor that contains not a single line of code. + */ + CAstraObjectFactory(); + + /** Destructor. + */ + ~CAstraObjectFactory(); + + /** Create, but don't initialize, a new projector object. + * + * @param _sType Type of the new projector. + * @return Pointer to a new, unitialized projector. + */ + T* create(std::string _sType); + + /** Create and initialize a new projector object. + * + * @param _cfg Configuration object to create and initialize a new projector. + * @return Pointer to a new, initialized projector. + */ + T* create(const Config& _cfg); + + +}; + + +//---------------------------------------------------------------------------------------- +// Constructor +template <typename T, typename TypeList> +CAstraObjectFactory<T, TypeList>::CAstraObjectFactory() +{ + +} + +//---------------------------------------------------------------------------------------- +// Destructor +template <typename T, typename TypeList> +CAstraObjectFactory<T, TypeList>::~CAstraObjectFactory() +{ + +} + +//---------------------------------------------------------------------------------------- +// Create +template <typename T, typename TypeList> +T* CAstraObjectFactory<T, TypeList>::create(std::string _sType) +{ + functor_find<T> finder = functor_find<T>(); + finder.tofind = _sType; + CreateObject<TypeList>::find(finder); + return finder.res; +} + +//---------------------------------------------------------------------------------------- +// Create with XML +template <typename T, typename TypeList> +T* CAstraObjectFactory<T, TypeList>::create(const Config& _cfg) +{ + functor_find<T> finder = functor_find<T>(); + finder.tofind = _cfg.self->getAttribute("type"); + CreateObject<TypeList>::find(finder); + if (finder.res == NULL) return NULL; + if (finder.res->initialize(_cfg)) + return finder.res; + + delete finder.res; + return NULL; +} +//---------------------------------------------------------------------------------------- + + + + +//---------------------------------------------------------------------------------------- +// Create the necessary Object Managers +/** + * Class used to create algorithms from a string or a config object +*/ +class _AstraExport CAlgorithmFactory : public CAstraObjectFactory<CAlgorithm, AlgorithmTypeList> {}; + +/** + * Class used to create 2D projectors from a string or a config object +*/ +class _AstraExport CProjector2DFactory : public CAstraObjectFactory<CProjector2D, Projector2DTypeList> {}; + +/** + * Class used to create 3D projectors from a string or a config object +*/ +class _AstraExport CProjector3DFactory : public CAstraObjectFactory<CProjector3D, Projector3DTypeList> {}; + + + + +} // end namespace + +#endif diff --git a/include/astra/AstraObjectManager.h b/include/astra/AstraObjectManager.h new file mode 100644 index 0000000..afb6312 --- /dev/null +++ b/include/astra/AstraObjectManager.h @@ -0,0 +1,290 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_ASTRAOBJECTMANAGER +#define _INC_ASTRA_ASTRAOBJECTMANAGER + +#include <map> +#include <sstream> + +#include "Globals.h" +#include "Singleton.h" +#include "Projector2D.h" +#include "Projector3D.h" +#include "Float32Data2D.h" +#include "Float32Data3D.h" +#include "SparseMatrix.h" +#include "Algorithm.h" + +namespace astra { + +/** + * This class contains functionality to store objects. A unique index handle + * will be assigned to each data object by which it can be accessed in the + * future. Indices are always >= 1. + * + * We store them in a special common base class to make indices unique + * among all ObjectManagers. + */ + + +class CAstraIndexManager { +protected: + /** The index of the previously stored data object. + */ + static int m_iPreviousIndex; +}; + + +template <typename T> +class CAstraObjectManager : public Singleton<CAstraObjectManager<T> >, CAstraIndexManager { + +public: + + /** Default constructor. + */ + CAstraObjectManager(); + + /** Destructor. + */ + ~CAstraObjectManager(); + + /** Store the object in the manager and assign a unique index handle to it. + * + * @param _pObject A pointer to the object that should be stored. + * @return The index of the stored data object. If the index in negative, an error occurred + * and the object was NOT stored. + */ + int store(T* _pObject); + + /** Does the manager contain an object with the index _iIndex? + * + * @param _iIndex Index handle to the data object in question. + * @return True if the manager contains an object with the index handle _iIndex. + */ + bool hasIndex(int _iIndex) const; + + /** Fetch the object to which _iIndex refers to. + * + * @param _iIndex Index handle to the data object in question. + * @return Pointer to the stored data object. A null pointer is returned if no object with index _iIndex is found. + */ + T* get(int _iIndex) const; + + /** Delete an object that was previously stored. This actually DELETES the objecy. Therefore, after this + * function call, the object in question will have passed on. It will be no more. It will have ceased + * to be. It will be expired and will go to meet its maker. Bereft of life, it will rest in peace. + * It will be an EX-OBJECT. + * + * @param _iIndex Index handle to the object in question. + * @return Error code. 0 for success. + */ + void remove(int _iIndex); + + /** Get the index of the object, zero if it doesn't exist. + * + * @param _pObject The data object. + * @return Index of the stored object, 0 if not found. + */ + int getIndex(const T* _pObject) const; + + /** Clear all data. This will also delete all the content of each object. + */ + void clear(); + + /** Get info. + */ + std::string info(); + +protected: + + /** Map each data object to a unique index. + */ + std::map<int, T*> m_mIndexToObject; + +}; + +//---------------------------------------------------------------------------------------- +// Constructor +template <typename T> +CAstraObjectManager<T>::CAstraObjectManager() +{ +} + +//---------------------------------------------------------------------------------------- +// Destructor +template <typename T> +CAstraObjectManager<T>::~CAstraObjectManager() +{ + +} + +//---------------------------------------------------------------------------------------- +// store data +template <typename T> +int CAstraObjectManager<T>::store(T* _pDataObject) +{ + m_iPreviousIndex++; + m_mIndexToObject[m_iPreviousIndex] = _pDataObject; + return m_iPreviousIndex; +} + +//---------------------------------------------------------------------------------------- +// has data? +template <typename T> +bool CAstraObjectManager<T>::hasIndex(int _iIndex) const +{ + typename map<int,T*>::const_iterator it = m_mIndexToObject.find(_iIndex); + return it != m_mIndexToObject.end(); +} + +//---------------------------------------------------------------------------------------- +// get data +template <typename T> +T* CAstraObjectManager<T>::get(int _iIndex) const +{ + typename map<int,T*>::const_iterator it = m_mIndexToObject.find(_iIndex); + if (it != m_mIndexToObject.end()) + return it->second; + else + return 0; +} + +//---------------------------------------------------------------------------------------- +// delete data +template <typename T> +void CAstraObjectManager<T>::remove(int _iIndex) +{ + if (!hasIndex(_iIndex)) { + return; + } + // find data + typename map<int,T*>::iterator it = m_mIndexToObject.find(_iIndex); + // delete data + delete (*it).second; + // delete from map + m_mIndexToObject.erase(it); +} + +//---------------------------------------------------------------------------------------- +// Get Index +template <typename T> +int CAstraObjectManager<T>::getIndex(const T* _pObject) const +{ + for (typename map<int,T*>::const_iterator it = m_mIndexToObject.begin(); it != m_mIndexToObject.end(); it++) { + if ((*it).second == _pObject) return (*it).first; + } + return 0; +} + + +//---------------------------------------------------------------------------------------- +// clear +template <typename T> +void CAstraObjectManager<T>::clear() +{ + for (typename map<int,T*>::iterator it = m_mIndexToObject.begin(); it != m_mIndexToObject.end(); it++) { + // delete data + delete (*it).second; + (*it).second = 0; + } + + m_mIndexToObject.clear(); +} + +//---------------------------------------------------------------------------------------- +// Print info to string +template <typename T> +std::string CAstraObjectManager<T>::info() { + std::stringstream res; + res << "id init description" << std::endl; + res << "-----------------------------------------" << std::endl; + for (typename map<int,T*>::iterator it = m_mIndexToObject.begin(); it != m_mIndexToObject.end(); it++) { + res << (*it).first << " \t"; + T* pObject = m_mIndexToObject[(*it).first]; + if (pObject->isInitialized()) { + res << "v "; + } else { + res << "x "; + } + res << pObject->description() << endl; + } + res << "-----------------------------------------" << std::endl; + return res.str(); +} + + + +//---------------------------------------------------------------------------------------- +// Create the necessary Object Managers +/** + * This class contains functionality to store 2D projector objects. A unique index handle will be + * assigned to each data object by which it can be accessed in the future. + * Indices are always >= 1. + */ +class _AstraExport CProjector2DManager : public CAstraObjectManager<CProjector2D>{}; + +/** + * This class contains functionality to store 3D projector objects. A unique index handle will be + * assigned to each data object by which it can be accessed in the future. + * Indices are always >= 1. + */ +class _AstraExport CProjector3DManager : public CAstraObjectManager<CProjector3D>{}; + +/** + * This class contains functionality to store 2D data objects. A unique index handle will be + * assigned to each data object by which it can be accessed in the future. + * Indices are always >= 1. + */ +class _AstraExport CData2DManager : public CAstraObjectManager<CFloat32Data2D>{}; + +/** + * This class contains functionality to store 3D data objects. A unique index handle will be + * assigned to each data object by which it can be accessed in the future. + * Indices are always >= 1. + */ +class _AstraExport CData3DManager : public CAstraObjectManager<CFloat32Data3D>{}; + +/** + * This class contains functionality to store algorithm objects. A unique index handle will be + * assigned to each data object by which it can be accessed in the future. + * Indices are always >= 1. + */ +class _AstraExport CAlgorithmManager : public CAstraObjectManager<CAlgorithm>{}; + +/** + * This class contains functionality to store matrix objects. A unique index handle will be + * assigned to each data object by which it can be accessed in the future. + * Indices are always >= 1. + */ +class _AstraExport CMatrixManager : public CAstraObjectManager<CSparseMatrix>{}; + + +} // end namespace + +#endif diff --git a/include/astra/AsyncAlgorithm.h b/include/astra/AsyncAlgorithm.h new file mode 100644 index 0000000..64f70c3 --- /dev/null +++ b/include/astra/AsyncAlgorithm.h @@ -0,0 +1,128 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_ASYNCALGORITHM +#define _INC_ASTRA_ASYNCALGORITHM + +#include "Config.h" +#include "Algorithm.h" + +#ifdef __linux__ +#define USE_PTHREADS +#include <pthread.h> +#else +#include <boost/thread.hpp> +#endif + + +namespace astra { + +/** + * \brief + * This class contains an wrapper algorithm that allows termination of its wrapped algorithm. + * + * This is used to allow algorithm termination from matlab command line. + */ + +class _AstraExport CAsyncAlgorithm : public CAlgorithm { +public: + /** Default constructor, containing no code. + */ + CAsyncAlgorithm(); + + /** Constructor. + */ + explicit CAsyncAlgorithm(CAlgorithm* _pAlg); + + /** Destructor. + */ + virtual ~CAsyncAlgorithm(); + + /** Initialize using config object. + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize using algorithm pointer. + */ + virtual bool initialize(CAlgorithm* _pAlg); + + /** Run the algorithm. + */ + virtual void run(int _iNrIterations = 0); + + /** Wait for thread to complete and delete thread. + */ + virtual void timedJoin(int _milliseconds); + + /** Return pointer to the wrapped algorithm. + */ + CAlgorithm* getWrappedAlgorithm() { return m_pAlg; } + + /** Is the wrapped algorithm done. + */ + bool isDone() const { return m_bDone; } + + /** Signal abort to the wrapped algorithm. + */ + void signalAbort(); + +protected: + //< Has this class been initialized? + bool m_bInitialized; + + //< Should wrapped algorithm be deleted after completion? + bool m_bAutoFree; + + //< Pointer to wrapped algorithm. + CAlgorithm* m_pAlg; + + //< Is the wrapped algorithm done. + volatile bool m_bDone; + +#ifndef USE_PTHREADS + //< Handle to boost thread object running the wrapped algorithm. + boost::thread* m_pThread; +#else + pthread_t m_thread; + struct AsyncThreadInfo { + int m_iIterations; + CAlgorithm* m_pAlg; + volatile bool* m_pDone; + } m_ThreadInfo; + friend void* runAsync_pthreads(void*); +#endif + bool m_bThreadStarted; + + //< Run the wrapped algorithm. + void runWrapped(int _iNrIterations); + +}; + +} + +#endif diff --git a/include/astra/BackProjectionAlgorithm.h b/include/astra/BackProjectionAlgorithm.h new file mode 100644 index 0000000..d50b406 --- /dev/null +++ b/include/astra/BackProjectionAlgorithm.h @@ -0,0 +1,155 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_BACKPROJECTIONALGORITHM +#define _INC_ASTRA_BACKPROJECTIONALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" +#include "ReconstructionAlgorithm2D.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +#include "DataProjector.h" + +namespace astra { + +/** + * \brief + * This class performs an unfiltered backprojection. + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.} + * + */ +class _AstraExport CBackProjectionAlgorithm : public CReconstructionAlgorithm2D { + +protected: + + /** Init stuff + */ + virtual void _init(); + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - valid projector + * - valid data objects + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CBackProjectionAlgorithm(); + + /** Default constructor + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + CBackProjectionAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Destructor. + */ + virtual ~CBackProjectionAlgorithm(); + + /** Clear this class. + */ + virtual void clear(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return Initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @return Initialization successful? + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Get all information parameters. + * + * @return Map with all available identifier strings and their values. + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier Identifier string to specify which piece of information you want. + * @return One piece of information. + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +}; + +// inline functions +inline std::string CBackProjectionAlgorithm::description() const { return CBackProjectionAlgorithm::type; }; + + +} // end namespace + +#endif diff --git a/include/astra/CglsAlgorithm.h b/include/astra/CglsAlgorithm.h new file mode 100644 index 0000000..1700d74 --- /dev/null +++ b/include/astra/CglsAlgorithm.h @@ -0,0 +1,182 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CGLSALGORITHM +#define _INC_ASTRA_CGLSALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" +#include "ReconstructionAlgorithm2D.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +#include "DataProjector.h" + +namespace astra { + +/** + * \brief + * This class contains the implementation of the CGLS (Conguent Gradient Algorithm) algorithm. + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 0 = reconstruct using this ray. 1 = don't use this ray while reconstructing.} + * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.} + * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} + * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} + * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('CGLS');\n + * cfg.ProjectorId = proj_id;\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.MaskId = mask_id;\n + * cfg.option.UseMinConstraint = 'yes';\n + * cfg.option.UseMaxConstraint = 'yes';\n + * cfg.option.MaxConstraintValue = 1024;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 10);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ +class _AstraExport CCglsAlgorithm : public CReconstructionAlgorithm2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - valid projector + * - valid data objects + */ + virtual bool _check(); + + CFloat32ProjectionData2D* r; + CFloat32ProjectionData2D* w; + CFloat32VolumeData2D* z; + CFloat32VolumeData2D* p; + + float32 alpha; + float32 beta; + float32 gamma; + + + int m_iIteration; + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCglsAlgorithm(); + + /** Default constructor + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + CCglsAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Destructor. + */ + virtual ~CCglsAlgorithm(); + + /** Clear this class. + */ + virtual void clear(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return Initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @return Initialization successful? + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Get all information parameters. + * + * @return Map with all available identifier strings and their values. + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier Identifier string to specify which piece of information you want. + * @return One piece of information. + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +}; + +// inline functions +inline std::string CCglsAlgorithm::description() const { return CCglsAlgorithm::type; }; + + +} // end namespace + +#endif diff --git a/include/astra/ConeProjectionGeometry3D.h b/include/astra/ConeProjectionGeometry3D.h new file mode 100644 index 0000000..497ce7d --- /dev/null +++ b/include/astra/ConeProjectionGeometry3D.h @@ -0,0 +1,213 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CONEPROJECTIONGEOMETRY3D +#define _INC_ASTRA_CONEPROJECTIONGEOMETRY3D + +#include "ProjectionGeometry3D.h" + +namespace astra +{ + +/** + * This class defines a 3D cone beam projection geometry. + * + * \par XML Configuration + * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorWidth, float, Width of each detector.} + * \astra_xml_item{DetectorHeight, float, Width of each detector.} + * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.} + * \astra_xml_item{DistanceOriginDetector, float, Distance between the center of rotation and the detectorarray.} + * \astra_xml_item{DistanceOriginSource, float, Distance between the center of rotation the the x-ray source.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('cone');\n + * proj_geom.DetectorRowCount = 512;\n + * proj_geom.DetectorColCount = 512;\n + * proj_geom.DetectorWidth = 1.0;\n + * proj_geom.DetectorHeight = 1.0;\n + * proj_geom.ProjectionAngles = linspace(0,pi,100);\n + * proj_geom.DistanceOriginDetector = 10000;\n + * proj_geom.DistanceOriginSource = 10000;\n + * } + */ +class _AstraExport CConeProjectionGeometry3D : public CProjectionGeometry3D +{ +protected: + + /** + * Distance from the origin of the coordinate system to the source. + */ + float32 m_fOriginSourceDistance; + + /** + * Distance from the origin of the coordinate system to the detector (i.e., the distance between the origin and its orthogonal projection + * onto the detector array). + */ + float32 m_fOriginDetectorDistance; + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling initialize() + * is not allowed, except calling the member function isInitialized(). + */ + CConeProjectionGeometry3D(); + + /** Constructor. Create an instance of the CParallelProjectionGeometry3D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles + * are represented in radians and lie in the [0,2pi[ interval. + */ + CConeProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance); + + /** Copy constructor. + */ + CConeProjectionGeometry3D(const CConeProjectionGeometry3D& _projGeom); + + /** Destructor. + */ + ~CConeProjectionGeometry3D(); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the geometry. If the object has been initialized before, the object is reinitialized + * and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal height. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles + * are represented in radians and lie in the [0,2pi[ interval. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance); + + + /** Create a hard copy. + */ + virtual CProjectionGeometry3D* clone() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(const CProjectionGeometry3D*) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "cone". + */ + virtual bool isOfType(const std::string& _sType) const; + + /** Turn this object into an XML object. + * + * @param _sNode The XML object to fill. + */ + virtual void toXML(XMLNode* _sNode) const; + + /** Returns the distance from the origin of the coordinate system to the source. + * + * @return Distance from the origin of the coordinate system to the source + */ + float32 getOriginSourceDistance() const; + + /** Returns the distance from the origin of the coordinate system to the detector + * (i.e., the distance between the origin and its orthogonal projection onto the detector array). + * + * @return Distance from the origin of the coordinate system to the detector + */ + float32 getOriginDetectorDistance() const; + + /** Returns the distance from the source to the detector + * (i.e., the distance between the source and its orthogonal projection onto the detector array). + * + * @return Distance from the source to the detector + */ + float32 getSourceDetectorDistance() const; + + /** + * Returns a vector giving the projection direction for a projection and detector index + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const; +}; + +// Returns the distance from the origin of the coordinate system to the source. +inline float32 CConeProjectionGeometry3D::getOriginSourceDistance() const +{ + return m_fOriginSourceDistance; +} + + +// Returns the distance from the origin of the coordinate system to the detector. +inline float32 CConeProjectionGeometry3D::getOriginDetectorDistance() const +{ + return m_fOriginDetectorDistance; +} + + +// Returns the distance from the source to the detector. +inline float32 CConeProjectionGeometry3D::getSourceDetectorDistance() const +{ + return (m_fOriginSourceDistance + m_fOriginDetectorDistance); +} + + +} // namespace astra + +#endif /* _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D */ diff --git a/include/astra/ConeVecProjectionGeometry3D.h b/include/astra/ConeVecProjectionGeometry3D.h new file mode 100644 index 0000000..1765cdd --- /dev/null +++ b/include/astra/ConeVecProjectionGeometry3D.h @@ -0,0 +1,154 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CONEVECPROJECTIONGEOMETRY3D +#define _INC_ASTRA_CONEVECPROJECTIONGEOMETRY3D + +#include "ProjectionGeometry3D.h" +#include "../cuda/3d/dims3d.h" + +namespace astra +{ + +/** + * This class defines a 3D cone beam projection geometry. + * + * \par XML Configuration + * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.} + * \astra_xml_item{Vectors, matrix defining the 3D position of source and detector.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('cone_vec');\n + * proj_geom.DetectorRowCount = 512;\n + * proj_geom.DetectorColCount = 512;\n + * proj_geom.Vectors = V;\n + * } + * + * \par Vectors + * Vectors is a matrix containing the actual geometry. Each row corresponds + * to a single projection, and consists of: + * ( srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ ) + * src: the ray source + * d : the corner of the detector + * u : the vector from detector pixel (0,0) to (0,1) + * v : the vector from detector pixel (0,0) to (1,0) + */ +class _AstraExport CConeVecProjectionGeometry3D : public CProjectionGeometry3D +{ +protected: + + SConeProjection *m_pProjectionAngles; + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling initialize() + * is not allowed, except calling the member function isInitialized(). + */ + CConeVecProjectionGeometry3D(); + + /** Constructor. Create an instance of the CConeVecProjectionGeometry3D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + CConeVecProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SConeProjection* _pProjectionAngles); + + /** Copy constructor. + */ + CConeVecProjectionGeometry3D(const CConeVecProjectionGeometry3D& _projGeom); + + /** Destructor. + */ + ~CConeVecProjectionGeometry3D(); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the geometry. If the object has been initialized before, the object is reinitialized + * and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _pProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SConeProjection* _pProjectionAngles); + + virtual bool _check(); + + /** Create a hard copy. + */ + virtual CProjectionGeometry3D* clone() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(const CProjectionGeometry3D*) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "cone_vec". + */ + virtual bool isOfType(const std::string& _sType) const; + + /** Turn this object into an XML object. + * + * @param _sNode The XML object to fill. + */ + virtual void toXML(XMLNode* _sNode) const; + + /** + * Returns a vector giving the projection direction for a projection and detector index + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const; + + const SConeProjection* getProjectionVectors() const { return m_pProjectionAngles; } +}; + +} // namespace astra + +#endif /* _INC_ASTRA_CONEVECPROJECTIONGEOMETRY3D */ diff --git a/include/astra/Config.h b/include/astra/Config.h new file mode 100644 index 0000000..5a629a2 --- /dev/null +++ b/include/astra/Config.h @@ -0,0 +1,80 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CONFIG +#define _INC_ASTRA_CONFIG + +#include "Globals.h" +#include "XMLNode.h" + +#include <set> + +namespace astra { + + +/** + * Configuration options for an ASTRA class. + */ +struct _AstraExport Config { + + Config(); + Config(XMLNode* _self); + ~Config(); + + XMLNode* self; + XMLNode* global; +}; + +struct ConfigCheckData { + // For checking for unparsed nodes/options + std::set<std::string> parsedNodes; + std::set<std::string> parsedOptions; + unsigned int parseDepth; +}; + + +template<class T> +class ConfigStackCheck { +public: + ConfigStackCheck(const char *_name, T* _obj, const Config& _cfg); + ~ConfigStackCheck(); + + bool stopParsing(); // returns true if no unused nodes/options + void markNodeParsed(const std::string& name); + void markOptionParsed(const std::string& name); + + +private: + T* object; + const Config* cfg; + const char* name; +}; + +} // end namespace + +#endif diff --git a/include/astra/CudaBackProjectionAlgorithm.h b/include/astra/CudaBackProjectionAlgorithm.h new file mode 100644 index 0000000..965c734 --- /dev/null +++ b/include/astra/CudaBackProjectionAlgorithm.h @@ -0,0 +1,110 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDABACKPROJECTIONALGORITHM +#define _INC_ASTRA_CUDABACKPROJECTIONALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "CudaReconstructionAlgorithm2D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +/** + * \brief + * This class contains a GPU implementation of backprojection. + * + * \par XML Configuration + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('BP_CUDA');\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 1);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ +class _AstraExport CCudaBackProjectionAlgorithm : public CCudaReconstructionAlgorithm2D +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaBackProjectionAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaBackProjectionAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _iGPUindex GPU to use. + * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex = 0, int _iPixelSuperSampling = 1); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; +}; + +// inline functions +inline std::string CCudaBackProjectionAlgorithm::description() const { return CCudaBackProjectionAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaBackProjectionAlgorithm3D.h b/include/astra/CudaBackProjectionAlgorithm3D.h new file mode 100644 index 0000000..b069da6 --- /dev/null +++ b/include/astra/CudaBackProjectionAlgorithm3D.h @@ -0,0 +1,152 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDABACKPROJECTIONALGORITHM3D +#define _INC_ASTRA_CUDABACKPROJECTIONALGORITHM3D + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" + +#include "Float32ProjectionData3DMemory.h" +#include "Float32VolumeData3DMemory.h" +#include "ReconstructionAlgorithm3D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +class _AstraExport CCudaBackProjectionAlgorithm3D : public CReconstructionAlgorithm3D { + +protected: + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - the projector is compatible with both data objects + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, does not initialize the object. + */ + CCudaBackProjectionAlgorithm3D(); + + /** Constructor with initialization. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + */ + CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Copy constructor. + */ + CCudaBackProjectionAlgorithm3D(const CCudaBackProjectionAlgorithm3D&); + + /** Destructor. + */ + virtual ~CCudaBackProjectionAlgorithm3D(); + + /** Clear this class. + */ +/* virtual void clear();*/ + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + * @return initialization successful? + */ + bool initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + +protected: + + int m_iGPUIndex; + int m_iVoxelSuperSampling; + +}; + +// inline functions +inline std::string CCudaBackProjectionAlgorithm3D::description() const { return CCudaBackProjectionAlgorithm3D::type; }; + +} // end namespace + +#endif + +#endif diff --git a/include/astra/CudaCglsAlgorithm.h b/include/astra/CudaCglsAlgorithm.h new file mode 100644 index 0000000..7734d6e --- /dev/null +++ b/include/astra/CudaCglsAlgorithm.h @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDACGLSALGORITHM +#define _INC_ASTRA_CUDACGLSALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "CudaReconstructionAlgorithm2D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +/** + * \brief + * This class contains a GPU implementation of the CGLS algorithm. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, integer, Geometry of the projection data.} + * \astra_xml_item{VolumeGeometry, integer, Geometry of the volume data.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('CGLS_CUDA');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.ReconstructionMaskId = mask_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 10);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ + +class AstraCGLS; + +class _AstraExport CCudaCglsAlgorithm : public CCudaReconstructionAlgorithm2D +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaCglsAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaCglsAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram + * @param _pReconstruction VolumeData2D for storing the reconstruction + * @param _iGPUindex Index of GPU to use. (Starting at 0.) + * @param _iDetectorSuperSampling Supersampling factor for the FP. + * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1, + int _iPixelSuperSampling = 1); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +}; + +// inline functions +inline std::string CCudaCglsAlgorithm::description() const { return CCudaCglsAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaCglsAlgorithm3D.h b/include/astra/CudaCglsAlgorithm3D.h new file mode 100644 index 0000000..47b61af --- /dev/null +++ b/include/astra/CudaCglsAlgorithm3D.h @@ -0,0 +1,173 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDACGLSALGORITHM3D +#define _INC_ASTRA_CUDACGLSALGORITHM3D + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" + +#include "Float32ProjectionData3DMemory.h" +#include "Float32VolumeData3DMemory.h" +#include "ReconstructionAlgorithm3D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +class AstraCGLS3d; + +/** + * \brief + * This class contains the 3D implementation of the CGLS algorithm + * + */ +class _AstraExport CCudaCglsAlgorithm3D : public CReconstructionAlgorithm3D { + +protected: + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - the projector is compatible with both data objects + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, does not initialize the object. + */ + CCudaCglsAlgorithm3D(); + + /** Constructor with initialization. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + */ + CCudaCglsAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Copy constructor. + */ + CCudaCglsAlgorithm3D(const CCudaCglsAlgorithm3D&); + + /** Destructor. + */ + virtual ~CCudaCglsAlgorithm3D(); + + /** Clear this class. + */ +/* virtual void clear();*/ + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + * @return initialization successful? + */ + bool initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + + + virtual void signalAbort(); + + /** Get the norm of the residual image. + * Only a few algorithms support this method. + * + * @param _fNorm if supported, the norm is returned here + * @return true if this operation is supported + */ + virtual bool getResidualNorm(float32& _fNorm); + +protected: + + AstraCGLS3d* m_pCgls; + + int m_iGPUIndex; + bool m_bAstraCGLSInit; + int m_iDetectorSuperSampling; + int m_iVoxelSuperSampling; +}; + +// inline functions +inline std::string CCudaCglsAlgorithm3D::description() const { return CCudaCglsAlgorithm3D::type; }; + +} // end namespace + +#endif + +#endif diff --git a/include/astra/CudaDartMaskAlgorithm.h b/include/astra/CudaDartMaskAlgorithm.h new file mode 100644 index 0000000..f370f42 --- /dev/null +++ b/include/astra/CudaDartMaskAlgorithm.h @@ -0,0 +1,126 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDADARTMASKALGORITHM +#define _INC_ASTRA_CUDADARTMASKALGORITHM + +#include "Globals.h" +#include "Config.h" +#include "Algorithm.h" +#include "Float32VolumeData2D.h" + + +#ifdef ASTRA_CUDA + +namespace astraCUDA { +class PDART; +} + +namespace astra { + + class _AstraExport CCudaDartMaskAlgorithm : public CAlgorithm +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaDartMaskAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaDartMaskAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pSegmentation ... + * @param iConn ... + */ + //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + +protected: + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + unsigned int m_iConn; + unsigned int m_iThreshold; + unsigned int m_iRadius; + int m_iGPUIndex; + + CFloat32VolumeData2D* m_pSegmentation; + CFloat32VolumeData2D* m_pMask; + +}; + +// inline functions +inline std::string CCudaDartMaskAlgorithm::description() const { return CCudaDartMaskAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaDartMaskAlgorithm3D.h b/include/astra/CudaDartMaskAlgorithm3D.h new file mode 100644 index 0000000..bdbce2b --- /dev/null +++ b/include/astra/CudaDartMaskAlgorithm3D.h @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDADARTMASKALGORITHM3D +#define _INC_ASTRA_CUDADARTMASKALGORITHM3D + +#include "Globals.h" +#include "Config.h" +#include "Algorithm.h" +#include "Float32VolumeData3DMemory.h" + + +#ifdef ASTRA_CUDA + +namespace astra { + + class _AstraExport CCudaDartMaskAlgorithm3D : public CAlgorithm +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaDartMaskAlgorithm3D(); + + /** Destructor. + */ + virtual ~CCudaDartMaskAlgorithm3D(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pSegmentation ... + * @param iConn ... + */ + //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + +protected: + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + unsigned int m_iConn; + unsigned int m_iThreshold; + unsigned int m_iRadius; + int m_iGPUIndex; + + CFloat32VolumeData3DMemory* m_pSegmentation; + CFloat32VolumeData3DMemory* m_pMask; + +}; + +// inline functions +inline std::string CCudaDartMaskAlgorithm3D::description() const { return CCudaDartMaskAlgorithm3D::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaDartSmoothingAlgorithm.h b/include/astra/CudaDartSmoothingAlgorithm.h new file mode 100644 index 0000000..f90f9cf --- /dev/null +++ b/include/astra/CudaDartSmoothingAlgorithm.h @@ -0,0 +1,125 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM +#define _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM + +#include "Globals.h" +#include "Config.h" +#include "Algorithm.h" +#include "Float32VolumeData2D.h" + + +#ifdef ASTRA_CUDA + +namespace astraCUDA { +class PDART; +} + +namespace astra { + + class _AstraExport CCudaDartSmoothingAlgorithm : public CAlgorithm +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaDartSmoothingAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaDartSmoothingAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pSegmentation ... + * @param iConn ... + */ + //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + +protected: + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + float m_fB; + unsigned int m_iRadius; + int m_iGPUIndex; + + CFloat32VolumeData2D* m_pIn; + CFloat32VolumeData2D* m_pOut; + +}; + +// inline functions +inline std::string CCudaDartSmoothingAlgorithm::description() const { return CCudaDartSmoothingAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaDartSmoothingAlgorithm3D.h b/include/astra/CudaDartSmoothingAlgorithm3D.h new file mode 100644 index 0000000..9942de8 --- /dev/null +++ b/include/astra/CudaDartSmoothingAlgorithm3D.h @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM3D +#define _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM3D + +#include "Globals.h" +#include "Config.h" +#include "Algorithm.h" +#include "Float32VolumeData3DMemory.h" + + +#ifdef ASTRA_CUDA + +namespace astra { + + class _AstraExport CCudaDartSmoothingAlgorithm3D : public CAlgorithm +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaDartSmoothingAlgorithm3D(); + + /** Destructor. + */ + virtual ~CCudaDartSmoothingAlgorithm3D(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pSegmentation ... + * @param iConn ... + */ + //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + +protected: + + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + float m_fB; + unsigned int m_iRadius; + int m_iGPUIndex; + + CFloat32VolumeData3DMemory* m_pIn; + CFloat32VolumeData3DMemory* m_pOut; + +}; + +// inline functions +inline std::string CCudaDartSmoothingAlgorithm3D::description() const { return CCudaDartSmoothingAlgorithm3D::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaDataOperationAlgorithm.h b/include/astra/CudaDataOperationAlgorithm.h new file mode 100644 index 0000000..a5ab01a --- /dev/null +++ b/include/astra/CudaDataOperationAlgorithm.h @@ -0,0 +1,128 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDADATAOPERATIONALGORITHM +#define _INC_ASTRA_CUDADATAOPERATIONALGORITHM + +#include "Globals.h" +#include "Config.h" +#include "Algorithm.h" +#include "Float32VolumeData2D.h" + +#ifdef ASTRA_CUDA + +namespace astraCUDA { +class PDART; +} + +namespace astra { + + class _AstraExport CCudaDataOperationAlgorithm : public CAlgorithm +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaDataOperationAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaDataOperationAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pSegmentation ... + * @param iConn ... + */ + //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + +protected: + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + + + int m_iGPUIndex; + + CFloat32Data2D* m_pMask; + + vector<CFloat32Data2D*> m_pData; + vector<float> m_fScalar; + + string m_sOperation; + +}; + +// inline functions +inline std::string CCudaDataOperationAlgorithm::description() const { return CCudaDataOperationAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaEMAlgorithm.h b/include/astra/CudaEMAlgorithm.h new file mode 100644 index 0000000..ff22dd4 --- /dev/null +++ b/include/astra/CudaEMAlgorithm.h @@ -0,0 +1,92 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDAEMALGORITHM +#define _INC_ASTRA_CUDAEMALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "CudaReconstructionAlgorithm2D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +class _AstraExport CCudaEMAlgorithm : public CCudaReconstructionAlgorithm2D +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaEMAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaEMAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _iGPUindex GPU to use. + * @param _iDetectorSuperSampling Supersampling factor for the FP. + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1, + int _iPixelSuperSampling = 1); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; +}; + +// inline functions +inline std::string CCudaEMAlgorithm::description() const { return CCudaEMAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaFDKAlgorithm3D.h b/include/astra/CudaFDKAlgorithm3D.h new file mode 100644 index 0000000..7ab9bbe --- /dev/null +++ b/include/astra/CudaFDKAlgorithm3D.h @@ -0,0 +1,164 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDAFDKALGORITHM3D +#define _INC_ASTRA_CUDAFDKALGORITHM3D + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" + +#include "Float32ProjectionData3DMemory.h" +#include "Float32VolumeData3DMemory.h" +#include "ReconstructionAlgorithm3D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +/** + * \brief + * This class contains the 3D implementation of the FDK algorithm. + * + * \par XML Configuration + * + * \par MATLAB example + * \astra_code{ + * + * } + * + */ +class _AstraExport CCudaFDKAlgorithm3D : public CReconstructionAlgorithm3D { + +protected: + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - the projector is compatible with both data objects + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, does not initialize the object. + */ + CCudaFDKAlgorithm3D(); + + /** Constructor with initialization. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + */ + CCudaFDKAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Copy constructor. + */ + CCudaFDKAlgorithm3D(const CCudaFDKAlgorithm3D&); + + /** Destructor. + */ + virtual ~CCudaFDKAlgorithm3D(); + + /** Clear this class. + */ +/* virtual void clear();*/ + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + * @return initialization successful? + */ + bool initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + +protected: + + int m_iGPUIndex; + int m_iVoxelSuperSampling; + bool m_bShortScan; +}; + +// inline functions +inline std::string CCudaFDKAlgorithm3D::description() const { return CCudaFDKAlgorithm3D::type; }; + +} // end namespace + +#endif + +#endif diff --git a/include/astra/CudaFilteredBackProjectionAlgorithm.h b/include/astra/CudaFilteredBackProjectionAlgorithm.h new file mode 100644 index 0000000..4b7b904 --- /dev/null +++ b/include/astra/CudaFilteredBackProjectionAlgorithm.h @@ -0,0 +1,94 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef CUDAFILTEREDBACKPROJECTIONALGORITHM2_H +#define CUDAFILTEREDBACKPROJECTIONALGORITHM2_H + +#include <astra/Float32ProjectionData2D.h> +#include <astra/Float32VolumeData2D.h> +#include <astra/ReconstructionAlgorithm2D.h> + +#include "../../cuda/2d/astra.h" + +namespace astra +{ + +class _AstraExport CCudaFilteredBackProjectionAlgorithm : public CReconstructionAlgorithm2D +{ +public: + static std::string type; + +private: + CFloat32ProjectionData2D * m_pSinogram; + CFloat32VolumeData2D * m_pReconstruction; + int m_iGPUIndex; + int m_iPixelSuperSampling; + E_FBPFILTER m_eFilter; + float * m_pfFilter; + int m_iFilterWidth; // number of elements per projection direction in filter + float m_fFilterParameter; // some filters allow for parameterization (value < 0.0f -> no parameter) + float m_fFilterD; // frequency cut-off + + static E_FBPFILTER _convertStringToFilter(const char * _filterType); + +public: + CCudaFilteredBackProjectionAlgorithm(); + virtual ~CCudaFilteredBackProjectionAlgorithm(); + + virtual bool initialize(const Config& _cfg); + bool initialize(CFloat32ProjectionData2D * _pSinogram, CFloat32VolumeData2D * _pReconstruction, E_FBPFILTER _eFilter, const float * _pfFilter = NULL, int _iFilterWidth = 0, int _iGPUIndex = 0, float _fFilterParameter = -1.0f); + + virtual void run(int _iNrIterations = 0); + + static int calcIdealRealFilterWidth(int _iDetectorCount); + static int calcIdealFourierFilterWidth(int _iDetectorCount); + + //debug + static void testGenFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, cufftComplex * _pFilter, int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount); + static int getGPUCount(); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +protected: + bool check(); + + AstraFBP* m_pFBP; + + bool m_bAstraFBPInit; +}; + +// inline functions +inline std::string CCudaFilteredBackProjectionAlgorithm::description() const { return CCudaFilteredBackProjectionAlgorithm::type; }; + +} + +#endif /* CUDAFILTEREDBACKPROJECTIONALGORITHM2_H */ diff --git a/include/astra/CudaForwardProjectionAlgorithm.h b/include/astra/CudaForwardProjectionAlgorithm.h new file mode 100644 index 0000000..53b6c8e --- /dev/null +++ b/include/astra/CudaForwardProjectionAlgorithm.h @@ -0,0 +1,169 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM2 +#define _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM2 + +#include "Globals.h" + +#include "Algorithm.h" + +#include "ParallelProjectionGeometry2D.h" +#include "VolumeGeometry2D.h" + +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +/** + * \brief + * This class contains a GPU implementation of an algorithm that creates a forward projection + * of a volume object and stores it into a sinogram. + * + * \par XML Configuration + * \astra_xml_item{VolumeGeometry, integer, Geometry of the volume data.} + * \astra_xml_item{ProjectionGeometry, integer, Geometry of the projection data.} + * \astra_xml_item{VolumeDataId, integer, Identifier of the volume data object as it is stored in the DataManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of the resulting projection data object as it is stored in the DataManager.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('FP_CUDA2');\n + * cfg.VolumeGeometry = vol_geom;\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeDataId = vol_id;\n + * cfg.ProjectionDataId = sino_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('run'\, alg_id);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ +class _AstraExport CCudaForwardProjectionAlgorithm : public CAlgorithm +{ +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaForwardProjectionAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaForwardProjectionAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pVolumeGeometry Geometry of the volume. + * @param _pProjectionGeometry Geometry of the projection. + * @param _pVolume VolumeData2D object containing the phantom to compute sinogram from + * @param _pSinogram ProjectionData2D object to store sinogram data in. + * @param _iGPUindex Index of GPU to use. (Starting at 0.) + * @param _iDetectorSuperSampling Number of samples per detector element, used to compute the forward projection + * @return success + */ + bool initialize(CProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Check this object. + * + * @return object initialized + */ + bool check(); + + CFloat32VolumeData2D* getVolume() { return m_pVolume; } + CFloat32ProjectionData2D* getSinogram() { return m_pSinogram; } + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + +protected: + //< ProjectionData2D object containing the sinogram. + CFloat32ProjectionData2D* m_pSinogram; + //< VolumeData2D object containing the phantom. + CFloat32VolumeData2D* m_pVolume; + + //< Index of GPU to use + int m_iGPUIndex; + //< Number of rays per detector element + int m_iDetectorSuperSampling; + +}; + +// inline functions +inline std::string CCudaForwardProjectionAlgorithm::description() const { return CCudaForwardProjectionAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaForwardProjectionAlgorithm3D.h b/include/astra/CudaForwardProjectionAlgorithm3D.h new file mode 100644 index 0000000..72c6a00 --- /dev/null +++ b/include/astra/CudaForwardProjectionAlgorithm3D.h @@ -0,0 +1,135 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM3D +#define _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM3D + +#include "Globals.h" + +#include "Algorithm.h" + +#include "Float32ProjectionData3DMemory.h" +#include "Float32VolumeData3DMemory.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +class CProjector3D; + +class _AstraExport CCudaForwardProjectionAlgorithm3D : public CAlgorithm +{ +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaForwardProjectionAlgorithm3D(); + + /** Destructor. + */ + virtual ~CCudaForwardProjectionAlgorithm3D(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object for storing the projection data. + * @param _pReconstruction VolumeData3D object containing the volume. + * @return initialization successful? + */ + bool initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1); + + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Check this object. + * + * @return object initialized + */ + bool check(); + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + +protected: + CProjector3D* m_pProjector; + CFloat32ProjectionData3DMemory* m_pProjections; + CFloat32VolumeData3DMemory* m_pVolume; + int m_iGPUIndex; + int m_iDetectorSuperSampling; + +}; + +// inline functions +inline std::string CCudaForwardProjectionAlgorithm3D::description() const { return CCudaForwardProjectionAlgorithm3D::type; }; + + +} + +#endif + +#endif diff --git a/include/astra/CudaProjector2D.h b/include/astra/CudaProjector2D.h new file mode 100644 index 0000000..073b299 --- /dev/null +++ b/include/astra/CudaProjector2D.h @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------- +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") + +Copyright: IBBT-Vision Lab, University of Antwerp +Contact: mailto:wim.vanaarle@ua.ac.be +Website: http://astra.ua.ac.be +----------------------------------------------------------------------- +$Id$ +*/ +#ifndef _INC_ASTRA_CUDAPROJECTOR2D +#define _INC_ASTRA_CUDAPROJECTOR2D + +#include "ParallelProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" +#include "../../cuda/2d/astra.h" + +namespace astra +{ + + +/** This is a two-dimensional CUDA-projector. + * It is essentially a fake projector, containing settings relevant for the + * actual CUDA code. + */ +class _AstraExport CCudaProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CCudaProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CCudaProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + ~CCudaProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Clear this class. + */ + virtual void clear(); + + + virtual int getProjectionWeightsCount(int _iProjectionIndex) { return 0; } + + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) {} + + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol) + { std::vector<SDetector2D> x; return x; } + + template <typename Policy> + void project(Policy& _policy) {} + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy) {} + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy) {} + + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const; + + +protected: + + Cuda2DProjectionKernel m_projectionKernel; +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CCudaProjector2D::getType() +{ + return type; +} + +} // namespace astra + +#endif + diff --git a/include/astra/CudaProjector3D.h b/include/astra/CudaProjector3D.h new file mode 100644 index 0000000..66071f0 --- /dev/null +++ b/include/astra/CudaProjector3D.h @@ -0,0 +1,131 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef INC_ASTRA_CUDAPROJECTOR3D +#define INC_ASTRA_CUDAPROJECTOR3D + +#ifdef ASTRA_CUDA + +#include <cmath> +#include <vector> + +#include "Globals.h" +#include "Config.h" +#include "Projector3D.h" +#include "../../cuda/3d/astra3d.h" + +namespace astra +{ + +/** This is a three-dimensional CUDA-projector. + * It is essentially a fake projector, containing settings relevant for the + * actual CUDA code. + */ +class _AstraExport CCudaProjector3D : public CProjector3D +{ + +protected: + + /** Check variable values. + */ + bool _check(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + * Should only be used by constructors. Otherwise use the clear() function. + */ + void _clear(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** + * Default Constructor. + */ + CCudaProjector3D(); + + /** Destructor, is virtual to show that we are aware subclass destructor is called. + */ + virtual ~CCudaProjector3D(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + void clear(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iSliceIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) {} + virtual int getProjectionWeightsCount(int _iProjectionIndex) { return 0; } + template <typename Policy> + void project(Policy& _policy) {} + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy) {} + template <typename Policy> + void projectSingleRay(int _iProjection, int _iSlice, int _iDetector, Policy& _policy) {} + + + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType() { return type; } + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const; + + + Cuda3DProjectionKernel getProjectionKernel() const { return m_projectionKernel; } + +protected: + + Cuda3DProjectionKernel m_projectionKernel; + + +}; + + +} // namespace astra + +#endif // ASTRA_CUDA + +#endif /* INC_ASTRA_CUDAPROJECTOR3D */ diff --git a/include/astra/CudaReconstructionAlgorithm2D.h b/include/astra/CudaReconstructionAlgorithm2D.h new file mode 100644 index 0000000..88fc344 --- /dev/null +++ b/include/astra/CudaReconstructionAlgorithm2D.h @@ -0,0 +1,176 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDARECONSTRUCTIONALGORITHM2D +#define _INC_ASTRA_CUDARECONSTRUCTIONALGORITHM2D + +#include "Globals.h" +#include "Config.h" + +#include "ReconstructionAlgorithm2D.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +namespace astraCUDA { +class ReconAlgo; +} + +namespace astra { + +/** + * This is a base class for the different CUDA implementations of 2D reconstruction algorithms. + * They don't use a Projector, and share GPUIndex and DetectorSuperSampling options. + * + */ +class _AstraExport CCudaReconstructionAlgorithm2D : public CReconstructionAlgorithm2D { + +public: + + /** Default constructor, containing no code. + */ + CCudaReconstructionAlgorithm2D(); + + /** Destructor. + */ + virtual ~CCudaReconstructionAlgorithm2D(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Initialize class. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _iGPUindex GPU to use. + * @param _iDetectorSuperSampling Supersampling factor for the FP. + * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection + */ + virtual bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1, + int _iPixelSuperSampling = 1); + + + /** Clear this class. + */ + virtual void clear(); + + /** Get all information parameters. + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information. + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Get the norm of the residual image. + * Only a few algorithms support this method. + * + * @param _fNorm if supported, the norm is returned here + * @return true if this operation is supported + */ + virtual bool getResidualNorm(float32& _fNorm); + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + virtual void signalAbort(); + +protected: + + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + /** Initial clearing. Only to be used by constructors. + */ + void _clear(); + + /** Set up geometry. For internal use only. + */ + bool setupGeometry(); + + + /** The internally used CUDA algorithm object + */ + astraCUDA::ReconAlgo *m_pAlgo; + + int m_iDetectorSuperSampling; + int m_iPixelSuperSampling; + int m_iGPUIndex; + + bool m_bAlgoInit; +}; + +// inline functions +inline std::string CCudaReconstructionAlgorithm2D::description() const { return "2D CUDA Reconstruction Algorithm"; }; + +} // end namespace + +#endif diff --git a/include/astra/CudaRoiSelectAlgorithm.h b/include/astra/CudaRoiSelectAlgorithm.h new file mode 100644 index 0000000..1ee9c32 --- /dev/null +++ b/include/astra/CudaRoiSelectAlgorithm.h @@ -0,0 +1,123 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDAROISELECTALGORITHM +#define _INC_ASTRA_CUDAROISELECTALGORITHM + +#include "Globals.h" +#include "Config.h" +#include "Algorithm.h" +#include "Float32VolumeData2D.h" + + +#ifdef ASTRA_CUDA + +namespace astraCUDA { +class PDART; +} + +namespace astra { + + class _AstraExport CCudaRoiSelectAlgorithm : public CAlgorithm +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaRoiSelectAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaRoiSelectAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, use sequential order. + * + * @param _pSegmentation ... + * @param iConn ... + */ + //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + +protected: + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + float32 m_fRadius; + int m_iGPUIndex; + + CFloat32VolumeData2D* m_pData; + +}; + +// inline functions +inline std::string CCudaRoiSelectAlgorithm::description() const { return CCudaRoiSelectAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaSartAlgorithm.h b/include/astra/CudaSartAlgorithm.h new file mode 100644 index 0000000..319e1e9 --- /dev/null +++ b/include/astra/CudaSartAlgorithm.h @@ -0,0 +1,112 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDASARTALGORITHM +#define _INC_ASTRA_CUDASARTALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "CudaReconstructionAlgorithm2D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +/** + * \brief + * This class contains a GPU implementation of the SART algorithm. + * + * \par XML Configuration + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('SART_CUDA');\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.ReconstructionMaskId = mask_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 10);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ +class _AstraExport CCudaSartAlgorithm : public CCudaReconstructionAlgorithm2D +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaSartAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaSartAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _iGPUindex GPU to use. + * @param _iDetectorSuperSampling Supersampling factor for the FP. + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; +}; + +// inline functions +inline std::string CCudaSartAlgorithm::description() const { return CCudaSartAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaSirtAlgorithm.h b/include/astra/CudaSirtAlgorithm.h new file mode 100644 index 0000000..7f3d67b --- /dev/null +++ b/include/astra/CudaSirtAlgorithm.h @@ -0,0 +1,131 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDASIRTALGORITHM2 +#define _INC_ASTRA_CUDASIRTALGORITHM2 + +#include "Globals.h" +#include "Config.h" + +#include "CudaReconstructionAlgorithm2D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +/** + * \brief + * This class contains a GPU implementation of the SIRT (Simultaneous Iterative Reconstruction Technique) algorithm. + * + * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by: + * \f[ + * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} + * \f] + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, integer, Geometry of the projection data.} + * \astra_xml_item{VolumeGeometry, integer, Geometry of the volume data.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('SIRT_CUDA2');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.ReconstructionMaskId = mask_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 10);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + * \par References + * [1] "Computational Analysis and Improvement of SIRT", J. Gregor, T. Benson, IEEE Transactions on Medical Imaging, Vol. 22, No. 7, July 2008. + */ +class _AstraExport CCudaSirtAlgorithm : public CCudaReconstructionAlgorithm2D +{ + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CCudaSirtAlgorithm(); + + /** Destructor. + */ + virtual ~CCudaSirtAlgorithm(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + virtual void run(int _iNrIterations); + + /** Initialize class. + * + * @param _pProjector Projector Object. (Ignored) + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _iGPUindex GPU to use. + * @param _iDetectorSuperSampling Supersampling factor for the FP. + * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex = 0, int _iDetectorSuperSampling = 1, + int _iPixelSuperSampling = 1); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +protected: + CFloat32VolumeData2D* m_pMinMask; + CFloat32VolumeData2D* m_pMaxMask; +}; + +// inline functions +inline std::string CCudaSirtAlgorithm::description() const { return CCudaSirtAlgorithm::type; }; + +} // end namespace + +#endif // ASTRA_CUDA + +#endif diff --git a/include/astra/CudaSirtAlgorithm3D.h b/include/astra/CudaSirtAlgorithm3D.h new file mode 100644 index 0000000..c2c794d --- /dev/null +++ b/include/astra/CudaSirtAlgorithm3D.h @@ -0,0 +1,187 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_CUDASIRTALGORITHM3D +#define _INC_ASTRA_CUDASIRTALGORITHM3D + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" + +#include "Float32ProjectionData3DMemory.h" +#include "Float32VolumeData3DMemory.h" +#include "ReconstructionAlgorithm3D.h" + +#ifdef ASTRA_CUDA + +namespace astra { + +class AstraSIRT3d; + +/** + * \brief + * This class contains the 3D implementation of the SIRT (Simultaneous Iterative Reconstruction Technique) algorithm. + * + * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by: + * \f[ + * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} + * \f] + * + * \par XML Configuration + * + * \par MATLAB example + * \astra_code{ + * + * } + * + * \par References + * [1] "Computational Analysis and Improvement of SIRT", J. Gregor, T. Benson, IEEE Transactions on Medical Imaging, Vol. 22, No. 7, July 2008. + */ +class _AstraExport CCudaSirtAlgorithm3D : public CReconstructionAlgorithm3D { + +protected: + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - the projector is compatible with both data objects + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, does not initialize the object. + */ + CCudaSirtAlgorithm3D(); + + /** Constructor with initialization. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + */ + CCudaSirtAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Copy constructor. + */ + CCudaSirtAlgorithm3D(const CCudaSirtAlgorithm3D&); + + /** Destructor. + */ + virtual ~CCudaSirtAlgorithm3D(); + + /** Clear this class. + */ +/* virtual void clear();*/ + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pProjectionData ProjectionData3D object containing the projection data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + * @return initialization successful? + */ + bool initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** + * Sets the index of the used GPU index: first GPU has index 0 + * + * @param _iGPUIndex New GPU index. + */ + void setGPUIndex(int _iGPUIndex); + + + virtual void signalAbort(); + + /** Get the norm of the residual image. + * Only a few algorithms support this method. + * + * @param _fNorm if supported, the norm is returned here + * @return true if this operation is supported + */ + virtual bool getResidualNorm(float32& _fNorm); + +protected: + + AstraSIRT3d* m_pSirt; + + int m_iGPUIndex; + bool m_bAstraSIRTInit; + int m_iDetectorSuperSampling; + int m_iVoxelSuperSampling; +}; + +// inline functions +inline std::string CCudaSirtAlgorithm3D::description() const { return CCudaSirtAlgorithm3D::type; }; + +} // end namespace + +#endif + +#endif diff --git a/include/astra/DataProjector.h b/include/astra/DataProjector.h new file mode 100644 index 0000000..a324625 --- /dev/null +++ b/include/astra/DataProjector.h @@ -0,0 +1,327 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_DATAPROJECTOR +#define _INC_ASTRA_DATAPROJECTOR + +#include "Projector2D.h" + +#include "TypeList.h" + +#include "ProjectorTypelist.h" + +#include "DataProjectorPolicies.h" + +namespace astra +{ + + +/** + * Interface class for the Data Projector. The sole purpose of this class is to force child classes to implement a series of methods + */ +class CDataProjectorInterface { +public: + CDataProjectorInterface() { } + virtual ~CDataProjectorInterface() { } + virtual void project() = 0; + virtual void projectSingleProjection(int _iProjection) = 0; + virtual void projectSingleRay(int _iProjection, int _iDetector) = 0; +// virtual void projectSingleVoxel(int _iRow, int _iCol) = 0; +// virtual void projectAllVoxels() = 0; +}; + +/** + * Templated Data Projector Class. In this class a specific projector and policies are combined. + */ +template <typename Projector, typename Policy> +class CDataProjector: public CDataProjectorInterface { + +private: + + Projector* m_pProjector; + Policy m_pPolicy; + +public: + + CDataProjector() {}; + + CDataProjector(Projector* _p, Policy _a); + ~CDataProjector(); + + virtual void project(); + + virtual void projectSingleProjection(int _iProjection); + + virtual void projectSingleRay(int _iProjection, int _iDetector); + +// virtual void projectSingleVoxel(int _iRow, int _iCol); + +// virtual void projectAllVoxels(); +}; + +//---------------------------------------------------------------------------------------- +/** + * Constructor +*/ +template <typename Projector, typename Policy> +CDataProjector<Projector,Policy>::CDataProjector(Projector* _p, Policy _a) +{ + m_pProjector = _p; + m_pPolicy = _a; +} + +//---------------------------------------------------------------------------------------- +/** + * Destructor +*/ +template <typename Projector, typename Policy> +CDataProjector<Projector,Policy>::~CDataProjector() +{ + // does nothing +} + +//---------------------------------------------------------------------------------------- +/** + * Compute projection using the algorithm specific to the projector type +*/ +template <typename Projector, typename Policy> +void CDataProjector<Projector,Policy>::project() +{ + m_pProjector->project(m_pPolicy); +} + +//---------------------------------------------------------------------------------------- +/** + * Compute just one projection using the algorithm specific to the projector type +*/ +template <typename Projector, typename Policy> +void CDataProjector<Projector,Policy>::projectSingleProjection(int _iProjection) +{ + m_pProjector->projectSingleProjection(_iProjection, m_pPolicy); +} + +//---------------------------------------------------------------------------------------- +/** + * Compute projection of one ray using the algorithm specific to the projector type +*/ +template <typename Projector, typename Policy> +void CDataProjector<Projector,Policy>::projectSingleRay(int _iProjection, int _iDetector) +{ + m_pProjector->projectSingleRay(_iProjection, _iDetector, m_pPolicy); +} + +//---------------------------------------------------------------------------------------- +//template <typename Projector, typename Policy> +//void CDataProjector<Projector,Policy>::projectSingleVoxel(int _iRow, int _iCol) +//{ +// m_pProjector->projectSingleVoxel(_iRow, _iCol, m_pPolicy); +//} + +//---------------------------------------------------------------------------------------- +//template <typename Projector, typename Policy> +//void CDataProjector<Projector,Policy>::projectAllVoxels() +//{ +// m_pProjector->projectAllVoxels(m_pPolicy); +//} +//---------------------------------------------------------------------------------------- + + + + +//----------------------------------------------------------------------------------------- +// Create a new datainterface from the projector TypeList +namespace typelist { + template <class TList> + struct CreateDataProjector { + template <class U, typename Policy> + static void find (U& functor, CProjector2D* _pProjector, const Policy& _pPolicy) { + if (functor(TList::Head::type)) { + functor.res = new CDataProjector<typename TList::Head, Policy>(static_cast<typename TList::Head*>(_pProjector), _pPolicy); + } + CreateDataProjector<typename TList::Tail>::find(functor, _pProjector, _pPolicy); + } + }; + template <> + struct CreateDataProjector<NullType> { + template <class U, typename Policy> + static void find(U& functor, CProjector2D* _pProjector, const Policy& _pPolicy) {} + }; + + struct functor_find_datainterface { + functor_find_datainterface() { res = NULL; } + bool operator() (std::string name) { + return strcmp(tofind.c_str(), name.c_str()) == 0; + } + std::string tofind; + CDataProjectorInterface* res; + }; +} +//----------------------------------------------------------------------------------------- + +/** + * Data Projector Dispatcher - 1 Policy + */ +template <typename Policy> +static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector, const Policy& _policy) +{ + typelist::functor_find_datainterface finder = typelist::functor_find_datainterface(); + finder.tofind = _pProjector->getType(); + typelist::CreateDataProjector<Projector2DTypeList>::find(finder, _pProjector, _policy); + return finder.res; +} + + + +/** + * Data Projector Dispatcher - 2 Policies + */ +template <typename Policy1, typename Policy2> +static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector, + const Policy1& _policy, + const Policy2& _policy2, + bool _bUsePolicy1 = true, + bool _bUsePolicy2 = true) +{ + if (!_bUsePolicy1 && !_bUsePolicy2) { + return dispatchDataProjector(_pProjector, EmptyPolicy()); + } else if (!_bUsePolicy1) { + return dispatchDataProjector(_pProjector, _policy2); + } else if (!_bUsePolicy2) { + return dispatchDataProjector(_pProjector, _policy); + } else { + return dispatchDataProjector(_pProjector, CombinePolicy<Policy1, Policy2>(_policy, _policy2)); + } + +} + +/** + * Data Projector Dispatcher - 3 Policies + */ + +template <typename Policy1, typename Policy2, typename Policy3> +static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector, + const Policy1& _policy1, + const Policy2& _policy2, + const Policy3& _policy3, + bool _bUsePolicy1 = true, + bool _bUsePolicy2 = true, + bool _bUsePolicy3 = true) +{ + if (!_bUsePolicy1) { + return dispatchDataProjector(_pProjector, _policy2, _policy3, _bUsePolicy2, _bUsePolicy3); + } else if (!_bUsePolicy2) { + return dispatchDataProjector(_pProjector, _policy1, _policy3, _bUsePolicy1, _bUsePolicy3); + } else if (!_bUsePolicy3) { + return dispatchDataProjector(_pProjector, _policy1, _policy2, _bUsePolicy1, _bUsePolicy2); + } else { + return dispatchDataProjector(_pProjector, Combine3Policy<Policy1, Policy2, Policy3>(_policy1, _policy2, _policy3)); + } +} + +/** + * Data Projector Dispatcher - 4 Policies + */ +template <typename Policy1, typename Policy2, typename Policy3, typename Policy4> +static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector, + const Policy1& _policy1, + const Policy2& _policy2, + const Policy3& _policy3, + const Policy4& _policy4, + bool _bUsePolicy1 = true, + bool _bUsePolicy2 = true, + bool _bUsePolicy3 = true, + bool _bUsePolicy4 = true) +{ + if (!_bUsePolicy1) { + return dispatchDataProjector(_pProjector, _policy2, _policy3, _policy4, _bUsePolicy2, _bUsePolicy3, _bUsePolicy4); + } else if (!_bUsePolicy2) { + return dispatchDataProjector(_pProjector, _policy1, _policy3, _policy4, _bUsePolicy1, _bUsePolicy3, _bUsePolicy4); + } else if (!_bUsePolicy3) { + return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy4, _bUsePolicy1, _bUsePolicy2, _bUsePolicy4); + } else if (!_bUsePolicy4) { + return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy3, _bUsePolicy1, _bUsePolicy2, _bUsePolicy3); + } else { + return dispatchDataProjector(_pProjector, Combine4Policy<Policy1, Policy2, Policy3, Policy4>(_policy1, _policy2, _policy3, _policy4)); + } +} + +/** + * Data Projector Dispatcher - 5 Policies + */ +template <typename Policy1, typename Policy2, typename Policy3, typename Policy4, typename Policy5> +static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector, + const Policy1& _policy1, + const Policy2& _policy2, + const Policy3& _policy3, + const Policy4& _policy4, + const Policy5& _policy5, + bool _bUsePolicy1 = true, + bool _bUsePolicy2 = true, + bool _bUsePolicy3 = true, + bool _bUsePolicy4 = true, + bool _bUsePolicy5 = true) +{ + if (!_bUsePolicy1) { + return dispatchDataProjector(_pProjector, _policy2, _policy3, _policy4, _policy5, _bUsePolicy2, _bUsePolicy3, _bUsePolicy4, _bUsePolicy5); + } else if (!_bUsePolicy2) { + return dispatchDataProjector(_pProjector, _policy1, _policy3, _policy4, _policy5, _bUsePolicy1, _bUsePolicy3, _bUsePolicy4, _bUsePolicy5); + } else if (!_bUsePolicy3) { + return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy4, _policy5, _bUsePolicy1, _bUsePolicy2, _bUsePolicy4, _bUsePolicy5); + } else if (!_bUsePolicy4) { + return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy3, _policy5, _bUsePolicy1, _bUsePolicy2, _bUsePolicy3, _bUsePolicy5); + } else if (!_bUsePolicy5) { + return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy3, _policy4, _bUsePolicy1, _bUsePolicy2, _bUsePolicy3, _bUsePolicy4); + } else { + return dispatchDataProjector(_pProjector, CombinePolicy< Combine4Policy<Policy1, Policy2, Policy3, Policy4>, Policy5>( + Combine4Policy<Policy1, Policy2, Policy3, Policy4>(_policy1, _policy2, _policy3, _policy4), + _policy5) + ); + } +} + + + + +//----------------------------------------------------------------------------------------- +/** + * Data Projector Project + */ +template <typename Policy> +static void projectData(CProjector2D* _pProjector, const Policy& _policy) +{ + CDataProjectorInterface* dp = dispatchDataProjector(_pProjector, _policy); + dp->project(); + delete dp; +} + + + + +} // namespace astra + +#endif diff --git a/include/astra/DataProjectorPolicies.h b/include/astra/DataProjectorPolicies.h new file mode 100644 index 0000000..5ec08bd --- /dev/null +++ b/include/astra/DataProjectorPolicies.h @@ -0,0 +1,382 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_DATAPROJECTORPOLICIES +#define _INC_ASTRA_DATAPROJECTORPOLICIES + +#include "Globals.h" +#include "Config.h" + +#include <list> + +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +namespace astra { + +//enum {PixelDrivenPolicy, RayDrivenPolicy, AllPolicy} PolicyType; + + +//---------------------------------------------------------------------------------------- +/** Policy for Default Forward Projection (Ray Driven) + */ +class DefaultFPPolicy { + + //< Projection Data + CFloat32ProjectionData2D* m_pProjectionData; + //< Volume Data + CFloat32VolumeData2D* m_pVolumeData; + +public: + FORCEINLINE DefaultFPPolicy(); + FORCEINLINE DefaultFPPolicy(CFloat32VolumeData2D* _pVolumeData, CFloat32ProjectionData2D* _pProjectionData); + FORCEINLINE ~DefaultFPPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + + +//---------------------------------------------------------------------------------------- +/** Policy for Default Back Projection. (Ray+Pixel Driven) + * This does VolumeData += transpose(ProjectionMap) * ProjectionData. + */ +class DefaultBPPolicy { + + //< Projection Data + CFloat32ProjectionData2D* m_pProjectionData; + //< Volume Data + CFloat32VolumeData2D* m_pVolumeData; + +public: + FORCEINLINE DefaultBPPolicy(); + FORCEINLINE DefaultBPPolicy(CFloat32VolumeData2D* _pVolumeData, CFloat32ProjectionData2D* _pProjectionData); + FORCEINLINE ~DefaultBPPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + + + +//---------------------------------------------------------------------------------------- +/** Policy For Calculating the Projection Difference between Volume Data and Projection Data (Ray Driven) + */ +class DiffFPPolicy { + + CFloat32ProjectionData2D* m_pDiffProjectionData; + CFloat32ProjectionData2D* m_pBaseProjectionData; + CFloat32VolumeData2D* m_pVolumeData; +public: + + FORCEINLINE DiffFPPolicy(); + FORCEINLINE DiffFPPolicy(CFloat32VolumeData2D* _vol_data, CFloat32ProjectionData2D* _proj_data, CFloat32ProjectionData2D* _proj_data_base); + FORCEINLINE ~DiffFPPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Store Pixel Weights (Ray+Pixel Driven) + */ +class StorePixelWeightsPolicy { + + SPixelWeight* m_pPixelWeights; + int m_iMaxPixelCount; + int m_iStoredPixelCount; + +public: + + FORCEINLINE StorePixelWeightsPolicy(); + FORCEINLINE StorePixelWeightsPolicy(SPixelWeight* _pPixelWeights, int _iMaxPixelCount); + FORCEINLINE ~StorePixelWeightsPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); + + FORCEINLINE int getStoredPixelCount(); +}; + + +//---------------------------------------------------------------------------------------- +/** Policy For Calculating the Total Pixel Weight Multiplied by Sinogram + */ +class TotalPixelWeightBySinogramPolicy { + + CFloat32VolumeData2D* m_pPixelWeight; + CFloat32ProjectionData2D* m_pSinogram; + +public: + + FORCEINLINE TotalPixelWeightBySinogramPolicy(); + FORCEINLINE TotalPixelWeightBySinogramPolicy(CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pPixelWeight); + FORCEINLINE ~TotalPixelWeightBySinogramPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For Calculating the Total Pixel Weight + */ +class TotalPixelWeightPolicy { + + CFloat32VolumeData2D* m_pPixelWeight; + +public: + + FORCEINLINE TotalPixelWeightPolicy(); + FORCEINLINE TotalPixelWeightPolicy(CFloat32VolumeData2D* _pPixelWeight); + FORCEINLINE ~TotalPixelWeightPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For Calculating the the Total Ray Length + */ +class TotalRayLengthPolicy { + + CFloat32ProjectionData2D* m_pRayLength; + +public: + + FORCEINLINE TotalRayLengthPolicy(); + FORCEINLINE TotalRayLengthPolicy(CFloat32ProjectionData2D* _pRayLength); + FORCEINLINE ~TotalRayLengthPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + + +//---------------------------------------------------------------------------------------- +/** Policy For Combining Two Policies + */ +template<typename P1, typename P2> +class CombinePolicy { + + P1 policy1; + P2 policy2; + +public: + + FORCEINLINE CombinePolicy(); + FORCEINLINE CombinePolicy(P1 _policy1, P2 _policy2); + FORCEINLINE ~CombinePolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For Combining Three Policies + */ +template<typename P1, typename P2, typename P3> +class Combine3Policy { + + P1 policy1; + P2 policy2; + P3 policy3; + +public: + + FORCEINLINE Combine3Policy(); + FORCEINLINE Combine3Policy(P1 _policy1, P2 _policy2, P3 _policy3); + FORCEINLINE ~Combine3Policy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For Combining Four Policies + */ +template<typename P1, typename P2, typename P3, typename P4> +class Combine4Policy { + + P1 policy1; + P2 policy2; + P3 policy3; + P4 policy4; + +public: + + FORCEINLINE Combine4Policy(); + FORCEINLINE Combine4Policy(P1 _policy1, P2 _policy2, P3 _policy3, P4 _policy4); + FORCEINLINE ~Combine4Policy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For Combining a List of the same Policies + */ +template<typename P> +class CombineListPolicy { + + std::vector<P> policyList; + unsigned int size; + +public: + + FORCEINLINE CombineListPolicy(); + FORCEINLINE CombineListPolicy(std::vector<P> _policyList); + FORCEINLINE ~CombineListPolicy(); + + FORCEINLINE void addPolicy(P _policy); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Empty Policy + */ +class EmptyPolicy { + +public: + + FORCEINLINE EmptyPolicy(); + FORCEINLINE ~EmptyPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For SIRT Backprojection + */ +class SIRTBPPolicy { + + CFloat32ProjectionData2D* m_pSinogram; + CFloat32VolumeData2D* m_pReconstruction; + + CFloat32ProjectionData2D* m_pTotalRayLength; + CFloat32VolumeData2D* m_pTotalPixelWeight; + +public: + + FORCEINLINE SIRTBPPolicy(); + FORCEINLINE SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction, CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pTotalPixelWeight, CFloat32ProjectionData2D* _pTotalRayLength); + FORCEINLINE ~SIRTBPPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + + +//---------------------------------------------------------------------------------------- +/** Policy For Sinogram Mask + */ +class SinogramMaskPolicy { + + CFloat32ProjectionData2D* m_pSinogramMask; + +public: + + FORCEINLINE SinogramMaskPolicy(); + FORCEINLINE SinogramMaskPolicy(CFloat32ProjectionData2D* _pSinogramMask); + FORCEINLINE ~SinogramMaskPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- +/** Policy For Reconstruction Mask + */ +class ReconstructionMaskPolicy { + + CFloat32VolumeData2D* m_pReconstructionMask; + +public: + + FORCEINLINE ReconstructionMaskPolicy(); + FORCEINLINE ReconstructionMaskPolicy(CFloat32VolumeData2D* _pReconstructionMask); + FORCEINLINE ~ReconstructionMaskPolicy(); + + FORCEINLINE bool rayPrior(int _iRayIndex); + FORCEINLINE bool pixelPrior(int _iVolumeIndex); + FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight); + FORCEINLINE void rayPosterior(int _iRayIndex); + FORCEINLINE void pixelPosterior(int _iVolumeIndex); +}; + +//---------------------------------------------------------------------------------------- + +#include "DataProjectorPolicies.inl" + +} // end namespace + +#endif diff --git a/include/astra/DataProjectorPolicies.inl b/include/astra/DataProjectorPolicies.inl new file mode 100644 index 0000000..b2166c3 --- /dev/null +++ b/include/astra/DataProjectorPolicies.inl @@ -0,0 +1,855 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_DATAPROJECTORPOLICIES_INLINE +#define _INC_ASTRA_DATAPROJECTORPOLICIES_INLINE + + + +//---------------------------------------------------------------------------------------- +// DEFAULT FORWARD PROJECTION (Ray Driven) +//---------------------------------------------------------------------------------------- +DefaultFPPolicy::DefaultFPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +DefaultFPPolicy::DefaultFPPolicy(CFloat32VolumeData2D* _pVolumeData, + CFloat32ProjectionData2D* _pProjectionData) +{ + m_pProjectionData = _pProjectionData; + m_pVolumeData = _pVolumeData; +} +//---------------------------------------------------------------------------------------- +DefaultFPPolicy::~DefaultFPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool DefaultFPPolicy::rayPrior(int _iRayIndex) +{ + m_pProjectionData->getData()[_iRayIndex] = 0.0f; + return true; +} +//---------------------------------------------------------------------------------------- +bool DefaultFPPolicy::pixelPrior(int _iVolumeIndex) +{ + // do nothing + return true; +} +//---------------------------------------------------------------------------------------- +void DefaultFPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pProjectionData->getData()[_iRayIndex] += m_pVolumeData->getData()[_iVolumeIndex] * _fWeight; +} +//---------------------------------------------------------------------------------------- +void DefaultFPPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void DefaultFPPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------------------- +// DEFAULT BACK PROJECTION (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +DefaultBPPolicy::DefaultBPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +DefaultBPPolicy::DefaultBPPolicy(CFloat32VolumeData2D* _pVolumeData, + CFloat32ProjectionData2D* _pProjectionData) +{ + m_pProjectionData = _pProjectionData; + m_pVolumeData = _pVolumeData; +} +//---------------------------------------------------------------------------------------- +DefaultBPPolicy::~DefaultBPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool DefaultBPPolicy::rayPrior(int _iRayIndex) +{ + // do nothing + return true; +} +//---------------------------------------------------------------------------------------- +bool DefaultBPPolicy::pixelPrior(int _iVolumeIndex) +{ + // do nothing + return true; +} +//---------------------------------------------------------------------------------------- +void DefaultBPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pVolumeData->getData()[_iVolumeIndex] += m_pProjectionData->getData()[_iRayIndex] * _fWeight; +} +//---------------------------------------------------------------------------------------- +void DefaultBPPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void DefaultBPPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + + +//---------------------------------------------------------------------------------------- +// FORWARD PROJECTION DIFFERENCE CALCULATION (Ray Driven) +//---------------------------------------------------------------------------------------- +DiffFPPolicy::DiffFPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +DiffFPPolicy::DiffFPPolicy(CFloat32VolumeData2D* _pVolumeData, + CFloat32ProjectionData2D* _pDiffProjectionData, + CFloat32ProjectionData2D* _pBaseProjectionData) +{ + m_pDiffProjectionData = _pDiffProjectionData; + m_pBaseProjectionData = _pBaseProjectionData; + m_pVolumeData = _pVolumeData; +} +//---------------------------------------------------------------------------------------- +DiffFPPolicy::~DiffFPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- + bool DiffFPPolicy::rayPrior(int _iRayIndex) +{ + m_pDiffProjectionData->getData()[_iRayIndex] = m_pBaseProjectionData->getData()[_iRayIndex]; + return true; +} +//---------------------------------------------------------------------------------------- +bool DiffFPPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void DiffFPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pDiffProjectionData->getData()[_iRayIndex] -= m_pVolumeData->getData()[_iVolumeIndex] * _fWeight; +} +//---------------------------------------------------------------------------------------- +void DiffFPPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void DiffFPPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------------------- +// STORE PIXEL WEIGHT (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +StorePixelWeightsPolicy::StorePixelWeightsPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +StorePixelWeightsPolicy::StorePixelWeightsPolicy(SPixelWeight* _pPixelWeights, int _iMaxPixelCount) +{ + m_iStoredPixelCount = 0; + m_pPixelWeights = _pPixelWeights; + m_iMaxPixelCount = _iMaxPixelCount; +} +//---------------------------------------------------------------------------------------- +StorePixelWeightsPolicy::~StorePixelWeightsPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool StorePixelWeightsPolicy::rayPrior(int _iRayIndex) +{ + return (m_iStoredPixelCount < m_iMaxPixelCount); +} +//---------------------------------------------------------------------------------------- +bool StorePixelWeightsPolicy::pixelPrior(int _iVolumeIndex) +{ + return (m_iStoredPixelCount < m_iMaxPixelCount); +} +//---------------------------------------------------------------------------------------- +void StorePixelWeightsPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pPixelWeights[m_iStoredPixelCount].m_fWeight = _fWeight; + m_pPixelWeights[m_iStoredPixelCount].m_iIndex = _iVolumeIndex; + ++m_iStoredPixelCount; +} +//---------------------------------------------------------------------------------------- +void StorePixelWeightsPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void StorePixelWeightsPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +int StorePixelWeightsPolicy::getStoredPixelCount() +{ + return m_iStoredPixelCount; +} +//---------------------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------------------- +// TOTAL PIXEL WEIGHT MULTIPLIED BY SINOGRAM (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +TotalPixelWeightBySinogramPolicy::TotalPixelWeightBySinogramPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +TotalPixelWeightBySinogramPolicy::TotalPixelWeightBySinogramPolicy(CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pPixelWeight) +{ + m_pPixelWeight = _pPixelWeight; + m_pSinogram = _pSinogram; +} +//---------------------------------------------------------------------------------------- +TotalPixelWeightBySinogramPolicy::~TotalPixelWeightBySinogramPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool TotalPixelWeightBySinogramPolicy::rayPrior(int _iRayIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +bool TotalPixelWeightBySinogramPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void TotalPixelWeightBySinogramPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pPixelWeight->getData()[_iVolumeIndex] += _fWeight * m_pSinogram->getData()[_iRayIndex]; +} +//---------------------------------------------------------------------------------------- +void TotalPixelWeightBySinogramPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void TotalPixelWeightBySinogramPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + + + +//---------------------------------------------------------------------------------------- +// TOTAL PIXEL WEIGHT (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +TotalPixelWeightPolicy::TotalPixelWeightPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +TotalPixelWeightPolicy::TotalPixelWeightPolicy(CFloat32VolumeData2D* _pPixelWeight) +{ + m_pPixelWeight = _pPixelWeight; +} +//---------------------------------------------------------------------------------------- +TotalPixelWeightPolicy::~TotalPixelWeightPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool TotalPixelWeightPolicy::rayPrior(int _iRayIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +bool TotalPixelWeightPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void TotalPixelWeightPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pPixelWeight->getData()[_iVolumeIndex] += _fWeight; +} +//---------------------------------------------------------------------------------------- +void TotalPixelWeightPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void TotalPixelWeightPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + + +//---------------------------------------------------------------------------------------- +// TOTAL RAY LENGTH (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +TotalRayLengthPolicy::TotalRayLengthPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +TotalRayLengthPolicy::TotalRayLengthPolicy(CFloat32ProjectionData2D* _pRayLength) +{ + m_pRayLength = _pRayLength; +} +//---------------------------------------------------------------------------------------- +TotalRayLengthPolicy::~TotalRayLengthPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool TotalRayLengthPolicy::rayPrior(int _iRayIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +bool TotalRayLengthPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void TotalRayLengthPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + m_pRayLength->getData()[_iRayIndex] += _fWeight; +} +//---------------------------------------------------------------------------------------- +void TotalRayLengthPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void TotalRayLengthPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + + + +//---------------------------------------------------------------------------------------- +// COMBINE TWO POLICIES (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +CombinePolicy<P1,P2>::CombinePolicy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +CombinePolicy<P1,P2>::CombinePolicy(P1 _policy1, P2 _policy2) +{ + policy1 = _policy1; + policy2 = _policy2; +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +CombinePolicy<P1,P2>::~CombinePolicy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +bool CombinePolicy<P1,P2>::rayPrior(int _iRayIndex) +{ + if (!policy1.rayPrior(_iRayIndex)) return false; + return policy2.rayPrior(_iRayIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +bool CombinePolicy<P1,P2>::pixelPrior(int _iVolumeIndex) +{ + if (!policy1.pixelPrior(_iVolumeIndex)) return false; + return policy2.pixelPrior(_iVolumeIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +void CombinePolicy<P1,P2>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + policy1.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + policy2.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +void CombinePolicy<P1,P2>::rayPosterior(int _iRayIndex) +{ + policy1.rayPosterior(_iRayIndex); + policy2.rayPosterior(_iRayIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2> +void CombinePolicy<P1,P2>::pixelPosterior(int _iVolumeIndex) +{ + policy1.pixelPosterior(_iVolumeIndex); + policy2.pixelPosterior(_iVolumeIndex); +} +//---------------------------------------------------------------------------------------- + + + + +//---------------------------------------------------------------------------------------- +// COMBINE THREE POLICIES (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +Combine3Policy<P1,P2,P3>::Combine3Policy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +Combine3Policy<P1,P2,P3>::Combine3Policy(P1 _policy1, P2 _policy2, P3 _policy3) +{ + policy1 = _policy1; + policy2 = _policy2; + policy3 = _policy3; +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +Combine3Policy<P1,P2,P3>::~Combine3Policy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +bool Combine3Policy<P1,P2,P3>::rayPrior(int _iRayIndex) +{ + if (!policy1.rayPrior(_iRayIndex)) return false; + if (!policy2.rayPrior(_iRayIndex)) return false; + return policy3.rayPrior(_iRayIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +bool Combine3Policy<P1,P2,P3>::pixelPrior(int _iVolumeIndex) +{ + if (!policy1.pixelPrior(_iVolumeIndex)) return false; + if (!policy2.pixelPrior(_iVolumeIndex)) return false; + return policy3.pixelPrior(_iVolumeIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +void Combine3Policy<P1,P2,P3>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + policy1.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + policy2.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + policy3.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +void Combine3Policy<P1,P2,P3>::rayPosterior(int _iRayIndex) +{ + policy1.rayPosterior(_iRayIndex); + policy2.rayPosterior(_iRayIndex); + policy3.rayPosterior(_iRayIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3> +void Combine3Policy<P1,P2,P3>::pixelPosterior(int _iVolumeIndex) +{ + policy1.pixelPosterior(_iVolumeIndex); + policy2.pixelPosterior(_iVolumeIndex); + policy3.pixelPosterior(_iVolumeIndex); +} +//---------------------------------------------------------------------------------------- + + + + + + +//---------------------------------------------------------------------------------------- +// COMBINE FOUR POLICIES (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +Combine4Policy<P1,P2,P3,P4>::Combine4Policy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +Combine4Policy<P1,P2,P3,P4>::Combine4Policy(P1 _policy1, P2 _policy2, P3 _policy3, P4 _policy4) +{ + policy1 = _policy1; + policy2 = _policy2; + policy3 = _policy3; + policy4 = _policy4; +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +Combine4Policy<P1,P2,P3,P4>::~Combine4Policy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +bool Combine4Policy<P1,P2,P3,P4>::rayPrior(int _iRayIndex) +{ + if (!policy1.rayPrior(_iRayIndex)) return false; + if (!policy2.rayPrior(_iRayIndex)) return false; + if (!policy3.rayPrior(_iRayIndex)) return false; + return policy4.rayPrior(_iRayIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +bool Combine4Policy<P1,P2,P3,P4>::pixelPrior(int _iVolumeIndex) +{ + if (!policy1.pixelPrior(_iVolumeIndex)) return false; + if (!policy2.pixelPrior(_iVolumeIndex)) return false; + if (!policy3.pixelPrior(_iVolumeIndex)) return false; + return policy4.pixelPrior(_iVolumeIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +void Combine4Policy<P1,P2,P3,P4>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + policy1.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + policy2.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + policy3.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + policy4.addWeight(_iRayIndex, _iVolumeIndex, _fWeight); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +void Combine4Policy<P1,P2,P3,P4>::rayPosterior(int _iRayIndex) +{ + policy1.rayPosterior(_iRayIndex); + policy2.rayPosterior(_iRayIndex); + policy3.rayPosterior(_iRayIndex); + policy4.rayPosterior(_iRayIndex); +} +//---------------------------------------------------------------------------------------- +template<typename P1, typename P2, typename P3, typename P4> +void Combine4Policy<P1,P2,P3,P4>::pixelPosterior(int _iVolumeIndex) +{ + policy1.pixelPosterior(_iVolumeIndex); + policy2.pixelPosterior(_iVolumeIndex); + policy3.pixelPosterior(_iVolumeIndex); + policy4.pixelPosterior(_iVolumeIndex); +} +//---------------------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------------------- +// COMBINE LIST OF EQUAL POLICIES (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +template<typename P> +CombineListPolicy<P>::CombineListPolicy() +{ + size = 0; +} +//---------------------------------------------------------------------------------------- +template<typename P> +CombineListPolicy<P>::CombineListPolicy(std::vector<P> _policyList) +{ + policyList = _policyList; + size = policyList.size(); +} +//---------------------------------------------------------------------------------------- +template<typename P> +CombineListPolicy<P>::~CombineListPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +template<typename P> +void CombineListPolicy<P>::addPolicy(P _policy) +{ + policyList.push_back(_policy); + size = policyList.size(); +} +//---------------------------------------------------------------------------------------- +template<typename P> +bool CombineListPolicy<P>::rayPrior(int _iRayIndex) +{ + for(unsigned int i = 0; i < size; ++i) { + if (!policyList[i].rayPrior(_iRayIndex)) return false; + } + return true; +} +//---------------------------------------------------------------------------------------- +template<typename P> +bool CombineListPolicy<P>::pixelPrior(int _iVolumeIndex) +{ + for(unsigned int i = 0; i < size; ++i) { + if (!policyList[i].pixelPrior(_iVolumeIndex)) return false; + } + return true; +} +//---------------------------------------------------------------------------------------- +template<typename P> +void CombineListPolicy<P>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + for(unsigned int i = 0; i < size; ++i) { + policyList[i].addWeight(_iRayIndex, _iVolumeIndex, _fWeight); + } +} +//---------------------------------------------------------------------------------------- +template<typename P> +void CombineListPolicy<P>::rayPosterior(int _iRayIndex) +{ + for(unsigned int i = 0; i < size; ++i) { + policyList[i].rayPosterior(_iRayIndex); + } +} +//---------------------------------------------------------------------------------------- +template<typename P> +void CombineListPolicy<P>::pixelPosterior(int _iVolumeIndex) +{ + for(unsigned int i = 0; i < size; ++i) { + policyList[i].pixelPosterior(_iVolumeIndex); + } +} +//---------------------------------------------------------------------------------------- + + + + + +//---------------------------------------------------------------------------------------- +// EMPTY POLICY (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +EmptyPolicy::EmptyPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +EmptyPolicy::~EmptyPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool EmptyPolicy::rayPrior(int _iRayIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +bool EmptyPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void EmptyPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void EmptyPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void EmptyPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------------------- +// SIRT BACKPROJECTION (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +SIRTBPPolicy::SIRTBPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +SIRTBPPolicy::SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pTotalPixelWeight, + CFloat32ProjectionData2D* _pTotalRayLength) +{ + m_pReconstruction = _pReconstruction; + m_pSinogram = _pSinogram; + m_pTotalPixelWeight = _pTotalPixelWeight; + m_pTotalRayLength = _pTotalRayLength; +} +//---------------------------------------------------------------------------------------- +SIRTBPPolicy::~SIRTBPPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool SIRTBPPolicy::rayPrior(int _iRayIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +bool SIRTBPPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void SIRTBPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + float32 fGammaBeta = m_pTotalPixelWeight->getData()[_iVolumeIndex] * m_pTotalRayLength->getData()[_iRayIndex]; + if ((fGammaBeta > 0.001f) || (fGammaBeta < -0.001f)) { + m_pReconstruction->getData()[_iVolumeIndex] += _fWeight * m_pSinogram->getData()[_iRayIndex] / fGammaBeta; + } +} +//---------------------------------------------------------------------------------------- +void SIRTBPPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void SIRTBPPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + + + +//---------------------------------------------------------------------------------------- +// SINOGRAM MASK (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +SinogramMaskPolicy::SinogramMaskPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +SinogramMaskPolicy::SinogramMaskPolicy(CFloat32ProjectionData2D* _pSinogramMask) +{ + m_pSinogramMask = _pSinogramMask; +} +//---------------------------------------------------------------------------------------- +SinogramMaskPolicy::~SinogramMaskPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool SinogramMaskPolicy::rayPrior(int _iRayIndex) +{ + return (m_pSinogramMask->getData()[_iRayIndex] != 0); +} +//---------------------------------------------------------------------------------------- +bool SinogramMaskPolicy::pixelPrior(int _iVolumeIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +void SinogramMaskPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void SinogramMaskPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void SinogramMaskPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + + + +//---------------------------------------------------------------------------------------- +// RECONSTRUCTION MASK (Ray+Pixel Driven) +//---------------------------------------------------------------------------------------- +ReconstructionMaskPolicy::ReconstructionMaskPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +ReconstructionMaskPolicy::ReconstructionMaskPolicy(CFloat32VolumeData2D* _pReconstructionMask) +{ + m_pReconstructionMask = _pReconstructionMask; +} +//---------------------------------------------------------------------------------------- +ReconstructionMaskPolicy::~ReconstructionMaskPolicy() +{ + +} +//---------------------------------------------------------------------------------------- +bool ReconstructionMaskPolicy::rayPrior(int _iRayIndex) +{ + return true; +} +//---------------------------------------------------------------------------------------- +bool ReconstructionMaskPolicy::pixelPrior(int _iVolumeIndex) +{ + return (m_pReconstructionMask->getData()[_iVolumeIndex] != 0); +} +//---------------------------------------------------------------------------------------- +void ReconstructionMaskPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void ReconstructionMaskPolicy::rayPosterior(int _iRayIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- +void ReconstructionMaskPolicy::pixelPosterior(int _iVolumeIndex) +{ + // nothing +} +//---------------------------------------------------------------------------------------- + + + +#endif diff --git a/include/astra/FanFlatBeamLineKernelProjector2D.h b/include/astra/FanFlatBeamLineKernelProjector2D.h new file mode 100644 index 0000000..154504a --- /dev/null +++ b/include/astra/FanFlatBeamLineKernelProjector2D.h @@ -0,0 +1,194 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FANFLATBEAMLINEKERNELPROJECTOR +#define _INC_ASTRA_FANFLATBEAMLINEKERNELPROJECTOR + +#include "FanFlatProjectionGeometry2D.h" +#include "FanFlatVecProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +namespace astra +{ + + +/** This class implements a two-dimensional projector based on a line based kernel + * with a fan flat projection geometry. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('fanflat_line');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CFanFlatBeamLineKernelProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CFanFlatBeamLineKernelProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CFanFlatBeamLineKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CFanFlatBeamLineKernelProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @return initialization successful? + */ + virtual bool initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Wwhich projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + + float32 angleBetweenVectors(float32 _fAX, float32 _fAY, float32 _fBX, float32 _fBY); + +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CFanFlatBeamLineKernelProjector2D::getType() +{ + return type; +} + + +} // namespace astra + +#endif + diff --git a/include/astra/FanFlatBeamLineKernelProjector2D.inl b/include/astra/FanFlatBeamLineKernelProjector2D.inl new file mode 100644 index 0000000..e686532 --- /dev/null +++ b/include/astra/FanFlatBeamLineKernelProjector2D.inl @@ -0,0 +1,740 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +using namespace astra; + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CFanFlatBeamLineKernelProjector2D::project(Policy& p) +{ + // variables + float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY; + int iVolumeIndex, iRayIndex, row, col, iAngle, iDetector, x1; + bool switch_t; + + const CFanFlatProjectionGeometry2D* pProjectionGeometry = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry); + const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry); + + float32 old_theta, theta, alpha; + const SFanProjection * proj = 0; + + // loop angles + for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { + + // get theta + if (pProjectionGeometry) { + old_theta = pProjectionGeometry->getProjectionAngle(iAngle); + } + else if (pVecProjectionGeometry) { + proj = &pVecProjectionGeometry->getProjectionVectors()[iAngle]; + old_theta = atan2(-proj->fSrcX, proj->fSrcY); + if (old_theta < 0) old_theta += 2*PI; + } else { + assert(false); + } + + switch_t = false; + if (old_theta >= 7*PIdiv4) old_theta -= 2*PI; + if (old_theta >= 3*PIdiv4) { + old_theta -= PI; + switch_t = true; + } + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get values + if (pProjectionGeometry) { + t = -pProjectionGeometry->indexToDetectorOffset(iDetector); + alpha = atan(t / pProjectionGeometry->getSourceDetectorDistance()); + t = sin(alpha) * pProjectionGeometry->getOriginSourceDistance(); + } + else if (pVecProjectionGeometry) { + float32 detX = proj->fDetSX + proj->fDetUX*(0.5f + iDetector); + float32 detY = proj->fDetSY + proj->fDetUY*(0.5f + iDetector); + alpha = angleBetweenVectors(-proj->fSrcX, -proj->fSrcY, detX - proj->fSrcX, detY - proj->fSrcY); + t = sin(alpha) * sqrt(proj->fSrcX*proj->fSrcX + proj->fSrcY*proj->fSrcY); + } else { + assert(false); + } + + if (switch_t) t = -t; + theta = old_theta + alpha; + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_sin_theta = 1.0f / sin_theta; + inv_cos_theta = 1.0f / cos_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // precalculate S and T + S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow); + T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol); + + // vertically + if (old_theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerRow; + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue; + + // left + if (x2 < 0.5f-S) { + I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridColCount()*/) {//x1 is always less than or equal to gridColCount because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+S) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // right + else if (x2 <= 1.0f) { + I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridColCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } + + // horizontally + //else if (PIdiv4 <= old_theta && old_theta <= 3*PIdiv4) { + else { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerCol; + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue; + + // up + if (x2 < 0.5f-T) { + I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridRowCount()*/) {//x1 is always less than or equal to gridRowCount because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+T) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // down + else if (x2 <= 1.0f) { + I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridRowCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } // end loop col + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end loop detector + } // end loop angles +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CFanFlatBeamLineKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + // variables + float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY; + int iVolumeIndex, iRayIndex, row, col, iDetector, x1; + bool switch_t; + + const CFanFlatProjectionGeometry2D* pProjectionGeometry = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry); + const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry); + + float32 old_theta, theta, alpha; + const SFanProjection * proj = 0; + + //get theta + if (pProjectionGeometry) { + old_theta = pProjectionGeometry->getProjectionAngle(_iProjection); + } + else if (pVecProjectionGeometry) { + proj = &pVecProjectionGeometry->getProjectionVectors()[_iProjection]; + old_theta = atan2(-proj->fSrcX, proj->fSrcY); + if (old_theta < 0) old_theta += 2*PI; + } else { + assert(false); + } + + switch_t = false; + if (old_theta >= 7*PIdiv4) old_theta -= 2*PI; + if (old_theta >= 3*PIdiv4) { + old_theta -= PI; + switch_t = true; + } + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + if (pProjectionGeometry) { + t = -pProjectionGeometry->indexToDetectorOffset(iDetector); + alpha = atan(t / pProjectionGeometry->getSourceDetectorDistance()); + t = sin(alpha) * pProjectionGeometry->getOriginSourceDistance(); + } + else if (pVecProjectionGeometry) { + float32 detX = proj->fDetSX + proj->fDetUX*(0.5f + iDetector); + float32 detY = proj->fDetSY + proj->fDetUY*(0.5f + iDetector); + alpha = angleBetweenVectors(-proj->fSrcX, -proj->fSrcY, detX - proj->fSrcX, detY - proj->fSrcY); + t = sin(alpha) * sqrt(proj->fSrcX*proj->fSrcX + proj->fSrcY*proj->fSrcY); + } else { + assert(false); + } + + if (switch_t) t = -t; + theta = old_theta + alpha; + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_sin_theta = 1.0f / sin_theta; + inv_cos_theta = 1.0f / cos_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // precalculate S and T + S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow); + T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol); + + // vertically + if (old_theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerRow; + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue; + + // left + if (x2 < 0.5f-S) { + I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridColCount()*/) {//x1 is always less than or equal to gridColCount because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+S) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // right + else if (x2 <= 1.0f) { + I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridColCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } + + // horizontally + else { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerCol; + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue; + + // up + if (x2 < 0.5f-T) { + I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridRowCount()*/) {//x1 is always less than or equal to gridRowCount because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+T) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // down + else if (x2 <= 1.0f) { + I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridRowCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } // end loop col + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end loop detector + +} + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CFanFlatBeamLineKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + // variables + float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY; + int iVolumeIndex, iRayIndex, row, col, x1; + bool switch_t; + + const CFanFlatProjectionGeometry2D* pProjectionGeometry = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry); + const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry); + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) return; + + float32 old_theta, theta, alpha; + if (pProjectionGeometry) { + old_theta = pProjectionGeometry->getProjectionAngle(_iProjection); + t = -pProjectionGeometry->indexToDetectorOffset(_iDetector); + alpha = atan(t / pProjectionGeometry->getSourceDetectorDistance()); + t = sin(alpha) * pProjectionGeometry->getOriginSourceDistance(); + } + else if (pVecProjectionGeometry) { + const SFanProjection * proj = &pVecProjectionGeometry->getProjectionVectors()[_iProjection]; + old_theta = atan2(-proj->fSrcX, proj->fSrcY); + if (old_theta < 0) old_theta += 2*PI; + + float32 detX = proj->fDetSX + proj->fDetUX*(0.5f + _iDetector); + float32 detY = proj->fDetSY + proj->fDetUY*(0.5f + _iDetector); + alpha = angleBetweenVectors(-proj->fSrcX, -proj->fSrcY, detX - proj->fSrcX, detY - proj->fSrcY); + t = sin(alpha) * sqrt(proj->fSrcX*proj->fSrcX + proj->fSrcY*proj->fSrcY); + } else { + assert(false); + } + + switch_t = false; + if (old_theta >= 7*PIdiv4) old_theta -= 2*PI; + if (old_theta >= 3*PIdiv4) { + old_theta -= PI; + switch_t = true; + } + if (switch_t) t = -t; + theta = old_theta + alpha; + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_sin_theta = 1.0f / sin_theta; + inv_cos_theta = 1.0f / cos_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // precalculate S and T + S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow); + T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol); + + // vertically + if (old_theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerRow; + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue; + + // left + if (x2 < 0.5f-S) { + I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridColCount()*/) {//x1 is always less than or equal to gridColCount because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+S) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // right + else if (x2 <= 1.0f) { + I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridColCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } + + // horizontally + else { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerCol; + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue; + + // up + if (x2 < 0.5f-T) { + I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridRowCount()*/) {//x1 is always less than or equal to gridRowCount because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+T) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // down + else if (x2 <= 1.0f) { + I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridRowCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } // end loop col + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); +} diff --git a/include/astra/FanFlatBeamStripKernelProjector2D.h b/include/astra/FanFlatBeamStripKernelProjector2D.h new file mode 100644 index 0000000..7fed4c8 --- /dev/null +++ b/include/astra/FanFlatBeamStripKernelProjector2D.h @@ -0,0 +1,191 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FANFLATBEAMSTRIPKERNELPROJECTOR +#define _INC_ASTRA_FANFLATBEAMSTRIPKERNELPROJECTOR + +#include "FanFlatProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +namespace astra +{ + + +/** This class implements a two-dimensional fan-flat-beam projector based on a strip based kernel. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('strip_fanflat');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CFanFlatBeamStripKernelProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CFanFlatBeamStripKernelProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CFanFlatBeamStripKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CFanFlatBeamStripKernelProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @return initialization successful? + */ + virtual bool initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Wwhich projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CFanFlatBeamStripKernelProjector2D::getType() +{ + return type; +} + +} // namespace astra + + + +#endif + diff --git a/include/astra/FanFlatBeamStripKernelProjector2D.inl b/include/astra/FanFlatBeamStripKernelProjector2D.inl new file mode 100644 index 0000000..e3f8b29 --- /dev/null +++ b/include/astra/FanFlatBeamStripKernelProjector2D.inl @@ -0,0 +1,961 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +using namespace astra; + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CFanFlatBeamStripKernelProjector2D::project(Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + // Some variables + float32 theta; + int row, col; + int iAngle, iDetector; + float32 res; + int x1L, x1R; + float32 x2L, x2R; + int iVolumeIndex, iRayIndex; + + CFanFlatProjectionGeometry2D* projgeom = static_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry); + + // Other precalculations + float32 PW = m_pVolumeGeometry->getPixelLengthX(); + float32 PH = m_pVolumeGeometry->getPixelLengthY(); + float32 DW = m_pProjectionGeometry->getDetectorWidth(); + float32 inv_PW = 1.0f / PW; + float32 inv_PH = 1.0f / PH; + + // calculate alpha's + float32 alpha; + float32* cos_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1]; + float32* sin_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1]; + for (int i = 0; i < m_pProjectionGeometry->getDetectorCount() + 1; ++i) { + alpha = -atan((i - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW / projgeom->getSourceDetectorDistance()); + cos_alpha[i] = cos(alpha); + sin_alpha[i] = sin(alpha); + } + + // loop angles + for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { + + // get values + theta = m_pProjectionGeometry->getProjectionAngle(iAngle); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // Precalculate sin, cos, 1/cos + float32 sin_theta = sin(theta); + float32 cos_theta = cos(theta); + + // [-45?,45?] and [135?,225?] + if (theta < PIdiv4) { + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + float32 sin_theta_left, cos_theta_left; + float32 sin_theta_right, cos_theta_right; + + // get theta_l = alpha_left + theta and theta_r = alpha_right + theta + float32 t_l, t_r; + if (!switch_t) { + sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + + cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + + t_l = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + t_r = sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + + } else { + sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + + cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + + t_l = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + t_r = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + } + + float32 inv_cos_theta_left = 1.0f / cos_theta_left; + float32 inv_cos_theta_right = 1.0f / cos_theta_right; + + float32 updateX_left = sin_theta_left * inv_cos_theta_left; + float32 updateX_right = sin_theta_right * inv_cos_theta_right; + + // Precalculate kernel limits + float32 S_l = -0.5f * updateX_left; + if (S_l > 0) {S_l = -S_l;} + float32 T_l = -S_l; + float32 U_l = 1.0f + S_l; + float32 V_l = 1.0f - S_l; + float32 inv_4T_l = 0.25f / T_l; + + float32 S_r = -0.5f * updateX_right; + if (S_r > 0) {S_r = -S_r;} + float32 T_r = -S_r; + float32 U_r = 1.0f + S_r; + float32 V_r = 1.0f - S_r; + float32 inv_4T_r = 0.25f / T_r; + + // calculate strip extremes (volume coordinates) + float32 PL = (t_l - sin_theta_left * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_left; + float32 PR = (t_r - sin_theta_right * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_right; + float32 PLimitL = PL + S_l * PH; + float32 PLimitR = PR - S_r * PH; + + // calculate strip extremes (pixel coordinates) + float32 XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 xR = (PR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX_left; + XLimitR += updateX_right; + xL += updateX_left; + xR += updateX_right; + + // for each affected col + for (col = x1L; col <= x1R; ++col) { + + if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V_r) res = 1.0f; + else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r; + else if (x2R >= T_r) res = x2R; + else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S_l) {} + else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l; + else if (x2L <= U_l) res -= x2L; + else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + // [45?,135?] and [225?,315?] + // horizontaly + } else { + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get theta_l = alpha_left + theta and theta_r = alpha_right + theta + float32 sin_theta_left, cos_theta_left; + float32 sin_theta_right, cos_theta_right; + float32 t_l, t_r; + if (!switch_t) { + sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + + cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + + t_l = sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + t_r = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + + } else { + sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + + cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + + t_l = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + t_r = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + } + + float32 inv_sin_theta_left = 1.0f / sin_theta_left; + float32 inv_sin_theta_right = 1.0f / sin_theta_right; + + float32 updateX_left = cos_theta_left * inv_sin_theta_left; + float32 updateX_right = cos_theta_right * inv_sin_theta_right; + + // Precalculate kernel limits + float32 S_l = -0.5f * updateX_left; + if (S_l > 0) { S_l = -S_l; } + float32 T_l = -S_l; + float32 U_l = 1.0f + S_l; + float32 V_l = 1.0f - S_l; + float32 inv_4T_l = 0.25f / T_l; + + float32 S_r = -0.5f * updateX_right; + if (S_r > 0) { S_r = -S_r; } + float32 T_r = -S_r; + float32 U_r = 1.0f + S_r; + float32 V_r = 1.0f - S_r; + float32 inv_4T_r = 0.25f / T_r; + + // calculate strip extremes (volume coordinates) + float32 PL = (t_l - cos_theta_left * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_left; + float32 PR = (t_r - cos_theta_right * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_right; + float32 PLimitL = PL - S_l * PW; + float32 PLimitR = PR + S_r * PW; + + // calculate strip extremes (pixel coordinates) + float32 XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH; + float32 XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH; + float32 xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH; + float32 xR = (m_pVolumeGeometry->getWindowMaxY() - PR) * inv_PH; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX_left; + XLimitR += updateX_right; + xL += updateX_left; + xR += updateX_right; + + // for each affected row + for (row = x1L; row <= x1R; ++row) { + + if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V_r) res = 1.0f; + else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r; + else if (x2R >= T_r) res = x2R; + else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S_l) {} + else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l; + else if (x2L <= U_l) res -= x2L; + else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + } // end theta switch + + } // end angle loop + + delete[] cos_alpha; + delete[] sin_alpha; +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CFanFlatBeamStripKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + // Some variables + float32 theta; + int row, col; + int iDetector; + float32 res; + int x1L, x1R; + float32 x2L, x2R; + int iVolumeIndex, iRayIndex; + + CFanFlatProjectionGeometry2D* projgeom = static_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry); + + // Other precalculations + float32 PW = m_pVolumeGeometry->getPixelLengthX(); + float32 PH = m_pVolumeGeometry->getPixelLengthY(); + float32 DW = m_pProjectionGeometry->getDetectorWidth(); + float32 inv_PW = 1.0f / PW; + float32 inv_PH = 1.0f / PH; + + // calculate alpha's + float32 alpha; + float32* cos_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1]; + float32* sin_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1]; + for (int i = 0; i < m_pProjectionGeometry->getDetectorCount() + 1; ++i) { + alpha = -atan((i - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW / projgeom->getSourceDetectorDistance()); + cos_alpha[i] = cos(alpha); + sin_alpha[i] = sin(alpha); + } + + + // get values + theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // Precalculate sin, cos, 1/cos + float32 sin_theta = sin(theta); + float32 cos_theta = cos(theta); + + // [-45?,45?] and [135?,225?] + if (theta < PIdiv4) { + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + float32 sin_theta_left, cos_theta_left; + float32 sin_theta_right, cos_theta_right; + + // get theta_l = alpha_left + theta and theta_r = alpha_right + theta + float32 t_l, t_r; + if (!switch_t) { + sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + + cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + + t_l = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + t_r = sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + + } else { + sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + + cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + + t_l = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + t_r = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + } + + float32 inv_cos_theta_left = 1.0f / cos_theta_left; + float32 inv_cos_theta_right = 1.0f / cos_theta_right; + + float32 updateX_left = sin_theta_left * inv_cos_theta_left; + float32 updateX_right = sin_theta_right * inv_cos_theta_right; + + // Precalculate kernel limits + float32 S_l = -0.5f * updateX_left; + if (S_l > 0) {S_l = -S_l;} + float32 T_l = -S_l; + float32 U_l = 1.0f + S_l; + float32 V_l = 1.0f - S_l; + float32 inv_4T_l = 0.25f / T_l; + + float32 S_r = -0.5f * updateX_right; + if (S_r > 0) {S_r = -S_r;} + float32 T_r = -S_r; + float32 U_r = 1.0f + S_r; + float32 V_r = 1.0f - S_r; + float32 inv_4T_r = 0.25f / T_r; + + // calculate strip extremes (volume coordinates) + float32 PL = (t_l - sin_theta_left * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_left; + float32 PR = (t_r - sin_theta_right * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_right; + float32 PLimitL = PL + S_l * PH; + float32 PLimitR = PR - S_r * PH; + + // calculate strip extremes (pixel coordinates) + float32 XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 xR = (PR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX_left; + XLimitR += updateX_right; + xL += updateX_left; + xR += updateX_right; + + // for each affected col + for (col = x1L; col <= x1R; ++col) { + + if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V_r) res = 1.0f; + else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r; + else if (x2R >= T_r) res = x2R; + else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S_l) {} + else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l; + else if (x2L <= U_l) res -= x2L; + else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + // [45?,135?] and [225?,315?] + // horizontaly + } else { + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get theta_l = alpha_left + theta and theta_r = alpha_right + theta + float32 sin_theta_left, cos_theta_left; + float32 sin_theta_right, cos_theta_right; + float32 t_l, t_r; + if (!switch_t) { + sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + + cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + + t_l = sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + t_r = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + + } else { + sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1]; + sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector]; + + cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1]; + cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector]; + + t_l = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance(); + t_r = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance(); + } + + float32 inv_sin_theta_left = 1.0f / sin_theta_left; + float32 inv_sin_theta_right = 1.0f / sin_theta_right; + + float32 updateX_left = cos_theta_left * inv_sin_theta_left; + float32 updateX_right = cos_theta_right * inv_sin_theta_right; + + // Precalculate kernel limits + float32 S_l = -0.5f * updateX_left; + if (S_l > 0) { S_l = -S_l; } + float32 T_l = -S_l; + float32 U_l = 1.0f + S_l; + float32 V_l = 1.0f - S_l; + float32 inv_4T_l = 0.25f / T_l; + + float32 S_r = -0.5f * updateX_right; + if (S_r > 0) { S_r = -S_r; } + float32 T_r = -S_r; + float32 U_r = 1.0f + S_r; + float32 V_r = 1.0f - S_r; + float32 inv_4T_r = 0.25f / T_r; + + // calculate strip extremes (volume coordinates) + float32 PL = (t_l - cos_theta_left * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_left; + float32 PR = (t_r - cos_theta_right * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_right; + float32 PLimitL = PL - S_l * PW; + float32 PLimitR = PR + S_r * PW; + + // calculate strip extremes (pixel coordinates) + float32 XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH; + float32 XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH; + float32 xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH; + float32 xR = (m_pVolumeGeometry->getWindowMaxY() - PR) * inv_PH; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX_left; + XLimitR += updateX_right; + xL += updateX_left; + xR += updateX_right; + + // for each affected row + for (row = x1L; row <= x1R; ++row) { + + if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V_r) res = 1.0f; + else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r; + else if (x2R >= T_r) res = x2R; + else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S_l) {} + else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l; + else if (x2L <= U_l) res -= x2L; + else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + } // end theta switch + + delete[] cos_alpha; + delete[] sin_alpha; +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CFanFlatBeamStripKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + // Some variables + float32 theta; + int row, col; + float32 res; + int x1L, x1R; + float32 x2L, x2R; + int iVolumeIndex, iRayIndex; + + CFanFlatProjectionGeometry2D* projgeom = static_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry); + + // Other precalculations + float32 PW = m_pVolumeGeometry->getPixelLengthX(); + float32 PH = m_pVolumeGeometry->getPixelLengthY(); + float32 DW = m_pProjectionGeometry->getDetectorWidth(); + float32 inv_PW = 1.0f / PW; + float32 inv_PH = 1.0f / PH; + + // calculate alpha's + float32 alpha; + float32* cos_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1]; + float32* sin_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1]; + for (int i = 0; i < m_pProjectionGeometry->getDetectorCount() + 1; ++i) { + alpha = -atan((i - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW / projgeom->getSourceDetectorDistance()); + cos_alpha[i] = cos(alpha); + sin_alpha[i] = sin(alpha); + } + + + // get values + theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // Precalculate sin, cos, 1/cos + float32 sin_theta = sin(theta); + float32 cos_theta = cos(theta); + + // [-45?,45?] and [135?,225?] + if (theta < PIdiv4) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) { delete[] cos_alpha; delete[] sin_alpha; return; } + + float32 sin_theta_left, cos_theta_left; + float32 sin_theta_right, cos_theta_right; + + // get theta_l = alpha_left + theta and theta_r = alpha_right + theta + float32 t_l, t_r; + if (!switch_t) { + sin_theta_left = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1]; + sin_theta_right = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector]; + + cos_theta_left = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1]; + cos_theta_right = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector]; + + t_l = sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance(); + t_r = sin_alpha[_iDetector] * projgeom->getOriginSourceDistance(); + + } else { + sin_theta_left = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector]; + sin_theta_right = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1]; + + cos_theta_left = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector]; + cos_theta_right = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1]; + + t_l = -sin_alpha[_iDetector] * projgeom->getOriginSourceDistance(); + t_r = -sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance(); + } + + float32 inv_cos_theta_left = 1.0f / cos_theta_left; + float32 inv_cos_theta_right = 1.0f / cos_theta_right; + + float32 updateX_left = sin_theta_left * inv_cos_theta_left; + float32 updateX_right = sin_theta_right * inv_cos_theta_right; + + // Precalculate kernel limits + float32 S_l = -0.5f * updateX_left; + if (S_l > 0) {S_l = -S_l;} + float32 T_l = -S_l; + float32 U_l = 1.0f + S_l; + float32 V_l = 1.0f - S_l; + float32 inv_4T_l = 0.25f / T_l; + + float32 S_r = -0.5f * updateX_right; + if (S_r > 0) {S_r = -S_r;} + float32 T_r = -S_r; + float32 U_r = 1.0f + S_r; + float32 V_r = 1.0f - S_r; + float32 inv_4T_r = 0.25f / T_r; + + // calculate strip extremes (volume coordinates) + float32 PL = (t_l - sin_theta_left * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_left; + float32 PR = (t_r - sin_theta_right * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_right; + float32 PLimitL = PL + S_l * PH; + float32 PLimitR = PR - S_r * PH; + + // calculate strip extremes (pixel coordinates) + float32 XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + float32 xR = (PR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX_left; + XLimitR += updateX_right; + xL += updateX_left; + xR += updateX_right; + + // for each affected col + for (col = x1L; col <= x1R; ++col) { + + if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V_r) res = 1.0f; + else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r; + else if (x2R >= T_r) res = x2R; + else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S_l) {} + else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l; + else if (x2L <= U_l) res -= x2L; + else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + // [45?,135?] and [225?,315?] + // horizontaly + } else { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) { delete[] cos_alpha; delete[] sin_alpha; return; } + + // get theta_l = alpha_left + theta and theta_r = alpha_right + theta + float32 sin_theta_left, cos_theta_left; + float32 sin_theta_right, cos_theta_right; + float32 t_l, t_r; + if (!switch_t) { + sin_theta_left = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector]; + sin_theta_right = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1]; + + cos_theta_left = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector]; + cos_theta_right = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1]; + + t_l = sin_alpha[_iDetector] * projgeom->getOriginSourceDistance(); + t_r = sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance(); + + } else { + sin_theta_left = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1]; + sin_theta_right = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector]; + + cos_theta_left = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1]; + cos_theta_right = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector]; + + t_l = -sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance(); + t_r = -sin_alpha[_iDetector] * projgeom->getOriginSourceDistance(); + } + + float32 inv_sin_theta_left = 1.0f / sin_theta_left; + float32 inv_sin_theta_right = 1.0f / sin_theta_right; + + float32 updateX_left = cos_theta_left * inv_sin_theta_left; + float32 updateX_right = cos_theta_right * inv_sin_theta_right; + + // Precalculate kernel limits + float32 S_l = -0.5f * updateX_left; + if (S_l > 0) { S_l = -S_l; } + float32 T_l = -S_l; + float32 U_l = 1.0f + S_l; + float32 V_l = 1.0f - S_l; + float32 inv_4T_l = 0.25f / T_l; + + float32 S_r = -0.5f * updateX_right; + if (S_r > 0) { S_r = -S_r; } + float32 T_r = -S_r; + float32 U_r = 1.0f + S_r; + float32 V_r = 1.0f - S_r; + float32 inv_4T_r = 0.25f / T_r; + + // calculate strip extremes (volume coordinates) + float32 PL = (t_l - cos_theta_left * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_left; + float32 PR = (t_r - cos_theta_right * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_right; + float32 PLimitL = PL - S_l * PW; + float32 PLimitR = PR + S_r * PW; + + // calculate strip extremes (pixel coordinates) + float32 XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH; + float32 XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH; + float32 xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH; + float32 xR = (m_pVolumeGeometry->getWindowMaxY() - PR) * inv_PH; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX_left; + XLimitR += updateX_right; + xL += updateX_left; + xR += updateX_right; + + // for each affected row + for (row = x1L; row <= x1R; ++row) { + + if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V_r) res = 1.0f; + else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r; + else if (x2R >= T_r) res = x2R; + else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S_l) {} + else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l; + else if (x2L <= U_l) res -= x2L; + else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end theta switch + + delete[] cos_alpha; + delete[] sin_alpha; +} diff --git a/include/astra/FanFlatProjectionGeometry2D.h b/include/astra/FanFlatProjectionGeometry2D.h new file mode 100644 index 0000000..0e790ae --- /dev/null +++ b/include/astra/FanFlatProjectionGeometry2D.h @@ -0,0 +1,244 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FANFLATPROJECTIONGEOMETRY2D +#define _INC_ASTRA_FANFLATPROJECTIONGEOMETRY2D + +#include "ProjectionGeometry2D.h" + +#include <cmath> + +namespace astra +{ + +/** + * This class defines a 2D fan beam geometry with a flat detector that has equally spaced detector cells. + * + * \par XML Configuration + * \astra_xml_item{DetectorCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorWidth, float, Width of each detector.} + * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.} + * \astra_xml_item{DistanceOriginDetector, float, Distance between the center of rotation and the detectorarray.} + * \astra_xml_item{DistanceOriginSource, float, Distance between the center of rotation the the x-ray source.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('fanflat');\n + * proj_geom.DetectorCount = 512;\n + * proj_geom.DetectorWidth = 1.0;\n + * proj_geom.ProjectionAngles = linspace(0,pi,100);\n + * proj_geom.DistanceOriginDetector = 300;\n + * proj_geom.DistanceOriginSource = 300;\n + * } + */ +class _AstraExport CFanFlatProjectionGeometry2D : public CProjectionGeometry2D +{ + /** + * Distance from the origin of the coordinate system to the source. + */ + float32 m_fOriginSourceDistance; + + /** + * Distance from the origin of the coordinate system to the detector (i.e., the distance between the origin and its orthogonal projection + * onto the detector array). + */ + float32 m_fOriginDetectorDistance; + +public: + + /** Default constructor. Sets all variables to zero. Note that this constructor leaves the object in an unusable state and must + * be followed by a call to init(). + */ + CFanFlatProjectionGeometry2D(); + + /** Constructor. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + * All angles are represented in radians. + * @param _fOriginSourceDistance Distance from the origin of the coordinate system to the source + * @param _fOriginDetectorDistance Distance from the origin of the coordinate system to the detector + */ + CFanFlatProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance); + + /** Copy constructor. + */ + CFanFlatProjectionGeometry2D(const CFanFlatProjectionGeometry2D& _projGeom); + + /** Assignment operator. + */ + CFanFlatProjectionGeometry2D& operator=(const CFanFlatProjectionGeometry2D& _other); + + /** Destructor. + */ + virtual ~CFanFlatProjectionGeometry2D(); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialization. This function MUST be called after using the default constructor and MAY be called to + * reset a previously initialized object. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + * @param _fOriginSourceDistance Distance from the origin of the coordinate system to the source + * @param _fOriginDetectorDistance Distance from the origin of the coordinate system to the detector + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance); + + /** Create a hard copy. + */ + virtual CProjectionGeometry2D* clone(); + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "fanflat". + */ + virtual bool isOfType(const std::string& _sType); + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(CProjectionGeometry2D*) const; + + /** Returns the distance from the origin of the coordinate system to the source. + * + * @return Distance from the origin of the coordinate system to the source + */ + float32 getOriginSourceDistance() const; + + /** Returns the distance from the origin of the coordinate system to the detector + * (i.e., the distance between the origin and its orthogonal projection onto the detector array). + * + * @return Distance from the origin of the coordinate system to the detector + */ + float32 getOriginDetectorDistance() const; + + /** Returns the distance from the source to the detector + * (i.e., the distance between the source and its orthogonal projection onto the detector array). + * + * @return Distance from the source to the detector + */ + float32 getSourceDetectorDistance() const; + + /** Get the value for t and theta, based upon the row and column index. + * + * @param _iRow row index + * @param _iColumn column index + * @param _fT output: value of t + * @param _fTheta output: value of theta, always lies within the [0,pi[ interval. + */ + virtual void getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const; + + /** + * Returns a vector describing the direction of a ray belonging to a certain detector + * + * @param _iProjectionIndex index of projection + * @param _iProjectionIndex index of detector + * + * @return a unit vector describing the direction + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex); +}; + + + +// Returns the distance from the origin of the coordinate system to the source. +inline float32 CFanFlatProjectionGeometry2D::getOriginSourceDistance() const +{ + return m_fOriginSourceDistance; +} + + +// Returns the distance from the origin of the coordinate system to the detector. +inline float32 CFanFlatProjectionGeometry2D::getOriginDetectorDistance() const +{ + return m_fOriginDetectorDistance; +} + + +// Returns the distance from the source to the detector. +inline float32 CFanFlatProjectionGeometry2D::getSourceDetectorDistance() const +{ + return (m_fOriginSourceDistance + m_fOriginDetectorDistance); +} + + +// Get T and Theta +inline void CFanFlatProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const +{ + assert(m_bInitialized); + + // get the distance between the center of the detector array and the detector. + float32 det_offset = indexToDetectorOffset(_iColumn); + + // get the angle between the center ray of the projection and the projection. + float32 alpha = atan(det_offset / getSourceDetectorDistance()); + + // calculate t and theta + _fT = m_fOriginSourceDistance * sin(alpha); + _fTheta = getProjectionAngle(_iRow) + alpha; + + // if theta is larger than pi, flip of the origin + if (PI <= _fTheta) { + _fTheta -= PI; + _fT = -_fT; + } + // if theta is below 0, flip + if (_fTheta < 0) { + _fTheta += PI; + _fT = -_fT; + } +} + + + +} // namespace astra + +#endif /* _INC_ASTRA_FANFLATPROJECTIONGEOMETRY2D */ + diff --git a/include/astra/FanFlatVecProjectionGeometry2D.h b/include/astra/FanFlatVecProjectionGeometry2D.h new file mode 100644 index 0000000..d370b24 --- /dev/null +++ b/include/astra/FanFlatVecProjectionGeometry2D.h @@ -0,0 +1,155 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FANFLATVECPROJECTIONGEOMETRY2D +#define _INC_ASTRA_FANFLATVECPROJECTIONGEOMETRY2D + +#include "ProjectionGeometry2D.h" +#include "../cuda/2d/dims.h" + +#include <cmath> + +// FIXME: Avoid using +using astraCUDA::SFanProjection; + +namespace astra +{ + +/** + * This class defines a 2D fan beam geometry. + * + * \par XML Configuration + * \astra_xml_item{DetectorCount, int, Number of detectors for each projection.} + * \astra_xml_item{Vectors, matrix defining the 2D position of source and detector.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('fanflat_vec');\n + * proj_geom.DetectorCount = 512;\n + * proj_geom.Vectors = V;\n + * } + */ +class _AstraExport CFanFlatVecProjectionGeometry2D : public CProjectionGeometry2D +{ +protected: + + SFanProjection *m_pProjectionAngles; + +public: + + /** Default constructor. Sets all variables to zero. Note that this constructor leaves the object in an unusable state and must + * be followed by a call to init(). + */ + CFanFlatVecProjectionGeometry2D(); + + /** Constructor. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + CFanFlatVecProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + const SFanProjection* _pfProjectionAngles); + + /** Copy constructor. + */ + CFanFlatVecProjectionGeometry2D(const CFanFlatVecProjectionGeometry2D& _projGeom); + + /** Assignment operator. + */ + CFanFlatVecProjectionGeometry2D& operator=(const CFanFlatVecProjectionGeometry2D& _other); + + /** Destructor. + */ + virtual ~CFanFlatVecProjectionGeometry2D(); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialization. This function MUST be called after using the default constructor and MAY be called to + * reset a previously initialized object. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorCount, + const SFanProjection* _pfProjectionAngles); + + virtual bool _check(); + + /** Create a hard copy. + */ + virtual CProjectionGeometry2D* clone(); + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "fanflat_vec". + */ + virtual bool isOfType(const std::string& _sType); + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(CProjectionGeometry2D*) const; + + /** Get the value for t and theta, based upon the row and column index. + * + * @param _iRow row index + * @param _iColumn column index + * @param _fT output: value of t + * @param _fTheta output: value of theta, always lies within the [0,pi[ interval. + */ + virtual void getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const; + + /** + * Returns a vector describing the direction of a ray belonging to a certain detector + * + * @param _iProjectionIndex index of projection + * @param _iProjectionIndex index of detector + * + * @return a unit vector describing the direction + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex); + + const SFanProjection* getProjectionVectors() const { return m_pProjectionAngles; } +}; + + +} // namespace astra + +#endif /* _INC_ASTRA_FANFLATVECPROJECTIONGEOMETRY2D */ + diff --git a/include/astra/FilteredBackProjectionAlgorithm.h b/include/astra/FilteredBackProjectionAlgorithm.h new file mode 100644 index 0000000..cda7962 --- /dev/null +++ b/include/astra/FilteredBackProjectionAlgorithm.h @@ -0,0 +1,155 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FILTEREDBACKPROJECTION +#define _INC_ASTRA_FILTEREDBACKPROJECTION + +#include "ReconstructionAlgorithm2D.h" + +#include "Globals.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + + +namespace astra { + +/** + * \brief + * This class contains the implementation of the filtered back projection (FBP) + * reconstruction algorithm. + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{VolumeDataId, integer, Identifier of the volume data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of the resulting projection data object as it is stored in the DataManager.} + * \astra_xml_item_option{ProjectionIndex, integer, 0, Only reconstruct this specific projection angle. } + + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('FP');\n + * cfg.ProjectorId = proj_id;\n + * cfg.ReconstructionDataId = vol_id;\n + * cfg.ProjectionDataId = sino_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('run'\, alg_id);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ +class _AstraExport CFilteredBackProjectionAlgorithm : public CReconstructionAlgorithm2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - valid projector + * - valid data objects + * - projection order all within range + */ + virtual bool _check(); + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CFilteredBackProjectionAlgorithm(); + + /** Destructor. + */ + virtual ~CFilteredBackProjectionAlgorithm(); + + /** Initialize class. + * + * @param _pProjector Projector to use. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @return success + */ + bool initialize(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pReconstruction, + CFloat32ProjectionData2D* _pSinogram); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Clear this class. + */ + virtual void clear(); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Performs the filtering of the projection data. + * + * @param _pFilteredSinogram will contain filtered sinogram afterwards + */ + void performFiltering(CFloat32ProjectionData2D * _pFilteredSinogram); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +}; + +// inline functions +inline std::string CFilteredBackProjectionAlgorithm::description() const { return CFilteredBackProjectionAlgorithm::type; }; + +} // end namespace + +#endif diff --git a/include/astra/Float32Data.h b/include/astra/Float32Data.h new file mode 100644 index 0000000..99bbaf3 --- /dev/null +++ b/include/astra/Float32Data.h @@ -0,0 +1,88 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32DATA +#define _INC_ASTRA_FLOAT32DATA + +#include "Globals.h" + +namespace astra { + +/** + * This is a virtual base class for floating point data classes. + */ +class _AstraExport CFloat32Data { + +protected: + + // Protected Member Variables + bool m_bInitialized; ///< has the object been initialized? + int m_iDimensions; ///< the number of dimensions + +public: + + /** + * Default constructor. + */ + CFloat32Data(); + + /** + * Destructor. Free allocated memory + */ + virtual ~CFloat32Data(); + + /** + * Get the initialization state of the object. + * + * @return true iff the object has been initialized + */ + bool isInitialized() const; + + /** + * Get the number of dimensions of this object. + * + * @return number of dimensions + */ + virtual int getDimensionCount() const = 0; + +}; + +//---------------------------------------------------------------------------------------- +// Inline member functions +//---------------------------------------------------------------------------------------- + +// Get the initialization state of the object. +inline bool CFloat32Data::isInitialized() const +{ + return m_bInitialized; +} +//---------------------------------------------------------------------------------------- + +} // end namespace + +#endif diff --git a/include/astra/Float32Data2D.h b/include/astra/Float32Data2D.h new file mode 100644 index 0000000..c89e9f8 --- /dev/null +++ b/include/astra/Float32Data2D.h @@ -0,0 +1,544 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32DATA2D +#define _INC_ASTRA_FLOAT32DATA2D + +#include "Globals.h" +#include "Float32Data.h" + +#include <sstream> + +namespace astra { + +/** + * This class represents a two-dimensional block of float32ing point data. + * It contains member functions for accessing this data and for performing + * elementary computations on the data. + * The data block is "owned" by the class, meaning that the class is + * responsible for deallocation of the memory involved. + */ +class _AstraExport CFloat32Data2D : public CFloat32Data { + +protected: + + int m_iWidth; ///< width of the data (x) + int m_iHeight; ///< height of the data (y) + int m_iSize; ///< total size of the data + + /** Pointer to the data block, represented as a 1-dimensional array. + * Note that the data memory is "owned" by this class, meaning that the + * class is responsible for deallocation of the memory involved. + * To access element (ix, iy) internally, use + * m_pData[iy * m_iWidth + ix] + */ + float32* m_pfData; + + /** Array of float32 pointers, each pointing to a single horizontal + * line in the m_pfData memory block. + * To access element (ix, iy) internally, use m_ppfData2D[iy][ix] + */ + float32** m_ppfData2D; + + float32 m_fGlobalMin; ///< minimum value of the data + float32 m_fGlobalMax; ///< maximum value of the data + float32 m_fGlobalMean; ///< mean value of the data + + /** Allocate memory for m_pfData and m_ppfData2D arrays. + * + * The allocated block consists of m_iSize float32s. The block is + * not cleared after allocation and its contents is undefined. + * This function may NOT be called if memory has already been allocated. + */ + void _allocateData(); + + /** Free memory for m_pfData and m_ppfData2D arrays. + * + * This function may ONLY be called if the memory for both blocks has been + * allocated before. + */ + void _freeData(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + void _clear(); + + /** Un-initialize the object, bringing it back in the uninitialized state. + */ + void _unInit(); + + /** Find the minimum and maximum data value and store them in + * m_fGlobalMin and m_fGlobalMax + */ + void _computeGlobalMinMax(); + + /** Initialization. Initializes an instance of the CFloat32Data2D class, without filling the data block. + * Can only be called by derived classes. + * + * Initializes an instance of the CFloat32Data2D class. Memory is allocated for the + * data block. The allocated memory is not cleared and its contents after + * construction is undefined. Initialization may be followed by a call to + * copyData() to fill the memory block. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * This function does not set m_bInitialized to true if everything is ok. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @return initialization of the base class successfull + */ + bool _initialize(int _iWidth, int _iHeight); + + /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data block. + * Can only be called by derived classes. + * + * Initializes an instance of the CFloat32Data2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * This function does not set m_bInitialized to true if everything is ok. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @param _pfData pointer to a one-dimensional float32 data block + */ + bool _initialize(int _iWidth, int _iHeight, const float32* _pfData); + + /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data + * block with a scalar value. Can only be called by derived classes. + * + * Initializes an instance of the CFloat32Data2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * This function does not set m_bInitialized to true if everything is ok. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @param _fScalar scalar value to put at each index + */ + bool _initialize(int _iWidth, int _iHeight, float32 _fScalar); + + /** Constructor. Create an instance of the CFloat32Data2D class without initializing the data block. + * Can only be called by derived classes. + * + * Creates an instance of the CFloat32Data2D class. Memory is allocated for the + * data block. The allocated memory is not cleared and its contents after + * construction is undefined. Construction may be followed by a call to + * copyData() to fill the memory block. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + */ + CFloat32Data2D(int _iWidth, int _iHeight); + + /** Constructor. Create an instance of the CFloat32Data2D class with initialization of the data block. + * Can only be called by derived classes. + * + * Creates an instance of the CFloat32Data2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @param _pfData pointer to a one-dimensional float32 data block + */ + CFloat32Data2D(int _iWidth, int _iHeight, const float32* _pfData); + + /** Constructor. Create an instance of the CFloat32Data2D class with initialization of the data block + * with a scalar value. Can only be called by derived classes. + * + * Creates an instance of the CFloat32Data2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @param _fScalar scalar value to put at each index + */ + CFloat32Data2D(int _iWidth, int _iHeight, float32 _fScalar); + + /** Copy constructor. + */ + CFloat32Data2D(const CFloat32Data2D&); + +public: + + /** Typedef with available datatypes: BASE, PROJECTION, VOLUME. + */ + typedef enum {BASE, + PROJECTION, + VOLUME} EDataType; + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CFloat32Data2D(); + + /** Destructor. Free allocated memory + */ + virtual ~CFloat32Data2D(); + + /** Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. + * The pointer _pfData must point to a block of m_iSize float32s. + * + * @param _pfData source data block + */ + void copyData(const float32* _pfData); + + /** scale the grey value of the data from 0-255. + * + */ + void scale(); + + /** Set each element of the data to a specified scalar value. + * + * @param _fScalar scalar value + */ + void setData(float32 _fScalar); + + /** Set all data to zero + */ + void clearData(); + + /** Get a pointer to the data block, represented as a 1-dimensional + * array of float32 values. The data memory is still "owned" by the + * CFloat32Data2D instance; this memory may NEVER be freed by the + * caller of this function. If changes are made to this data, the + * function updateStatistics() should be called after completion of + * all changes. + * + * @return pointer to the 1-dimensional 32-bit floating point data block + */ + float32* getData(); + + /** Get a const pointer to the data block, represented as a 1-dimensional + * array of float32 values. The data memory is still "owned" by the + * CFloat32Data2D instance; this memory may NEVER be freed by the + * caller of this function. If changes are made to this data, the + * function updateStatistics() should be called after completion of + * all changes. + * + * @return pointer to the 1-dimensional 32-bit floating point data block + */ + const float32* getDataConst() const; + + /** Get a float32** to the data block, represented as a 2-dimensional array of float32 values. + * + * After the call p = getData2D(), use p[iy][ix] to access element (ix, iy). + * The data memory and pointer array are still "owned" by the CFloat32Data2D + * instance; this memory may NEVER be freed by the caller of this function. + * If changes are made to this data, the function updateStatistics() + * should be called after completion of all changes. + * + * @return pointer to the 2-dimensional 32-bit floating point data block + */ + float32** getData2D(); + + /** Get a const float32** to the data block, represented as a 2-dimensional array of float32 values. + * + * After the call p = getData2D(), use p[iy][ix] to access element (ix, iy). + * The data memory and pointer array are still "owned" by the CFloat32Data2D + * instance; this memory may NEVER be freed by the caller of this function. + * If changes are made to this data, the function updateStatistics() + * should be called after completion of all changes. + * + * @return pointer to the 2-dimensional 32-bit floating point data block + */ + const float32** getData2DConst() const; + + /** Update data statistics, such as minimum and maximum value, after the data has been modified. + */ + virtual void updateStatistics(); + + /** Get the minimum value in the data block. + * If the data has been changed after construction, the function + * updateStatistics() must be called at least once before + * a query can be made on this value. + * + * @return minimum value in the data block + */ + virtual float32 getGlobalMin() const; + + /** Get the maximum value in the data block + * If the data has been changed after construction, the function + * updateStatistics() must be called at least once before + * a query can be made on this value. + * + * @return maximum value in the data block + */ + virtual float32 getGlobalMax() const; + + /** Get the mean value in the data block + * If the data has been changed after construction, the function + * updateStatistics() must be called at least once before + * a query can be made on this value. + * + * @return maximum value in the data block + */ + virtual float32 getGlobalMean() const; + + + /** Get the width of the data block. + * + * @return width of the data block + */ + int getWidth() const; + + /** Get the height of the data block. + * + * @return height of the data block + */ + int getHeight() const; + + /** Get the total size (width*height) of the data block. + * + * @return size of the data block + */ + int getSize() const; + + /** which type is this class? + * + * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION or + * ASTRA_DATATYPE_FLOAT32_VOLUME + */ + virtual EDataType getType() const; + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const; + + /** Get the number of dimensions of this object. + * + * @return number of dimensions + */ + int getDimensionCount() const; + + /** + * Clamp data to minimum value + * + * @param _fMin minimum value + * @return l-value + */ + CFloat32Data2D& clampMin(float32& _fMin); + + /** + * Clamp data to maximum value + * + * @param _fMax maximum value + * @return l-value + */ + CFloat32Data2D& clampMax(float32& _fMax); + + /** + * Overloaded Operator: data += data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32Data2D& operator+=(const CFloat32Data2D& _data); + + /** + * Overloaded Operator: data -= data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32Data2D& operator-=(const CFloat32Data2D& _data); + + /** + * Overloaded Operator: data *= data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32Data2D& operator*=(const CFloat32Data2D& _data); + + /** + * Overloaded Operator: data *= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32Data2D& operator*=(const float32& _fScalar); + + /** + * Overloaded Operator: data /= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32Data2D& operator/=(const float32& _fScalar); + + /** + * Overloaded Operator: data += scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32Data2D& operator+=(const float32& _fScalar); + + /** + * Overloaded Operator: data -= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32Data2D& operator-=(const float32& _fScalar); + + CFloat32Data2D& operator=(const CFloat32Data2D& _dataIn); + + float32& getData(int _index); + +}; + + +//---------------------------------------------------------------------------------------- +// Inline member functions +//---------------------------------------------------------------------------------------- + +// Get the number of dimensions of this object. +inline int CFloat32Data2D::getDimensionCount() const +{ + return 2; +} + +//---------------------------------------------------------------------------------------- +inline std::string CFloat32Data2D::description() const +{ + std::stringstream res; + res << m_iWidth << "x" << m_iHeight; + if (getType() == CFloat32Data2D::PROJECTION) res << " sinogram data \t"; + if (getType() == CFloat32Data2D::VOLUME) res << " volume data \t"; + return res.str(); +} + +//---------------------------------------------------------------------------------------- +// Get the type of this object. +inline CFloat32Data2D::EDataType CFloat32Data2D::getType() const +{ + return BASE; +} + +//---------------------------------------------------------------------------------------- +// Get the width of the data block. +inline int CFloat32Data2D::getWidth() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iWidth; +} + +//---------------------------------------------------------------------------------------- +// Get the height of the data block. +inline int CFloat32Data2D::getHeight() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iHeight; +} + +//---------------------------------------------------------------------------------------- +// Get the total size (width*height*depth) of the data block. +inline int CFloat32Data2D::getSize() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iSize; +} + +//---------------------------------------------------------------------------------------- +// Get a pointer to the data block, represented as a 1-dimensional array of float32 values. +inline float32* CFloat32Data2D::getData() +{ + //ASTRA_ASSERT(m_bInitialized); + return m_pfData; +} + +//---------------------------------------------------------------------------------------- +// Get a pointer to the data block, represented as a 1-dimensional array of float32 values. +inline float32& CFloat32Data2D::getData(int _index) +{ + //ASTRA_ASSERT(m_bInitialized); + return m_pfData[_index]; +} + +//---------------------------------------------------------------------------------------- +// Get a const pointer to the data block, represented as a 1-dimensional array of float32 values. +inline const float32* CFloat32Data2D::getDataConst() const +{ + ASTRA_ASSERT(m_bInitialized); + return (const float32*)m_pfData; +} + +//---------------------------------------------------------------------------------------- +// Get a float32** to the data block, represented as a 2-dimensional array of float32 values. +inline float32** CFloat32Data2D::getData2D() +{ + ASTRA_ASSERT(m_bInitialized); + return m_ppfData2D; +} + +//---------------------------------------------------------------------------------------- +// Get a const float32** to the data block, represented as a 2-dimensional array of float32 values. +inline const float32** CFloat32Data2D::getData2DConst() const +{ + ASTRA_ASSERT(m_bInitialized); + return (const float32**)m_ppfData2D; +} + +//---------------------------------------------------------------------------------------- +// Get the minimum value in the data block. +inline float32 CFloat32Data2D::getGlobalMin() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fGlobalMin; +} + +//---------------------------------------------------------------------------------------- +// Get the maximum value in the data block +inline float32 CFloat32Data2D::getGlobalMax() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fGlobalMax; +} + +//---------------------------------------------------------------------------------------- +// Get the mean value in the data block +inline float32 CFloat32Data2D::getGlobalMean() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fGlobalMean; +} + + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32DATA2D diff --git a/include/astra/Float32Data3D.h b/include/astra/Float32Data3D.h new file mode 100644 index 0000000..8666890 --- /dev/null +++ b/include/astra/Float32Data3D.h @@ -0,0 +1,199 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32DATA3D +#define _INC_ASTRA_FLOAT32DATA3D + +#include "Globals.h" +#include "Float32Data.h" +#include "Float32Data2D.h" + +namespace astra { + +/** + * This class represents a three-dimensional block of float32ing point data. + */ +class _AstraExport CFloat32Data3D : public CFloat32Data { + +protected: + + int m_iWidth; ///< width of the data (x) + int m_iHeight; ///< height of the data (y) + int m_iDepth; ///< depth of the data (z) + size_t m_iSize; ///< size of the data (width*height*depth) + + /** + * Compares the size of two CFloat32Data instances. + * + * @param _pA CFloat32Data3D instance A + * @param _pB CFloat32Data3D instance B + * @return True if they have the same size + */ + static bool _data3DSizesEqual(const CFloat32Data3D * _pA, const CFloat32Data3D * _pB); + +public: + + typedef enum {BASE, PROJECTION, VOLUME} EDataType; + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + */ + CFloat32Data3D(); + + /** Destructor. + */ + virtual ~CFloat32Data3D(); + + /** Get the width of the data block. + * + * @return width of the data block + */ + int getWidth() const; + + /** Get the height of the data block. + * + * @return height of the data block + */ + int getHeight() const; + + /** Get the depth of the data block. + * + * @return depth of the data block + */ + int getDepth() const; + + /** Get the size of the data block. + * + * @return size of the data block + */ + int getSize() const; + + /** Which type is this class? + * + * @return DataType: PROJECTION or VOLUME + */ + virtual EDataType getType() const; + + /** Get the number of dimensions of this object. + * + * @return number of dimensions + */ + int getDimensionCount() const; + + /** + * Clamp data to minimum value + * + * @param _fMin minimum value + * @return l-value + */ + virtual CFloat32Data3D& clampMin(float32& _fMin) = 0; + + /** + * Clamp data to maximum value + * + * @param _fMax maximum value + * @return l-value + */ + virtual CFloat32Data3D& clampMax(float32& _fMax) = 0; + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const; + +}; +//---------------------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------------------- +// Get dimension count. +inline int CFloat32Data3D::getDimensionCount() const +{ + return 3; +} + +//---------------------------------------------------------------------------------------- +// Get the width of the data block. +inline int CFloat32Data3D::getWidth() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iWidth; +} + +//---------------------------------------------------------------------------------------- +// Get the height of the data block. +inline int CFloat32Data3D::getHeight() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iHeight; +} + +//---------------------------------------------------------------------------------------- +// Get the height of the data block. +inline int CFloat32Data3D::getDepth() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iDepth; +} + +//---------------------------------------------------------------------------------------- +// Get the size of the data block. +inline int CFloat32Data3D::getSize() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iSize; +} + + +//---------------------------------------------------------------------------------------- +// get type +inline CFloat32Data3D::EDataType CFloat32Data3D::getType() const +{ + return BASE; +} + +//---------------------------------------------------------------------------------------- +// To String +inline std::string CFloat32Data3D::description() const +{ + std::stringstream res; + res << m_iWidth << "x" << m_iHeight << "x" << m_iDepth; + if (getType() == CFloat32Data3D::PROJECTION) res << " sinogram data \t"; + if (getType() == CFloat32Data3D::VOLUME) res << " volume data \t"; + return res.str(); +} +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32DATA2D diff --git a/include/astra/Float32Data3DMemory.h b/include/astra/Float32Data3DMemory.h new file mode 100644 index 0000000..3a445b6 --- /dev/null +++ b/include/astra/Float32Data3DMemory.h @@ -0,0 +1,338 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32DATA3DMEMORY +#define _INC_ASTRA_FLOAT32DATA3DMEMORY + +#include "Globals.h" +#include "Float32Data3D.h" + +namespace astra { + +/** + * This class represents a three-dimensional block of float32ing point data. + * It contains member functions for accessing this data and for performing + * elementary computations on the data. + * The data block is "owned" by the class, meaning that the class is + * responsible for deallocation of the memory involved. + */ +class _AstraExport CFloat32Data3DMemory : public virtual CFloat32Data3D { + +protected: + + /** Pointer to the data block, represented as a 1-dimensional array. + * Note that the data memory is "owned" by this class, meaning that the + * class is responsible for deallocation of the memory involved. + * To access element (ix, iy, iz) internally, use + * m_pData[iz * m_iWidth * m_iHeight + iy * m_iWidth + ix] + */ + float32* m_pfData; + + /** Array of float32 pointers, each pointing to a single row + * in the m_pfData memory block. + * To access element (ix, iy, iz) internally, use m_ppfDataRowInd[iz * m_iHeight + iy][ix] + */ + float32** m_ppfDataRowInd; + + /** Array of float32 pointers, each pointing to a single slice + * in the m_pfData memory block. + * To access element (ix, iy, iz) internally, use m_pppfDataSliceInd[iz][iy][ix] + */ + float32*** m_pppfDataSliceInd; + + float32 m_fGlobalMin; ///< minimum value of the data + float32 m_fGlobalMax; ///< maximum value of the data + + /** Allocate memory for m_pfData, m_ppfDataRowInd and m_pppfDataSliceInd arrays. + * + * The allocated block consists of m_iSize float32s. The block is + * not cleared after allocation and its contents is undefined. + * This function may NOT be called if memory has already been allocated. + */ + void _allocateData(); + + /** Free memory for m_pfData, m_ppfDataRowInd and m_pppfDataSliceInd arrays. + * + * This function may ONLY be called if the memory for both blocks has been + * allocated before. + */ + void _freeData(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + void _clear(); + + /** Un-initialize the object, bringing it back in the unitialized state. + */ + void _unInit(); + + /** Find the minimum and maximum data value and store them in + * m_fGlobalMin and m_fGlobalMax + */ + void _computeGlobalMinMax(); + + /** Initialization. Initializes an instance of the CFloat32Data3DMemory class, without filling the data block. + * Can only be called by derived classes. + * + * Initializes an instance of the CFloat32Data3DMemory class. Memory is allocated for the + * data block. The allocated memory is not cleared and its contents after + * construction is undefined. Initialization may be followed by a call to + * copyData() to fill the memory block. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * This function does not set m_bInitialized to true if everything is ok. + * + * @param _iWidth width of the 3D data (x-axis), must be > 0 + * @param _iHeight height of the 3D data (y-axis), must be > 0 + * @param _iDepth depth of the 3D data (z-axis), must be > 0 + * @return initialization of the base class successfull + */ + bool _initialize(int _iWidth, int _iHeight, int _iDepth); + + /** Initialization. Initializes an instance of the CFloat32Data3DMemory class with initialization of the data block. + * Can only be called by derived classes. + * + * Initializes an instance of the CFloat32Data3DMemory class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * This function does not set m_bInitialized to true if everything is ok. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @param _iDepth depth of the 2D data (z-axis), must be > 0 + * @param _pfData pointer to a one-dimensional float32 data block + * @return initialization of the base class successfull + */ + bool _initialize(int _iWidth, int _iHeight, int _iDepth, const float32* _pfData); + + /** Initialization. Initializes an instance of the CFloat32Data3DMemory class with initialization of the data block. + * Can only be called by derived classes. + * + * Initializes an instance of the CFloat32Data3DMemory class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * This function does not set m_bInitialized to true if everything is ok. + * + * @param _iWidth width of the 2D data (x-axis), must be > 0 + * @param _iHeight height of the 2D data (y-axis), must be > 0 + * @param _iDepth depth of the 2D data (z-axis), must be > 0 + * @param _fScalar scalar value to fill the data + * @return initialization of the base class successfull + */ + bool _initialize(int _iWidth, int _iHeight, int _iDepth, float32 _fScalar); + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CFloat32Data3DMemory(); + + /** Destructor. Free allocated memory + */ + virtual ~CFloat32Data3DMemory(); + + /** Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. + * The pointer _pfData must point to a block of m_iSize float32s. + * + * @param _pfData source data block + * @param _iSize total number of data elements, must be equal to the allocated size of the object. + */ + void copyData(const float32* _pfData, size_t _iSize); + + /** Set each element of the data to a specified scalar value. + * + * @param _fScalar scalar value + */ + void setData(float32 _fScalar); + + /** Set all data to zero + */ + void clearData(); + + /** Get a pointer to the data block, represented as a 1-dimensional + * array of float32 values. The data memory is still "owned" by the + * CFloat32Data3DMemory instance; this memory may NEVER be freed by the + * caller of this function. If changes are made to this data, the + * function updateStatistics() should be called after completion of + * all changes. + * + * @return pointer to the 1-dimensional 32-bit floating point data block + */ + float32* getData(); + + /** Get a const pointer to the data block, represented as a 1-dimensional + * array of float32 values. The data memory is still "owned" by the + * CFloat32Data3DMemory instance; this memory may NEVER be freed by the + * caller of this function. If changes are made to this data, the + * function updateStatistics() should be called after completion of + * all changes. + * + * @return pointer to the 1-dimensional 32-bit floating point data block + */ + const float32* getDataConst() const; + + /** Get a float32*** to the data block, represented as a 3-dimensional array of float32 values. + * + * After the call p = getData3D(), use p[iz][iy][ix] to access element (ix, iy, iz). + * The data memory and pointer array are still "owned" by the CFloat32Data3DMemory + * instance; this memory may NEVER be freed by the caller of this function. + * If changes are made to this data, the function updateStatistics() + * should be called after completion of all changes. + * + * @return pointer to the 3-dimensional 32-bit floating point data block + */ + float32*** getData3D(); + + /** Get a const float32*** to the data block, represented as a 3-dimensional array of float32 values. + * + * After the call p = getData3D(), use p[iy][ix] to access element (ix, iy, iz). + * The data memory and pointer array are still "owned" by the CFloat32Data3DMemory + * instance; this memory may NEVER be freed by the caller of this function. + * If changes are made to this data, the function updateStatistics() + * should be called after completion of all changes. + * + * @return pointer to the 3-dimensional 32-bit floating point data block + */ + const float32*** getData3DConst() const; + + /** Update data statistics, such as minimum and maximum value, after the data has been modified. + */ + virtual void updateStatistics(); + + /** Get the minimum value in the data block. + * If the data has been changed after construction, the function + * updateStatistics() must be called at least once before + * a query can be made on this value. + * + * @return minimum value in the data block + */ + virtual float32 getGlobalMin() const; + + /** Get the maximum value in the data block + * If the data has been changed after construction, the function + * updateStatistics() must be called at least once before + * a query can be made on this value. + * + * @return maximum value in the data block + */ + virtual float32 getGlobalMax() const; + + /** which type is this class? + * + * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION or + * ASTRA_DATATYPE_FLOAT32_VOLUME + */ + virtual EDataType getType() const; + + /** + * Clamp data to minimum value + * + * @param _fMin minimum value + * @return l-value + */ + virtual CFloat32Data3D& clampMin(float32& _fMin); + + /** + * Clamp data to maximum value + * + * @param _fMax maximum value + * @return l-value + */ + virtual CFloat32Data3D& clampMax(float32& _fMax); +}; + + +//---------------------------------------------------------------------------------------- +// Inline member functions +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Get the type of this object. +inline CFloat32Data3DMemory::EDataType CFloat32Data3DMemory::getType() const +{ + return BASE; +} + +//---------------------------------------------------------------------------------------- +// Get the minimum value in the data block. +inline float32 CFloat32Data3DMemory::getGlobalMin() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fGlobalMin; +} + +//---------------------------------------------------------------------------------------- +// Get the maximum value in the data block +inline float32 CFloat32Data3DMemory::getGlobalMax() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fGlobalMax; +} + +//---------------------------------------------------------------------------------------- +// Get a pointer to the data block, represented as a 1-dimensional array of float32 values. +inline float32* CFloat32Data3DMemory::getData() +{ + ASTRA_ASSERT(m_bInitialized); + return m_pfData; +} + +//---------------------------------------------------------------------------------------- +// Get a const pointer to the data block, represented as a 1-dimensional array of float32 values. +inline const float32* CFloat32Data3DMemory::getDataConst() const +{ + ASTRA_ASSERT(m_bInitialized); + return (const float32*)m_pfData; +} + +//---------------------------------------------------------------------------------------- +// Get a float32** to the data block, represented as a 3-dimensional array of float32 values. +inline float32*** CFloat32Data3DMemory::getData3D() +{ + ASTRA_ASSERT(m_bInitialized); + return m_pppfDataSliceInd; +} + +//---------------------------------------------------------------------------------------- +// Get a const float32** to the data block, represented as a 3-dimensional array of float32 values. +inline const float32*** CFloat32Data3DMemory::getData3DConst() const +{ + ASTRA_ASSERT(m_bInitialized); + return (const float32***)m_pppfDataSliceInd; +} +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32DATA2D diff --git a/include/astra/Float32ProjectionData2D.h b/include/astra/Float32ProjectionData2D.h new file mode 100644 index 0000000..d9fe51a --- /dev/null +++ b/include/astra/Float32ProjectionData2D.h @@ -0,0 +1,247 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA2D +#define _INC_ASTRA_FLOAT32PROJECTIONDATA2D + +#include "Float32Data2D.h" +#include "ProjectionGeometry2D.h" + +namespace astra { + +/** + * This class represents two-dimensional Projection Data. + * + * It contains member functions for accessing this data and for performing + * elementary computations on the data. + * The data block is "owned" by the class, meaning that the class is + * responsible for deallocation of the memory involved. + * + * The projection data is stored as a series of consecutive rows, where + * each row contains the data for a single projection. + */ +class _AstraExport CFloat32ProjectionData2D : public CFloat32Data2D { + +public: + + /** + * Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CFloat32ProjectionData2D(); + + /** + * Constructor. Create an instance of the CFloat32ProjectionData2D class without initializing the data. + * + * Memory is allocated for the data block. The allocated memory is not cleared and + * its contents after construction is undefined. Construction may be followed by a + * call to copyData() to fill the memory block. + * The size of the data is determined by the specified projection geometry object. + * + * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class. + */ + CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry); + + /** + * Constructor. Create an instance of the CFloat32ProjectionData2D class with initialization of the data. + * + * Creates an instance of the CFloat32ProjectionData2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified projection geometry object. + * + * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32* _pfData); + + /** + * Constructor. Create an instance of the CFloat32ProjectionData2D class with initialization of the data. + * + * Creates an instance of the CFloat32ProjectionData2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified projection geometry object. + * + * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value to be put at each index. + */ + CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32 _fScalar); + + /** + * Copy constructor + */ + CFloat32ProjectionData2D(const CFloat32ProjectionData2D& _other); + + /** + * Assignment operator + */ + CFloat32ProjectionData2D& operator=(const CFloat32ProjectionData2D& _other); + + /** + * Destructor. + */ + virtual ~CFloat32ProjectionData2D(); + + /** Initialization. Initializes an instance of the CFloat32ProjectionData2D class, without filling the data block. + * + * Initializes an instance of the CFloat32Data2D class. Memory is allocated for the + * data block. The allocated memory is not cleared and its contents after + * construction is undefined. Initialization may be followed by a call to + * copyData() to fill the memory block. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class. + * @return Initialization of the base class successfull. + */ + bool initialize(CProjectionGeometry2D* _pGeometry); + + /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data block. + * + * Initializes an instance of the CFloat32Data2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + bool initialize(CProjectionGeometry2D* _pGeometry, const float32* _pfData); + + /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data block. + * + * Initializes an instance of the CFloat32Data2D class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value to be put at each index. + */ + bool initialize(CProjectionGeometry2D* _pGeometry, float32 _fScalar); + + /** Get the number of detectors. + * + * @return number of detectors + */ + int getDetectorCount() const; + + /** Get the number of projection angles. + * + * @return number of projection angles + */ + int getAngleCount() const; + + /** Get a pointer to the data of a single projection angle. + * + * The data memory is still "owned" by the + * CFloat32ProjectionData2D instance; this memory may NEVER be freed by the + * caller of this function. If changes are made to this data, the + * function updateStatistics() should be called after completion of + * all changes. + * + * @return pointer to the data + */ + float32* getSingleProjectionData(int _iAngleIndex); + + /** Get a const pointer to the data of a single projection angle. + * + * The data memory is still "owned" by the + * CFloat32ProjectionData2D instance; this memory may NEVER be freed by the + * caller of this function. + * + * @return pointer to the data + */ + const float32* getSingleProjectionDataConst(int _iAngleIndex) const; + + /** Which type is this class? + * + * @return DataType: PROJECTION + */ + virtual EDataType getType() const; + + /** Get the projection geometry. + * + * @return pointer to projection geometry. + */ + virtual CProjectionGeometry2D* getGeometry() const; + + /** Change the projection geometry. + * Note that this can't change the dimensions of the data. + */ + virtual void changeGeometry(CProjectionGeometry2D* pGeometry); + +protected: + + /** The projection geometry for this data. + */ + CProjectionGeometry2D* m_pGeometry; + +}; +//---------------------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CFloat32ProjectionData2D::getDetectorCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iWidth; +} + +//---------------------------------------------------------------------------------------- +// Get the number of projection angles. +inline int CFloat32ProjectionData2D::getAngleCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iHeight; +} + +//---------------------------------------------------------------------------------------- +// Get the projection geometry. +inline CProjectionGeometry2D* CFloat32ProjectionData2D::getGeometry() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_pGeometry; +} + +//---------------------------------------------------------------------------------------- +// Get type. +inline CFloat32Data2D::EDataType CFloat32ProjectionData2D::getType() const +{ + return PROJECTION; +} +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA2D diff --git a/include/astra/Float32ProjectionData3D.h b/include/astra/Float32ProjectionData3D.h new file mode 100644 index 0000000..92122a7 --- /dev/null +++ b/include/astra/Float32ProjectionData3D.h @@ -0,0 +1,257 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA3D +#define _INC_ASTRA_FLOAT32PROJECTIONDATA3D + +#include "Float32Data3D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" +#include "ProjectionGeometry3D.h" + +namespace astra { + +/** + * This asbtract class represents three-dimensional Projection Data. + */ +class _AstraExport CFloat32ProjectionData3D : public virtual CFloat32Data3D +{ +protected: + /** The projection geometry for this data. + */ + CProjectionGeometry3D* m_pGeometry; + +public: + + /** Default constructor. + */ + CFloat32ProjectionData3D(); + + /** Destructor. + */ + virtual ~CFloat32ProjectionData3D(); + + /** Get the number of detectors in one detector column. + * + * @return number of detectors + */ + int getDetectorRowCount() const; + + /** Get the number of detectors in one detector row. + * + * @return number of detectors + */ + int getDetectorColCount() const; + + /** Get the total number of detectors. + * + * @return number of detectors + */ + int getDetectorTotCount() const; + + /** Get the number of projection angles. + * + * @return number of projection angles + */ + int getAngleCount() const; + + /** Which type is this class? + * + * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION + */ + virtual CFloat32Data3D::EDataType getType() const; + + /** Fetch a COPY of a projection of the data. Note that if you update the 2D data slice, the data in the + * 3d data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnProjection'. + * + * @param _iProjectionNr projection number + * @return Volume data object + */ + virtual CFloat32VolumeData2D* fetchProjection(int _iProjectionNr) const = 0; + + /** Return a projection slice to the 3d data. The data will be deleted. If the slice was fetched with + * 'fetchProjection', the data will be stored first. + * + * @param _iProjectionNr projection number + * @param _pProjection 2D Projection Data + */ + virtual void returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection) = 0; + + /** Fetch a COPY of a sinogram slice of the data. Note that if you update the 2D data slice, the data in the + * 3d data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnSlice'. + * + * @param _iSliceNr slice number + * @return Sinogram data object + */ + virtual CFloat32ProjectionData2D* fetchSinogram(int _iSliceNr) const = 0; + + /** Return a sinogram slice to the 3d data. The data will be stored in the 3D Data object. + * + * @param _iSliceNr slice number + * @param _pSinogram2D 2D Sinogram Object. + */ + virtual void returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D) = 0; + + /** This SLOW function returns a detector value stored a specific index in the array. + * Reading values in this way might cause a lot of unnecessar__y memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @return The value the location specified by _iIndex + */ + virtual float32 getDetectorValue(int _iIndex) = 0; + + /** This SLOW function stores a detector value at a specific index in the array. + * Writing values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @param _fValue The value to be stored at the location specified by _iIndex + */ + virtual void setDetectorValue(int _iIndex, float32 _fValue) = 0; + + /** + * Overloaded Operator: data += data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator+=(const CFloat32ProjectionData3D& _data); + + /** + * Overloaded Operator: data -= data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator-=(const CFloat32ProjectionData3D& _data); + + /** + * Overloaded Operator: data *= data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator*=(const CFloat32ProjectionData3D& _data); + + /** + * Overloaded Operator: data *= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator*=(const float32& _fScalar); + + /** + * Overloaded Operator: data /= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator/=(const float32& _fScalar); + + /** + * Overloaded Operator: data += scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator+=(const float32& _fScalar); + + /** + * Overloaded Operator: data -= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32ProjectionData3D& operator-=(const float32& _fScalar); + + /** Get the projection geometry. + * + * @return pointer to projection geometry. + */ + virtual CProjectionGeometry3D* getGeometry() const; +}; + + +//---------------------------------------------------------------------------------------- +// Inline member functions +//---------------------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CFloat32ProjectionData3D::getDetectorColCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iWidth; +} + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CFloat32ProjectionData3D::getDetectorRowCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iDepth; +} + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CFloat32ProjectionData3D::getDetectorTotCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iWidth * m_iDepth; +} + +//---------------------------------------------------------------------------------------- +// Get the number of projection angles. +inline int CFloat32ProjectionData3D::getAngleCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iHeight; +} + +//---------------------------------------------------------------------------------------- +// Get type +inline CFloat32Data3D::EDataType CFloat32ProjectionData3D::getType() const +{ + return PROJECTION; +} +//---------------------------------------------------------------------------------------- +// Get the projection geometry. +inline CProjectionGeometry3D* CFloat32ProjectionData3D::getGeometry() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_pGeometry; +} +//---------------------------------------------------------------------------------------- + + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA3D diff --git a/include/astra/Float32ProjectionData3DMemory.h b/include/astra/Float32ProjectionData3DMemory.h new file mode 100644 index 0000000..8b61d45 --- /dev/null +++ b/include/astra/Float32ProjectionData3DMemory.h @@ -0,0 +1,218 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA3DMEMORY +#define _INC_ASTRA_FLOAT32PROJECTIONDATA3DMEMORY + +#include "Float32Data3DMemory.h" +#include "Float32ProjectionData3D.h" +#include "ParallelProjectionGeometry2D.h" // TEMP + +namespace astra { + +/** + * This class represents three-dimensional Projection Data. + * + * It contains member functions for accessing this data and for performing + * elementary computations on the data. + * The data block is "owned" by the class, meaning that the class is + * responsible for deallocation of the memory involved. + * + * The projection data is stored as a series of consecutive rows, where + * each row contains the data for a single projection. + */ +class _AstraExport CFloat32ProjectionData3DMemory : public CFloat32Data3DMemory, public CFloat32ProjectionData3D { + +public: + + /** + * Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CFloat32ProjectionData3DMemory(); + + /** + * Constructor. Create an instance of the CFloat32ProjectionData3DMemory class without initializing the data. + * + * Memory is allocated for the data block. The allocated memory is not cleared and + * its contents after construction is undefined. Construction may be followed by a + * call to copyData() to fill the memory block. + * The size of the data is determined by the specified projection geometry object. + * + * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class. + */ + CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry); + + /** + * Constructor. Create an instance of the CFloat32ProjectionData3DMemory class with initialization of the data. + * + * Creates an instance of the CFloat32ProjectionData3DMemory class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified projection geometry object. + * + * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32* _pfData); + + /** + * Constructor. Create an instance of the CFloat32ProjectionData3DMemory class filled with scalar data. + * + * Creates an instance of the CFloat32ProjectionData3DMemory class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified projection geometry object. + * + * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class. + * @param _fScalar scalar data + */ + CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32 _fScalar); + + /** + * Destructor. + */ + virtual ~CFloat32ProjectionData3DMemory(); + + /** Initialization. Initializes an instance of the CFloat32ProjectionData3DMemory class, without filling the data block. + * + * Initializes an instance of the CFloat32ProjectionData3DMemory class. Memory is allocated for the + * data block. The allocated memory is not cleared and its contents after + * construction is undefined. Initialization may be followed by a call to + * copyData() to fill the memory block. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class. + * @return Initialization of the base class successfull. + */ + bool initialize(CProjectionGeometry3D* _pGeometry); + + /** Initialization. Initializes an instance of the CFloat32ProjectionData3DMemory class with scalar initialization. + * + * Initializes an instance of the CFloat32ProjectionData3DMemory class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value + */ + bool initialize(CProjectionGeometry3D* _pGeometry, float32 _fScalar); + + /** Initialization. Initializes an instance of the CFloat32ProjectionData3DMemory class with initialization of the data block. + * + * Initializes an instance of the CFloat32ProjectionData3DMemory class. Memory + * is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. If the object has been initialized before, the + * object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + bool initialize(CProjectionGeometry3D* _pGeometry, const float32* _pfData); + + /** Fetch a COPY of a projection of the data. Note that if you update the 2D data slice, the data in the + * 3D data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnProjection'. + * + * @param _iProjectionNr projection number + * @return Volume data object + */ + virtual CFloat32VolumeData2D* fetchProjection(int _iProjectionNr) const; + + /** Return a projection slice to the 3D data. The data will be deleted. If the slice was fetched with + * 'fetchProjection', the data will be stored first. + * + * @param _iProjectionNr projection number + * @param _pProjection 2D Projection image + */ + virtual void returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection); + + /** Fetch a COPY of a sinogram slice of the data. Note that if you update the 2D data slice, the data in the + * 3D data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnSlice'. + * + * @param _iSliceNr slice number + * @return Sinogram data object + */ + virtual CFloat32ProjectionData2D* fetchSinogram(int _iSliceNr) const; + + /** This SLOW function returns a detector value stored a specific index in the array. + * Reading values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @return The value the location specified by _iIndex + */ + virtual float32 getDetectorValue(int _iIndex); + + /** This SLOW function stores a detector value at a specific index in the array. + * Writing values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @param _fValue The value to be stored at the location specified by _iIndex + */ + virtual void setDetectorValue(int _iIndex, float32 _fValue); + + /** Return a sinogram slice to the 3d data. The data will be stored in the 3D Data object. + * + * @param _iSliceNr slice number + * @param _pSinogram2D 2D Sinogram Object. + */ + virtual void returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D); + + /** Which type is this class? + * + * @return DataType: PROJECTION + */ + virtual EDataType getType() const; + + /** + * Overloaded Operator: data = data (pointwise) + * + * @param _dataIn r-value + * @return l-value + */ + CFloat32ProjectionData3DMemory& operator=(const CFloat32ProjectionData3DMemory& _dataIn); +}; +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Get type. +inline CFloat32Data3D::EDataType CFloat32ProjectionData3DMemory::getType() const +{ + return PROJECTION; +} +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA3DMEMORY diff --git a/include/astra/Float32VolumeData2D.h b/include/astra/Float32VolumeData2D.h new file mode 100644 index 0000000..d7bf2f6 --- /dev/null +++ b/include/astra/Float32VolumeData2D.h @@ -0,0 +1,183 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA2D +#define _INC_ASTRA_FLOAT32VOLUMEDATA2D + +#include "Float32Data2D.h" +#include "VolumeGeometry2D.h" + +namespace astra { + +/** + * This class represents two-dimensional Volume Data. + * + * It contains member functions for accessing this data and for performing + * elementary computations on the data. + * The data block is "owned" by the class, meaning that the class is + * responsible for deallocation of the memory involved. + */ +class _AstraExport CFloat32VolumeData2D : public CFloat32Data2D { + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CFloat32VolumeData2D(); + + /** Constructor. Create an instance of the CFloat32VolumeData2D class without initializing the data. + * + * Memory is allocated for the data block. The allocated memory is not cleared and + * its contents after construction is undefined. Construction may be followed by a + * call to copyData() to fill the memory block. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class. + */ + CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry); + + /** Constructor. Create an instance of the CFloat32VolumeData2D class with initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32* _pfData); + + /** Constructor. Create an instance of the CFloat32VolumeData2D class with a scalar initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value to be put at each index. + */ + CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32 _fScalar); + + /** + * Copy constructor + */ + CFloat32VolumeData2D(const CFloat32VolumeData2D& _other); + + /** + * Assignment operator + */ + CFloat32VolumeData2D& operator=(const CFloat32VolumeData2D& _other); + + /** Initialization. Initializes of the CFloat32VolumeData2D class without initializing the data. + * + * Memory is allocated for the data block. The allocated memory is not cleared and + * its contents after construction is undefined. Construction may be followed by a + * call to copyData() to fill the memory block. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class. + * @return Initialization of the base class successfull. + */ + bool initialize(CVolumeGeometry2D* _pGeometry); + + /** Initialization. Initializes an instance of the CFloat32VolumeData2D class with initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + bool initialize(CVolumeGeometry2D* _pGeometry, const float32* _pfData); + + + /** Initialization. Initializes an instance of the CFloat32VolumeData2D class with scalar initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value to be put at each index. + */ + bool initialize(CVolumeGeometry2D* _pGeometry, float32 _fScalar); + + /** Destructor. + */ + virtual ~CFloat32VolumeData2D(); + + /** Which type is this class? + * + * @return DataType: VOLUME + */ + virtual EDataType getType() const; + + /** Get the volume geometry. + * + * @return pointer to volume geometry. + */ + virtual CVolumeGeometry2D* getGeometry() const; + + /** Change the projection geometry. + * Note that this can't change the dimensions of the data. + */ + virtual void changeGeometry(CVolumeGeometry2D* pGeometry); + +protected: + + /** The projection geometry for this data. + */ + CVolumeGeometry2D* m_pGeometry; + +}; + +//---------------------------------------------------------------------------------------- +// Get the projection geometry. +inline CVolumeGeometry2D* CFloat32VolumeData2D::getGeometry() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_pGeometry; +} + +//---------------------------------------------------------------------------------------- +// Get type +inline CFloat32Data2D::EDataType CFloat32VolumeData2D::getType() const +{ + return VOLUME; +} + + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32VOLUMEDATA2D diff --git a/include/astra/Float32VolumeData3D.h b/include/astra/Float32VolumeData3D.h new file mode 100644 index 0000000..0b1bd96 --- /dev/null +++ b/include/astra/Float32VolumeData3D.h @@ -0,0 +1,265 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA3D +#define _INC_ASTRA_FLOAT32VOLUMEDATA3D + +#include "Float32Data3D.h" +#include "Float32VolumeData2D.h" +#include "VolumeGeometry3D.h" + +namespace astra { + +/** + * This asbtract class represents three-dimensional Volume Data. + */ +class _AstraExport CFloat32VolumeData3D : public virtual CFloat32Data3D +{ +protected: + CVolumeGeometry3D * m_pGeometry; + +public: + /** Default constructor. + */ + CFloat32VolumeData3D(); + + /** Destructor. + */ + virtual ~CFloat32VolumeData3D(); + + /** + * Returns number of rows + * + * @return number of rows + */ + int getRowCount() const; + + /** + * Returns number of columns + * + * @return number of columns + */ + int getColCount() const; + + /** + * Returns number of slices + * + * @return number of slices + */ + int getSliceCount() const; + + /** + * Returns total number of volumes + * + * @return total number of volumes + */ + int getVoxelTotCount() const; + + /** Which type is this class? + * + * @return DataType: VOLUME + */ + virtual CFloat32Data3D::EDataType getType() const; + + /** Fetch a slice from the data in the x direction. Note that if you update the 2D data slice, the data in the + * 3d data object will remain unaltered. To copy the data you must return the data by calling 'returnSliceX'. + * You should not delete data fetched with this function yourself, instead call the 'returnSliceX' function. + * + * @param _iColumnIndex slice number + * @return Volume data object + */ + virtual CFloat32VolumeData2D* fetchSliceX(int _iColumnIndex) const = 0; + + /** Fetch a slice from the data in the y direction. Note that if you update the 2D data slice, the data in the + * 3d data object will remain unaltered. To copy the data you must return the data by calling 'returnSliceY'. + * You should not delete data fetched with this function yourself, instead call the 'returnSliceY' function. + * + * @param _iRowIndex slice number + * @return Volume data object + */ + virtual CFloat32VolumeData2D* fetchSliceY(int _iRowIndex) const = 0; + + /** Fetch a slice from the data in the z direction. Note that if you update the 2D data slice, the data in the + * 3d data object will remain unaltered. To copy the data you must return the data by calling 'returnSliceZ'. + * You should not delete data fetched with this function yourself, instead call the 'returnSliceZ' function. + * + * @param _iSliceIndex slice number + * @return Volume data object + */ + virtual CFloat32VolumeData2D* fetchSliceZ(int _iSliceIndex) const = 0; + + /** Return a slice from the data in the x direction to the 3d data. The data will be deleted. If the slice was + * fetched with 'fetchSliceX', the data will be stored first. + * + * @param _iColumnIndex slice number + */ + virtual void returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSlice) = 0; + + /** Return a slice from the data in the y direction to the 3d data. The data will be deleted. If the slice was + * fetched with 'fetchSliceY', the data will be stored first. + * + * @param _iRowIndex slice number + */ + virtual void returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSlice) = 0; + + /** Return a slice from the data in the z direction to the 3d data. The data will be deleted. If the slice was + * fetched with 'fetchSliceZ', the data will be stored first. + * + * @param _iSliceIndex slice number + */ + virtual void returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSlice) = 0; + + /** This SLOW function returns a voxel value stored at a specific index in the array. + * Reading values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @return The value stored at the location specified by _iIndex + */ + virtual float32 getVoxelValue(int _iIndex) = 0; + + /** This SLOW function stores a voxel value at a specific index in the array. + * Writing values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @param _fValue The value to be stored at the location specified by _iIndex + */ + virtual void setVoxelValue(int _iIndex, float32 _fValue) = 0; + + /** + * Overloaded Operator: data += data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32VolumeData3D& operator+=(const CFloat32VolumeData3D& _data); + + /** + * Overloaded Operator: data -= data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32VolumeData3D& operator-=(const CFloat32VolumeData3D& _data); + + /** + * Overloaded Operator: data *= data (pointwise) + * + * @param _data r-value + * @return l-value + */ + CFloat32VolumeData3D& operator*=(const CFloat32VolumeData3D& _data); + + /** + * Overloaded Operator: data *= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32VolumeData3D& operator*=(const float32& _fScalar); + + /** + * Overloaded Operator: data /= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32VolumeData3D& operator/=(const float32& _fScalar); + + /** + * Overloaded Operator: data += scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32VolumeData3D& operator+=(const float32& _fScalar); + + /** + * Overloaded Operator: data -= scalar (pointwise) + * + * @param _fScalar r-value + * @return l-value + */ + CFloat32VolumeData3D& operator-=(const float32& _fScalar); + + /** + * Gives access to the geometry stored in this class + * + * @return The geometry describing the data stored in this volume + */ + virtual CVolumeGeometry3D* getGeometry() const; +}; + +//---------------------------------------------------------------------------------------- +// get row count +inline int CFloat32VolumeData3D::getRowCount() const +{ + return m_iHeight; +} + +//---------------------------------------------------------------------------------------- +// get column count +inline int CFloat32VolumeData3D::getColCount() const +{ + return m_iWidth; +} + +//---------------------------------------------------------------------------------------- +// get slice count +inline int CFloat32VolumeData3D::getSliceCount() const +{ + return m_iDepth; +} + +//---------------------------------------------------------------------------------------- +// get total voxel count +inline int CFloat32VolumeData3D::getVoxelTotCount() const +{ + return m_iHeight * m_iWidth * m_iDepth; +} + +//---------------------------------------------------------------------------------------- +// get type +inline CFloat32Data3D::EDataType CFloat32VolumeData3D::getType() const +{ + return CFloat32Data3D::VOLUME; +} + +//---------------------------------------------------------------------------------------- +// Get the volume geometry. +inline CVolumeGeometry3D* CFloat32VolumeData3D::getGeometry() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_pGeometry; +} +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32VOLUMEDATA2D diff --git a/include/astra/Float32VolumeData3DMemory.h b/include/astra/Float32VolumeData3DMemory.h new file mode 100644 index 0000000..51df93e --- /dev/null +++ b/include/astra/Float32VolumeData3DMemory.h @@ -0,0 +1,213 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA3DMEMORY +#define _INC_ASTRA_FLOAT32VOLUMEDATA3DMEMORY + +#include "Float32Data3DMemory.h" +#include "VolumeGeometry3D.h" +#include "Float32VolumeData3D.h" + +namespace astra { + +/** + * This class represents three-dimensional Volume Data where the entire data block is stored in memory. + */ +class _AstraExport CFloat32VolumeData3DMemory : public CFloat32Data3DMemory, public CFloat32VolumeData3D +{ +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CFloat32VolumeData3DMemory(); + + /** Constructor. Create an instance of the CFloat32VolumeData3DMemory class without initializing the data. + * + * Memory is allocated for the data block. The allocated memory is not cleared and + * its contents after construction is undefined. Construction may be followed by a + * call to copyData() to fill the memory block. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class. + */ + CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry); + + /** Constructor. Create an instance of the CFloat32VolumeData3DMemory class with initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, const float32* _pfData); + + /** Constructor. Create an instance of the CFloat32VolumeData3DMemory class with scalar initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value + */ + CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, float32 _fScalar); + + /** Destructor. + */ + virtual ~CFloat32VolumeData3DMemory(); + + /** Initialization. Initializes of the CFloat32VolumeData3DMemory class without initializing the data. + * + * Memory is allocated for the data block. The allocated memory is not cleared and + * its contents after construction is undefined. Construction may be followed by a + * call to copyData() to fill the memory block. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class. + * @return Initialization of the base class successful. + */ + bool initialize(CVolumeGeometry3D* _pGeometry); + + /** Initialization. Initializes an instance of the CFloat32VolumeData3DMemory class with initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class. + * @param _pfData pointer to a one-dimensional float32 data block + */ + bool initialize(CVolumeGeometry3D* _pGeometry, const float32* _pfData); + + /** Initialization. Initializes an instance of the CFloat32VolumeData3DMemory class with scalar initialization of the data. + * + * Memory is allocated for the data block and the contents of the memory pointed to by + * _pfData is copied into the allocated memory. + * The size of the data is determined by the specified volume geometry object. + * + * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class. + * @param _fScalar scalar value + */ + bool initialize(CVolumeGeometry3D* _pGeometry, float32 _fScalar); + + /** Which type is this class? + * + * @return DataType: VOLUME + */ + virtual CFloat32Data3D::EDataType getType() const; + + /** Get the volume geometry. + * + * @return pointer to volume geometry. + */ + CVolumeGeometry3D* getGeometry(); + + /** + * Gets a slice, containing all voxels with a given x (= column) index. + */ + CFloat32VolumeData2D * fetchSliceX(int _iColumnIndex) const; + + /** + * Gets a slice, containing all voxels with a given y (= row) index. + */ + CFloat32VolumeData2D * fetchSliceY(int _iRowIndex) const; + + /** + * Gets a slice, containing all voxels with a given z (= slice) index. + */ + CFloat32VolumeData2D * fetchSliceZ(int _iSliceIndex) const; + + /** + * Gets a slice, containing all voxels with a given x (= column) index. + */ + void returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSliceData); + + /** + * Gets a slice, containing all voxels with a given y (= row) index. + */ + void returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSliceData); + + /** + * Copies data from a 2D slice containing all voxels with a given z (= slice) index to the + * 3D memory stored in this class. + */ + void returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSliceData); + + /** This SLOW function returns a volume value stored a specific index in the array. + * Reading values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @return The value the location specified by _iIndex + */ + virtual float32 getVoxelValue(int _iIndex); + + /** This SLOW function stores a voxel value at a specific index in the array. + * Writing values in this way might cause a lot of unnecessary memory operations, don't + * use it in time-critical code. + * + * @param _iIndex Index in the array if the data were stored completely in main memory + * @param _fValue The value to be stored at the location specified by _iIndex + */ + virtual void setVoxelValue(int _iIndex, float32 _fValue); + + /** + * Overloaded Operator: data = data (pointwise) + * + * @param _dataIn r-value + * @return l-value + */ + CFloat32VolumeData3DMemory& operator=(const CFloat32VolumeData3DMemory& _dataIn); +}; + +//---------------------------------------------------------------------------------------- +// Get the projection geometry. +inline CVolumeGeometry3D* CFloat32VolumeData3DMemory::getGeometry() +{ + ASTRA_ASSERT(m_bInitialized); + return m_pGeometry; +} + +//---------------------------------------------------------------------------------------- +// Get type +inline CFloat32Data3D::EDataType CFloat32VolumeData3DMemory::getType() const +{ + return VOLUME; +} + + +} // end namespace astra + +#endif // _INC_ASTRA_FLOAT32VOLUMEDATA3DMEMORY diff --git a/include/astra/ForwardProjectionAlgorithm.h b/include/astra/ForwardProjectionAlgorithm.h new file mode 100644 index 0000000..147002b --- /dev/null +++ b/include/astra/ForwardProjectionAlgorithm.h @@ -0,0 +1,225 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FORWARDPROJECTIONALGORITHM +#define _INC_ASTRA_FORWARDPROJECTIONALGORITHM + +#include "Algorithm.h" + +#include "Globals.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +#include "DataProjector.h" + +namespace astra { + +/** + * \brief + * This class contains the implementation of an algorithm that creates a forward projection + * of a volume object and stores it into a sinogram. + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{VolumeDataId, integer, Identifier of the volume data object as it is stored in the DataManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of the resulting projection data object as it is stored in the DataManager.} + * \astra_xml_item_option{VolumeMaskId, integer, not used, Identifier of a volume data object that acts as a volume mask. 0 = don't use this pixel. 1 = use this pixel. } + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 0 = don't use this ray. 1 = use this ray.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('FP');\n + * cfg.ProjectorId = proj_id;\n + * cfg.VolumeDataId = vol_id;\n + * cfg.ProjectionDataId = sino_id;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('run'\, alg_id);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + */ +class _AstraExport CForwardProjectionAlgorithm : public CAlgorithm { + +protected: + + /** Init stuff + */ + virtual void _init(); + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - valid projector + * - valid data objects + */ + virtual bool _check(); + + //< Projector object. + CProjector2D* m_pProjector; + //< ProjectionData2D object containing the sinogram. + CFloat32ProjectionData2D* m_pSinogram; + //< VolumeData2D object containing the phantom. + CFloat32VolumeData2D* m_pVolume; + + // data projector + astra::CDataProjectorInterface* m_pForwardProjector; + + // ray or voxel-driven projector code? + bool m_bUseVoxelProjector; + + //< Dataobject containing fixed volume mask (0 = don't project) + CFloat32VolumeData2D* m_pVolumeMask; + //< Use the fixed reconstruction mask? + bool m_bUseVolumeMask; + + //< Dataobject containing fixed reconstruction mask (0 = don't project) + CFloat32ProjectionData2D* m_pSinogramMask; + //< Use the fixed reconstruction mask? + bool m_bUseSinogramMask; + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CForwardProjectionAlgorithm(); + + /** Initializing constructor. + * + * @param _pProjector Projector to use. + * @param _pVolume VolumeData2D object containing the phantom to compute sinogram from + * @param _pSinogram ProjectionData2D object to store sinogram data in. + */ + CForwardProjectionAlgorithm(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram); + + /** Destructor. + */ + virtual ~CForwardProjectionAlgorithm(); + + /** Clear this class. + */ + virtual void clear(); + + /** Initialize class. + * + * @param _pProjector Projector to use. + * @param _pVolume VolumeData2D object containing the phantom to compute sinogram from + * @param _pSinogram ProjectionData2D object to store sinogram data in. + * @return success + */ + bool initialize(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Set a fixed reconstruction mask. A pixel will only be used in the reconstruction if the + * corresponding value in the mask is 1. + * + * @param _pMask Volume Data object containing fixed reconstruction mask + * @param _bEnable enable the use of this mask + */ + void setVolumeMask(CFloat32VolumeData2D* _pMask, bool _bEnable = true); + + /** Set a fixed sinogram mask. A detector value will only be used in the reconstruction if the + * corresponding value in the mask is 1. + * + * @param _pMask Projection Data object containing fixed sinogram mask + * @param _bEnable enable the use of this mask + */ + void setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable = true); + + /** Get projector object + * + * @return projector + */ + CProjector2D* getProjector() const; + + /** Get sinogram data object + * + * @return sinogram data object + */ + CFloat32ProjectionData2D* getSinogram() const; + + /** Get volume data object + * + * @return volume data object + */ + CFloat32VolumeData2D* getVolume() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + +}; + +// inline functions +inline std::string CForwardProjectionAlgorithm::description() const { return CForwardProjectionAlgorithm::type; }; +inline CProjector2D* CForwardProjectionAlgorithm::getProjector() const { return m_pProjector; } +inline CFloat32ProjectionData2D* CForwardProjectionAlgorithm::getSinogram() const { return m_pSinogram; } +inline CFloat32VolumeData2D* CForwardProjectionAlgorithm::getVolume() const { return m_pVolume; } + +} // end namespace + +#endif diff --git a/include/astra/Fourier.h b/include/astra/Fourier.h new file mode 100644 index 0000000..290c094 --- /dev/null +++ b/include/astra/Fourier.h @@ -0,0 +1,127 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_FOURIER +#define _INC_ASTRA_FOURIER + +#include "Globals.h" + +namespace astra { + + +/** + * Perform a 1D DFT or inverse DFT. + * + * @param iLength number of elements + * @param pfRealIn real part of input + * @param pfImaginaryIn imaginary part of input + * @param pfRealOut real part of output + * @param pfImaginaryOut imaginary part of output + * @param iStrideIn distance between elements in pf*In + * @param iStrideOut distance between elements in pf*Out + * @param bInverse if true, perform an inverse DFT + */ + +void _AstraExport discreteFourierTransform1D(unsigned int iLength, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + unsigned int iStrideIn, + unsigned int iStrideOut, + bool bInverse); + +/** + * Perform a 2D DFT or inverse DFT. + * + * @param iHeight number of rows + * @param iWidth number of columns + * @param pfRealIn real part of input + * @param pfImaginaryIn imaginary part of input + * @param pfRealOut real part of output + * @param pfImaginaryOut imaginary part of output + * @param bInverse if true, perform an inverse DFT + */ + +void _AstraExport discreteFourierTransform2D(unsigned int iHeight, unsigned int iWidth, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + bool bInverse); + +/** + * Perform a 1D FFT or inverse FFT. The size must be a power of two. + * This transform can be done in-place, so the input and output pointers + * may point to the same data. + * + * @param iLength number of elements, must be a power of two + * @param pfRealIn real part of input + * @param pfImaginaryIn imaginary part of input + * @param pfRealOut real part of output + * @param pfImaginaryOut imaginary part of output + * @param iStrideIn distance between elements in pf*In + * @param iStrideOut distance between elements in pf*Out + * @param bInverse if true, perform an inverse DFT + */ + +void _AstraExport fastTwoPowerFourierTransform1D(unsigned int iLength, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + unsigned int iStrideIn, + unsigned int iStrideOut, + bool bInverse); + +/** + * Perform a 2D FFT or inverse FFT. The size must be a power of two. + * This transform can be done in-place, so the input and output pointers + * may point to the same data. + * + * @param iHeight number of rows, must be a power of two + * @param iWidth number of columns, must be a power of two + * @param pfRealIn real part of input + * @param pfImaginaryIn imaginary part of input + * @param pfRealOut real part of output + * @param pfImaginaryOut imaginary part of output + * @param bInverse if true, perform an inverse DFT + */ + +void _AstraExport fastTwoPowerFourierTransform2D(unsigned int iHeight, + unsigned int iWidth, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + bool bInverse); + + +} + +#endif diff --git a/include/astra/Globals.h b/include/astra/Globals.h new file mode 100644 index 0000000..9407ef9 --- /dev/null +++ b/include/astra/Globals.h @@ -0,0 +1,309 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_GLOBALS +#define _INC_ASTRA_GLOBALS + +/*! \mainpage The ASTRA-toolbox + * + * <img src="../images/logo_big.png"/> + */ + + +//---------------------------------------------------------------------------------------- + +#ifdef _MSC_VER + +// disable warning: 'fopen' was declared deprecated +#pragma warning (disable : 4996) +// disable warning: C++ exception handler used, but unwind semantics are not enables +#pragma warning (disable : 4530) +// disable warning: no suitable definition provided for explicit template instantiation request +#pragma warning (disable : 4661) + +#endif + +//---------------------------------------------------------------------------------------- +// standard includes +#include <cassert> +#include <iostream> +#include <fstream> +#include <math.h> +#include <boost/static_assert.hpp> +#include <boost/throw_exception.hpp> + +//---------------------------------------------------------------------------------------- +// macro's + +#define ASTRA_TOOLBOXVERSION_MAJOR 1 +#define ASTRA_TOOLBOXVERSION_MINOR 1 +#define ASTRA_TOOLBOXVERSION ((ASTRA_TOOLBOXVERSION_MAJOR)*100 + (ASTRA_TOOLBOXVERSION_MINOR)) +#define ASTRA_TOOLBOXVERSION_STRING "1.1" + + +#define ASTRA_ASSERT(a) assert(a) + +#define ASTRA_CONFIG_CHECK(value, type, msg) if (!(value)) { cout << "Configuration Error in " << type << ": " << msg << endl; return false; } + +#define ASTRA_CONFIG_WARNING(type, msg) { cout << "Warning in " << type << ": " << msg << endl; } + + +#define ASTRA_DELETE(a) if (a) { delete a; a = NULL; } +#define ASTRA_DELETE_ARRAY(a) if (a) { delete[] a; a = NULL; } + +#ifdef _MSC_VER + +#ifdef DLL_EXPORTS +#define _AstraExport __declspec(dllexport) +#define EXPIMP_TEMPLATE +#else +#define _AstraExport __declspec(dllimport) +#define EXPIMP_TEMPLATE extern +#endif + +#else + +#define _AstraExport + +#endif + + +//---------------------------------------------------------------------------------------- +// typedefs +namespace astra { + typedef float float32; + typedef double float64; + typedef unsigned short int uint16; + typedef signed short int sint16; + typedef unsigned char uchar8; + typedef signed char schar8; + + typedef int int32; + typedef short int int16; +} + +//---------------------------------------------------------------------------------------- +// globals vars & functions +//namespace astra { +//#define ToolboxVersion 0.1f; + +//float32 getVersion() { return ToolboxVersion; } + +//_AstraExport bool cudaEnabled() { +//#ifdef ASTRA_CUDA +// return true; +//#else +// return false; +//#endif +//} +//} + +//---------------------------------------------------------------------------------------- +// errors +namespace astra { + +typedef enum {ASTRA_SUCCESS, + ASTRA_ERROR_NOT_INITIALIZED, + ASTRA_ERROR_INVALID_FILE, + ASTRA_ERROR_OUT_OF_RANGE, + ASTRA_ERROR_DIMENSION_MISMATCH, + ASTRA_ERROR_EXTERNAL_LIBRARY, + ASTRA_ERROR_ALLOCATION, + ASTRA_ERROR_NOT_IMPLEMENTED} AstraError; +} + + +//---------------------------------------------------------------------------------------- +// variables +namespace astra { + const float32 PI = 3.14159265358979323846264338328f; + const float32 PI32 = 3.14159265358979323846264338328f; + const float32 PIdiv2 = PI / 2; + const float32 PIdiv4 = PI / 4; + const float32 eps = 1e-7f; +} + +//---------------------------------------------------------------------------------------- +// math +namespace astra { + + inline float32 cos_73s(float32 x) + { + /* + const float32 c1 = 0.999999953464f; + const float32 c2 = -0.4999999053455f; + const float32 c3 = 0.0416635846769f; + const float32 c4 = -0.0013853704264f; + const float32 c5 = 0.000023233f; + */ + const float c1= (float)0.99940307; + const float c2= (float)-0.49558072; + const float c3= (float)0.03679168; + + float32 x2; + x2 = x * x; + //return (c1 + x2*(c2 + x2*(c3 + x2*(c4 + c5*x2)))); + return (c1 + x2*(c2 + c3 * x2)); + } + + inline float32 fast_cos(float32 x) + { + int quad; + + //x = fmod(x, 2*PI); // Get rid of values > 2* pi + if (x < 0) x =- x; // cos(-x) = cos(x) + quad = int(x/PIdiv2); // Get quadrant # (0 to 3) + switch (quad) { + case 0: return cos_73s(x); + case 1: return -cos_73s(PI-x); + case 2: return -cos_73s(x-PI); + case 3: return cos_73s(2*PI-x); + } + return 0.0f; + } + + inline float32 fast_sin(float32 x){ + return fast_cos(PIdiv2-x); + } + +} + +//---------------------------------------------------------------------------------------- +// structs +namespace astra { + /** + * Struct for storing pixel weigths + **/ + struct SPixelWeight + { + int m_iIndex; + float32 m_fWeight; + }; + + /** + * Struct combining some properties of a detector in 1D detector row + **/ + struct SDetector2D + { + int m_iIndex; + int m_iAngleIndex; + int m_iDetectorIndex; + }; + + /** + * Struct combining some properties of a detector in 2D detector array + **/ + struct SDetector3D + { + int m_iIndex; + int m_iAngleIndex; + int m_iDetectorIndex; + int m_iSliceIndex; + }; +} +//---------------------------------------------------------------------------------------- +// some toys + +// safe reinterpret cast +template <class To, class From> +To safe_reinterpret_cast(From from) +{ + BOOST_STATIC_ASSERT(sizeof(From) <= sizeof(To)); + return reinterpret_cast<To>(from); +} + +//---------------------------------------------------------------------------------------- +// functions for testing +template<typename T> +inline void writeArray(T*** arr, int dim1, int dim2, int dim3, const std::string& filename) +{ + std::ofstream out(filename.c_str()); + int i1, i2, i3; + for (i1 = 0; i1 < dim1; ++i1) { + for (i2 = 0; i2 < dim2; ++i2) { + for (i3 = 0; i3 < dim3; ++i3) { + out << arr[i1][i2][i3] << " "; + } + out << std::endl; + } + out << std::endl; + } + out.close(); +} + +template<typename T> +inline void writeArray(T** arr, int dim1, int dim2, const std::string& filename) +{ + std::ofstream out(filename.c_str()); + for (int i1 = 0; i1 < dim1; i1++) { + for (int i2 = 0; i2 < dim2; i2++) { + out << arr[i1][i2] << " "; + } + out << std::endl; + } + out.close(); +} + +template<typename T> +inline void writeArray(T* arr, int dim1, const std::string& filename) +{ + std::ofstream out(filename.c_str()); + for (int i1 = 0; i1 < dim1; i1++) { + out << arr[i1] << " "; + } + out.close(); +} +namespace astra { +_AstraExport inline int getVersion() { return ASTRA_TOOLBOXVERSION; } +_AstraExport inline const char* getVersionString() { return ASTRA_TOOLBOXVERSION_STRING; } +#ifdef ASTRA_CUDA +_AstraExport inline bool cudaEnabled() { return true; } +#else +_AstraExport inline bool cudaEnabled() { return false; } +#endif +} +//---------------------------------------------------------------------------------------- +// portability between MSVC and Linux/gcc + +#ifndef _MSC_VER +#include "swrap.h" +#define EXPIMP_TEMPLATE + +#if !defined(FORCEINLINE) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +#define FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define FORCEINLINE inline +#endif + +#else + +#define FORCEINLINE __forceinline + +#endif + +#endif diff --git a/include/astra/Logger.h b/include/astra/Logger.h new file mode 100644 index 0000000..ae064fe --- /dev/null +++ b/include/astra/Logger.h @@ -0,0 +1,72 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_LOGGER +#define _INC_ASTRA_LOGGER + +#include <cstdio> + +namespace astra +{ + +/** + * This is the first stab at a decent logger. If the file "astra_logger.txt", it will be replaced + * with the text sent to this logger. If the file doesn't exist when the app starts, nothing is written. + */ +class CLogger +{ + static std::FILE * m_pOutFile; + static bool m_bInitialized; + + static void _assureIsInitialized(); + + CLogger(); + +public: + + /** + * Writes a line to the log file (newline is added). Ignored if logging is turned off. + * + * @param _text char pointer to text in line + */ + static void writeLine(const char * _text); + + /** + * Formats and writes a CUDA error to the log file. Ignored if logging is turned off. + * + * @param _fileName filename where error occurred (typically __FILE__) + * @param _line line in file (typically __LINE__) + * @param _errString string describing the error, can be output of cudaGetErrorString + */ + static void writeTerminalCUDAError(const char * _fileName, int _iLine, const char * _errString); +}; + +} + +#endif /* _INC_ASTRA_LOGGER */ + diff --git a/include/astra/ParallelBeamBlobKernelProjector2D.h b/include/astra/ParallelBeamBlobKernelProjector2D.h new file mode 100644 index 0000000..38b209c --- /dev/null +++ b/include/astra/ParallelBeamBlobKernelProjector2D.h @@ -0,0 +1,232 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELBEAMBLOBPROJECTOR +#define _INC_ASTRA_PARALLELBEAMBLOBPROJECTOR + +#include "ParallelProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +namespace astra +{ + +/** This class implements a two-dimensional projector based on a blob-kernel. + * A more detailed description (in dutch) is available at + * http://www.astra.ua.ac.be/wiki/images/6/6e/Uitleg_blob_projector.pdf + * + * \par XML Configuration + * type = "blob" + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * \astra_xml_item{Kernel, xml node, Kernel details. See below.} + * + * \par XML Configuration of the Kernel + * \astra_xml_item{KernelSize, float, Radius of the kernel.} + * \astra_xml_item{SampleRate, float, Sample rate of the kernel.} + * \astra_xml_item{SampleCount, integer, Number of samples.} + * \astra_xml_item{KernelValues, vector of float, Samples of the kernels starting at distance 0.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('blob');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * cfg.Kernel.KernelSize = 2;\n + * cfg.Kernel.SampleRate = 0.01;\n + * cfg.Kernel.SampleCount = length(0:0.01:2);\n + * cfg.Kernel.KernelValues = kaiserBessel(2\, 10.4\, 2\, 0:0.01:2);\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CParallelBeamBlobKernelProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CParallelBeamBlobKernelProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @param _fBlobSize Width of the blob. In units of PixelSize. + * @param _fBlobSampleRate Spacing between two blob samples. (= _fBlobSize/_iBlobSampleCount) + * @param _iBlobSampleCount Number of samples. + * @param _pfBlobValues Array of _iBlobSampleCount blob evaluations. + */ + CParallelBeamBlobKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry, + float32 _fBlobSize, + float32 _fBlobSampleRate, + int _iBlobSampleCount, + float32* _pfBlobValues); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CParallelBeamBlobKernelProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @param _fBlobSize Width of the blob. In units of PixelSize. + * @param _fBlobSampleRate Spacing between two blob samples. (= _fBlobSize/_iBlobSampleCount) + * @param _iBlobSampleCount Number of samples. + * @param _pfBlobValues Array of _iBlobSampleCount blob evaluations. Will be HARDCOPIED. + */ + bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry, + float32 _fBlobSize, + float32 _fBlobSampleRate, + int _iBlobSampleCount, + float32* _pfBlobValues); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Wwhich projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + +protected: + + /** Evaluate the blob kernel for a given distance from its center. + * + * @param _fDiff distance between hit point and blob center + * @return blob value + */ + float32 _getBlobValue(float32 _fDiff); + + float32 m_fBlobSize; //< Width of the blob + float32 m_fBlobSampleRate; //< At which interval are the inserted blob values evaluated? + int m_iBlobSampleCount; //< Number of evaluated blob samples + float32* m_pfBlobValues; //< Evaluated blob values + float32* m_pfBlobValuesNeg; //< Evaluated blob values + +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CParallelBeamBlobKernelProjector2D::getType() +{ + return type; +} + +} // namespace astra + +#endif + diff --git a/include/astra/ParallelBeamBlobKernelProjector2D.inl b/include/astra/ParallelBeamBlobKernelProjector2D.inl new file mode 100644 index 0000000..70764b1 --- /dev/null +++ b/include/astra/ParallelBeamBlobKernelProjector2D.inl @@ -0,0 +1,212 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CParallelBeamBlobKernelProjector2D::project(Policy& p) +{ + for (int iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { + for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + projectSingleRay(iAngle, iDetector, p); + } + } +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CParallelBeamBlobKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + projectSingleRay(_iProjection, iDetector, p); + } +} + + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CParallelBeamBlobKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) return; + + // get values + float32 t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector); + float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + + bool flip = false; + + if (theta >= 3*PIdiv4) { + theta -= PI; + t = -t; + flip = true; + } + + + if (theta <= PIdiv4) { // -pi/4 <= theta <= pi/4 + + // precalculate sin, cos, 1/cos + float32 sin_theta = sin(theta); + float32 cos_theta = cos(theta); + float32 inv_cos_theta = 1.0f / cos_theta; + + // precalculate other stuff + float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + float32 updatePerRow = sin_theta * lengthPerRow; + float32 inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + float32 pixelLengthX_over_blobSize = m_pVolumeGeometry->getPixelLengthX() / m_fBlobSize; + + // some variables + int row, col, xmin, xmax; + float32 P, x, d; + + // calculate P and x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // calculate extent + xmin = (int)ceil((P - m_fBlobSize - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f); + xmax = (int)floor((P + m_fBlobSize - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f); + + // add pixels + for (col = xmin; col <= xmax; col++) { + if (col >= 0 && col < m_pVolumeGeometry->getGridColCount()) { + //d = abs(x - col) * pixelLengthX_over_blobSize; + //index = (int)(d*m_iBlobSampleCount+0.5f); + //float32 fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)] * lengthPerRow; + + float32 fWeight; + int index; + if ((x >= col) ^ flip) { + d = abs(x - col) * pixelLengthX_over_blobSize * cos_theta; + index = (int)(d*m_iBlobSampleCount+0.5f); + fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)]; + } else { + d = abs(x - col) * pixelLengthX_over_blobSize * cos_theta; + index = (int)(d*m_iBlobSampleCount+0.5f); + fWeight = m_pfBlobValuesNeg[min(index,m_iBlobSampleCount-1)]; + } + + int iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, fWeight); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // update P and x + P += updatePerRow; + x += updatePerRow * inv_pixelLengthX; + } + + } else { // pi/4 < theta < 3pi/4 + + // precalculate sin cos + float32 sin_90_theta = sin(PIdiv2-theta); + float32 cos_90_theta = cos(PIdiv2-theta); + float32 inv_cos_90_theta = 1.0f / cos_90_theta; + + // precalculate other stuff + float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_cos_90_theta; + float32 updatePerCol = sin_90_theta * lengthPerCol; + float32 inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + float32 pixelLengthY_over_blobSize = m_pVolumeGeometry->getPixelLengthY() / m_fBlobSize; + + // some variables + int row, col, xmin, xmax; + float32 P,x, d; + + // calculate P and x for col 0 + P = (sin_90_theta * m_pVolumeGeometry->pixelColToCenterX(0) - t) * inv_cos_90_theta; + x = (P - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // calculate extent + xmin = (int)ceil((P - m_fBlobSize - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f); + xmax = (int)floor((P + m_fBlobSize - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f); + + // add pixels + for (row = xmin; row <= xmax; row++) { + if (row >= 0 && row < m_pVolumeGeometry->getGridRowCount()) { + //d = abs(x - row) * pixelLengthY_over_blobSize; + //int index = (int)(d*m_iBlobSampleCount+0.5f); + //float32 fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)] * lengthPerCol; + + float32 fWeight; + int index; + if ((x <= row) ^ flip) { + d = abs(x - row) * pixelLengthY_over_blobSize * cos_90_theta; + index = (int)(d*m_iBlobSampleCount+0.5f); + fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)]; + } else { + d = abs(x - row) * pixelLengthY_over_blobSize * cos_90_theta; + index = (int)(d*m_iBlobSampleCount+0.5f); + fWeight = m_pfBlobValuesNeg[min(index,m_iBlobSampleCount-1)]; + } + + + int iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, fWeight); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // update P and x + P += updatePerCol; + x += updatePerCol * inv_pixelLengthY; + } + + } + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + + +} diff --git a/include/astra/ParallelBeamLineKernelProjector2D.h b/include/astra/ParallelBeamLineKernelProjector2D.h new file mode 100644 index 0000000..9e2cc5a --- /dev/null +++ b/include/astra/ParallelBeamLineKernelProjector2D.h @@ -0,0 +1,186 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELBEAMLINEKERNELPROJECTOR +#define _INC_ASTRA_PARALLELBEAMLINEKERNELPROJECTOR + +#include "ParallelProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +namespace astra +{ + +/** This class implements a two-dimensional projector based on a line based kernel. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('line');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CParallelBeamLineKernelProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CParallelBeamLineKernelProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CParallelBeamLineKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CParallelBeamLineKernelProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @return initialization successful? + */ + virtual bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Wwhich projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + +}; + +inline std::string CParallelBeamLineKernelProjector2D::getType() +{ + return type; +} + +} // namespace astra + +#endif + diff --git a/include/astra/ParallelBeamLineKernelProjector2D.inl b/include/astra/ParallelBeamLineKernelProjector2D.inl new file mode 100644 index 0000000..08bbe5f --- /dev/null +++ b/include/astra/ParallelBeamLineKernelProjector2D.inl @@ -0,0 +1,731 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CParallelBeamLineKernelProjector2D::project(Policy& p) +{ + // variables + float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY; + int iVolumeIndex, iRayIndex, row, col, iAngle, iDetector, x1; + bool switch_t; + + // loop angles + for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { + + // get theta + theta = m_pProjectionGeometry->getProjectionAngle(iAngle); + switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_sin_theta = 1.0f / sin_theta; + inv_cos_theta = 1.0f / cos_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // precalculate S and T + S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow); + T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol); + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) t = -t; + + // vertically + if (theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX; + + // get coords + int nextx1 = int((x > 0.0f) ? x : x-1.0f); + float nextx2 = x - nextx1; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + x1 = nextx1; + x2 = nextx2; + + nextx2 += updatePerRow; + while (nextx2 >= 1.0f) { + nextx2 -= 1.0f; + nextx1++; + } + while (nextx2 < 0.0f) { + nextx2 += 1.0f; + nextx1--; + } + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue; + + // left + if (x2 < 0.5f-S) { + I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+S) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // right + else { + I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } + + // horizontally + else if (PIdiv4 <= theta && theta <= 3*PIdiv4) { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY; + + // get coords + int nextx1 = int((x > 0.0f) ? x : x-1.0f); + float nextx2 = x - nextx1; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + x1 = nextx1; + x2 = nextx2; + + nextx2 += updatePerCol; + while (nextx2 >= 1.0f) { + nextx2 -= 1.0f; + nextx1++; + } + while (nextx2 < 0.0f) { + nextx2 += 1.0f; + nextx1--; + } + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue; + + // up + if (x2 < 0.5f-T) { + I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+T) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // down + else { + I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } // end loop col + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end loop detector + } // end loop angles + +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CParallelBeamLineKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + // variables + float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY; + int iVolumeIndex, iRayIndex, row, col, iDetector, x1; + bool switch_t; + + // get theta + theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_sin_theta = 1.0f / sin_theta; + inv_cos_theta = 1.0f / cos_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // precalculate S and T + S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow); + T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol); + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) t = -t; + + // vertically + if (theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX; + + // get coords + int nextx1 = int((x > 0.0f) ? x : x-1.0f); + float nextx2 = x - nextx1; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + x1 = nextx1; + x2 = nextx2; + + nextx2 += updatePerRow; + while (nextx2 >= 1.0f) { + nextx2 -= 1.0f; + nextx1++; + } + while (nextx2 < 0.0f) { + nextx2 += 1.0f; + nextx1--; + } + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue; + + // left + if (x2 < 0.5f-S) { + I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+S) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // right + else { + I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } + + // horizontally + else if (PIdiv4 <= theta && theta <= 3*PIdiv4) { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY; + + // get coords + int nextx1 = int((x > 0.0f) ? x : x-1.0f); + float nextx2 = x - nextx1; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + x1 = nextx1; + x2 = nextx2; + + nextx2 += updatePerCol; + while (nextx2 >= 1.0f) { + nextx2 -= 1.0f; + nextx1++; + } + while (nextx2 < 0.0f) { + nextx2 += 1.0f; + nextx1--; + } + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue; + + // up + if (x2 < 0.5f-T) { + I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+T) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // down + else { + I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } // end loop col + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end loop detector +} + + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CParallelBeamLineKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) return; + + // variables + float32 t, I, P, x, x2; + int iVolumeIndex, row, col, x1; + + // get theta + float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector); + if (switch_t) t = -t; + + // vertically + if (theta <= PIdiv4) { + + float32 sin_theta = sin(theta); + float32 inv_cos_theta = 1.0f / cos(theta); + + // precalculate kernel limits + float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + float32 updatePerRow = sin_theta * inv_cos_theta; + float32 inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + float32 S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow); + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX; + + // get coords + int nextx1 = int((x > 0.0f) ? x : x-1.0f); + float nextx2 = x - nextx1; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + x1 = nextx1; + x2 = nextx2; + + nextx2 += updatePerRow; + while (nextx2 >= 1.0f) { + nextx2 -= 1.0f; + nextx1++; + } + while (nextx2 < 0.0f) { + nextx2 += 1.0f; + nextx1--; + } + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue; + + // left + if (x2 < 0.5f-S) { + I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+S) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // right + else { + I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } + + // horizontally + else if (PIdiv4 <= theta && theta <= 3*PIdiv4) { + + float32 cos_theta = cos(theta); + float32 inv_sin_theta = 1.0f / sin(theta); + + // precalculate kernel limits + float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + float32 updatePerCol = cos_theta * inv_sin_theta; + float32 inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + float32 T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol); + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY; + + // get coords + int nextx1 = int((x > 0.0f) ? x : x-1.0f); + float nextx2 = x - nextx1; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + x1 = nextx1; + x2 = nextx2; + + nextx2 += updatePerCol; + while (nextx2 >= 1.0f) { + nextx2 -= 1.0f; + nextx1++; + } + while (nextx2 < 0.0f) { + nextx2 += 1.0f; + nextx1--; + } + + if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue; + + // up + if (x2 < 0.5f-T) { + I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // center + else if (x2 <= 0.5f+T) { + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + + // down + else { + I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol; + + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, I); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + } // end loop col + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + +} diff --git a/include/astra/ParallelBeamLinearKernelProjector2D.h b/include/astra/ParallelBeamLinearKernelProjector2D.h new file mode 100644 index 0000000..ac5899e --- /dev/null +++ b/include/astra/ParallelBeamLinearKernelProjector2D.h @@ -0,0 +1,194 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELLINEARKERNELPROJECTOR +#define _INC_ASTRA_PARALLELLINEARKERNELPROJECTOR + +#include "ParallelProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +namespace astra +{ + +/** This class implements a two-dimensional projector based on a lineary interpolated kernel. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('linear');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CParallelBeamLinearKernelProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CParallelBeamLinearKernelProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CParallelBeamLinearKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CParallelBeamLinearKernelProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @return initialization successful? + */ + virtual bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CParallelBeamLinearKernelProjector2D::getType() +{ + return type; +} + + +} // namespace astra + + +#endif + diff --git a/include/astra/ParallelBeamLinearKernelProjector2D.inl b/include/astra/ParallelBeamLinearKernelProjector2D.inl new file mode 100644 index 0000000..66b1cb2 --- /dev/null +++ b/include/astra/ParallelBeamLinearKernelProjector2D.inl @@ -0,0 +1,416 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CParallelBeamLinearKernelProjector2D::project(Policy& p) +{ + // variables + float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, t; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX; + float32 lengthPerCol, updatePerCol, inv_pixelLengthY; + bool switch_t; + int iAngle, iDetector, iVolumeIndex, iRayIndex; + int row, col, x1; + float32 P,x,x2; + + // loop angles + for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { + + // get theta + theta = m_pProjectionGeometry->getProjectionAngle(iAngle); + switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_cos_theta = 1.0f / cos_theta; + inv_sin_theta = 1.0f / sin_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) { + t = -t; + } + + // vertically + if (theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = m_pVolumeGeometry->coordXToColF(P) - 0.5f; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerRow; + + // add weights + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (x2) * lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + + // horizontally + else if (PIdiv4 <= theta && theta <= 3*PIdiv4) { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = m_pVolumeGeometry->coordYToRowF(P) - 0.5f; + + // for each row + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get coords + x1 = int((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerCol; + + // add weights + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, x2 * lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end loop detector + } // end loop angles + +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CParallelBeamLinearKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + // variables + float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, t; + float32 lengthPerRow, updatePerRow, inv_pixelLengthX; + float32 lengthPerCol, updatePerCol, inv_pixelLengthY; + bool switch_t; + int iDetector, iVolumeIndex, iRayIndex; + int row, col, x1; + float32 P,x,x2; + + // get theta + theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_cos_theta = 1.0f / cos_theta; + inv_sin_theta = 1.0f / sin_theta; + + // precalculate kernel limits + lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + updatePerRow = sin_theta * inv_cos_theta; + inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); + + // precalculate kernel limits + lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + updatePerCol = cos_theta * inv_sin_theta; + inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) { + t = -t; + } + + // vertically + if (theta <= PIdiv4) { + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = m_pVolumeGeometry->coordXToColF(P) - 0.5f; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get coords + x1 = (int)((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerRow; + + // add weights + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (x2) * lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + + // horizontally + else if (PIdiv4 <= theta && theta <= 3*PIdiv4) { + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = m_pVolumeGeometry->coordYToRowF(P) - 0.5f; + + // for each row + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get coords + x1 = (int)((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerCol; + + // add weights + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, x2 * lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end loop detector +} + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CParallelBeamLinearKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + int iVolumeIndex, iRayIndex; + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) return; + + // get theta + float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // get t + float32 t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector); + if (switch_t) { + t = -t; + } + + // vertically + if (theta <= PIdiv4) { + + // precalculate sin, 1/cos + float32 sin_theta = sin(theta); + float32 inv_cos_theta = 1.0f / cos(theta); + + // precalculate kernel limits + float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; + float32 updatePerRow = sin_theta * inv_cos_theta; + + int row, x1; + float32 P,x,x2; + + // calculate x for row 0 + P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; + x = m_pVolumeGeometry->coordXToColF(P) - 0.5f; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get coords + x1 = (int)((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerRow; + + // add weights + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (x2) * lengthPerRow); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + + // horizontally + else if (PIdiv4 <= theta && theta <= 3*PIdiv4) { + + // precalculate cos 1/sin + float32 cos_theta = cos(theta); + float32 inv_sin_theta = 1.0f / sin(theta); + + // precalculate kernel limits + float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta; + float32 updatePerCol = cos_theta * inv_sin_theta; + + int col, x1; + float32 P,x,x2; + + // calculate point P + P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta; + x = m_pVolumeGeometry->coordYToRowF(P) - 0.5f; + + // for each row + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get coords + x1 = (int)((x > 0.0f) ? x : x-1.0f); + x2 = x - x1; + x += updatePerCol; + + // add weights + if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridRowCount()) { + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col); + // POLICY: PIXEL PRIOR + ADD + POSTERIOR + if (p.pixelPrior(iVolumeIndex)) { + p.addWeight(iRayIndex, iVolumeIndex, x2 * lengthPerCol); + p.pixelPosterior(iVolumeIndex); + } + } + } + } + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); +} diff --git a/include/astra/ParallelBeamStripKernelProjector2D.h b/include/astra/ParallelBeamStripKernelProjector2D.h new file mode 100644 index 0000000..de056de --- /dev/null +++ b/include/astra/ParallelBeamStripKernelProjector2D.h @@ -0,0 +1,191 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELBEAMSTROKEKERNELPROJECTOR +#define _INC_ASTRA_PARALLELBEAMSTROKEKERNELPROJECTOR + +#include "ParallelProjectionGeometry2D.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +namespace astra +{ + + +/** This class implements a two-dimensional projector based on a strip based kernel. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('strip');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CParallelBeamStripKernelProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - blobvalues are ok + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CParallelBeamStripKernelProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CParallelBeamStripKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CParallelBeamStripKernelProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @return initialization successful? + */ + virtual bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Wwhich projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + +protected: + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CParallelBeamStripKernelProjector2D::getType() +{ + return type; +} + +} // namespace astra + +#endif + diff --git a/include/astra/ParallelBeamStripKernelProjector2D.inl b/include/astra/ParallelBeamStripKernelProjector2D.inl new file mode 100644 index 0000000..c55fa8e --- /dev/null +++ b/include/astra/ParallelBeamStripKernelProjector2D.inl @@ -0,0 +1,739 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CParallelBeamStripKernelProjector2D::project(Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + // Some variables + float32 theta, t; + int row, col; + int iAngle; + int iDetector; + float32 res; + float32 PL, PLimitL, PLimitR; + float32 xL, xR, XLimitL, XLimitR; + int x1L,x1R; + float32 x2L, x2R, updateX; + int iVolumeIndex, iRayIndex; + + float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta; + float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta; + float32 PW, PH, DW, inv_PW, inv_PH; + float32 S, T, U, V, inv_4T; + + // loop angles + for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { + + // get values + theta = m_pProjectionGeometry->getProjectionAngle(iAngle); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // Precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_cos_theta = 1.0f / cos_theta; + inv_sin_theta = 1.0f / sin_theta; + + fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta; + fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta; + fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta; + fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta; + + // Other precalculations + PW = m_pVolumeGeometry->getPixelLengthX(); + PH = m_pVolumeGeometry->getPixelLengthY(); + DW = m_pProjectionGeometry->getDetectorWidth(); + inv_PW = 1.0f / PW; + inv_PH = 1.0f / PH; + + // [-45?,45?] and [135?,225?] + if (theta < PIdiv4) { + + // Precalculate kernel limits + S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta; + T = -S; + U = 1.0f + S; + V = 1.0f - S; + inv_4T = 0.25f / T; + + updateX = sin_theta * inv_cos_theta; + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) t = -t; + + // calculate left strip extremes (volume coordinates) + PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta; + PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH; + PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta; + + // calculate strip extremes (pixel coordinates) + XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + xR = xL + (DW * inv_cos_theta) * inv_PW; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX; + XLimitR += updateX; + xL += updateX; + xR += updateX; + + // for each affected col + for (col = x1L; col <= x1R; ++col) { + + if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V) res = 1.0f; + else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T; + else if (x2R >= T) res = x2R; + else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S) {} // - 0.0f + else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T; + else if (x2L <= U) res -= x2L; + else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + // [45?,135?] and [225?,315?] + // horizontaly + } else { + + // Precalculate kernel limits + S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta; + T = -S; + U = 1.0f + S; + V = 1.0f - S; + inv_4T = 0.25f / T; + + updateX = cos_theta * inv_sin_theta; + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) t = -t; + + // calculate left strip extremes (volume coordinates) + PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta; + PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW; + PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta; + + // calculate strip extremes (pixel coordinates) + XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH; + XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH; + xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH; + xR = xL + (DW * fabs_inv_sin_theta) * inv_PH; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX; + XLimitR += updateX; + xL += updateX; + xR += updateX; + + // for each affected col + for (row = x1L; row <= x1R; ++row) { + + if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V) res = 1.0f; + else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T; + else if (x2R >= T) res = x2R; + else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S) {} // - 0.0f + else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T; + else if (x2L <= U) res -= x2L; + else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end row loop + + } // end col loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + + } // end theta switch + + } // end angle loop +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CParallelBeamStripKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + // Some variables + float32 theta, t; + int row, col, iDetector; + float32 res; + float32 PL, PLimitL, PLimitR; + float32 xL, xR, XLimitL, XLimitR; + int x1L,x1R; + float32 x2L, x2R, updateX; + int iVolumeIndex, iRayIndex; + + float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta; + float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta; + float32 PW, PH, DW, inv_PW, inv_PH; + float32 S, T, U, V, inv_4T; + + // get values + theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // Precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_cos_theta = 1.0f / cos_theta; + inv_sin_theta = 1.0f / sin_theta; + + fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta; + fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta; + fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta; + fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta; + + // Other precalculations + PW = m_pVolumeGeometry->getPixelLengthX(); + PH = m_pVolumeGeometry->getPixelLengthY(); + DW = m_pProjectionGeometry->getDetectorWidth(); + inv_PW = 1.0f / PW; + inv_PH = 1.0f / PH; + + // [-45?,45?] and [135?,225?] + if (theta < PIdiv4) { + + // Precalculate kernel limits + S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta; + T = -S; + U = 1.0f + S; + V = 1.0f - S; + inv_4T = 0.25f / T; + + updateX = sin_theta * inv_cos_theta; + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) t = -t; + + // calculate left strip extremes (volume coordinates) + PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta; + PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH; + PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta; + + // calculate strip extremes (pixel coordinates) + XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + xR = xL + (DW * inv_cos_theta) * inv_PW; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX; + XLimitR += updateX; + xL += updateX; + xR += updateX; + + // for each affected col + for (col = x1L; col <= x1R; ++col) { + + if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V) res = 1.0f; + else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T; + else if (x2R >= T) res = x2R; + else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S) {} // - 0.0f + else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T; + else if (x2L <= U) res -= x2L; + else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + // [45?,135?] and [225?,315?] + // horizontaly + } else { + + // Precalculate kernel limits + S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta; + T = -S; + U = 1.0f + S; + V = 1.0f - S; + inv_4T = 0.25f / T; + + updateX = cos_theta * inv_sin_theta; + + // loop detectors + for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { + + iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) continue; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(iDetector); + if (switch_t) t = -t; + + // calculate left strip extremes (volume coordinates) + PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta; + PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW; + PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta; + + // calculate strip extremes (pixel coordinates) + XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH; + XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH; + xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH; + xR = xL + (DW * fabs_inv_sin_theta) * inv_PH; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX; + XLimitR += updateX; + xL += updateX; + xR += updateX; + + // for each affected col + for (row = x1L; row <= x1R; ++row) { + + if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V) res = 1.0f; + else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T; + else if (x2R >= T) res = x2R; + else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S) {} // - 0.0f + else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T; + else if (x2L <= U) res -= x2L; + else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end row loop + + } // end col loop + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + + } // end detector loop + + } // end theta switch +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CParallelBeamStripKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) return; + + // Some variables + float32 theta, t; + int row, col; + float32 res; + float32 PL, PLimitL, PLimitR; + float32 xL, xR, XLimitL, XLimitR; + int x1L,x1R; + float32 x2L, x2R, updateX; + int iVolumeIndex; + + float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta; + float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta; + float32 PW, PH, DW, inv_PW, inv_PH; + float32 S, T, U, V, inv_4T; + + // get values + theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); + bool switch_t = false; + if (theta >= 7*PIdiv4) theta -= 2*PI; + if (theta >= 3*PIdiv4) { + theta -= PI; + switch_t = true; + } + + // Precalculate sin, cos, 1/cos + sin_theta = sin(theta); + cos_theta = cos(theta); + inv_cos_theta = 1.0f / cos_theta; + inv_sin_theta = 1.0f / sin_theta; + + fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta; + fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta; + fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta; + fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta; + + // Other precalculations + PW = m_pVolumeGeometry->getPixelLengthX(); + PH = m_pVolumeGeometry->getPixelLengthY(); + DW = m_pProjectionGeometry->getDetectorWidth(); + inv_PW = 1.0f / PW; + inv_PH = 1.0f / PH; + + // [-45?,45?] and [135?,225?] + if (theta < PIdiv4) { + + // Precalculate kernel limits + S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta; + T = -S; + U = 1.0f + S; + V = 1.0f - S; + inv_4T = 0.25f / T; + + updateX = sin_theta * inv_cos_theta; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector); + if (switch_t) t = -t; + + // calculate left strip extremes (volume coordinates) + PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta; + PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH; + PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta; + + // calculate strip extremes (pixel coordinates) + XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW; + xR = xL + (DW * inv_cos_theta) * inv_PW; + + // for each row + for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX; + XLimitR += updateX; + xL += updateX; + xR += updateX; + + // for each affected col + for (col = x1L; col <= x1R; ++col) { + + if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V) res = 1.0f; + else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T; + else if (x2R >= T) res = x2R; + else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S) {} // - 0.0f + else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T; + else if (x2L <= U) res -= x2L; + else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end col loop + + } // end row loop + + // [45?,135?] and [225?,315?] + // horizontaly + } else { + + // Precalculate kernel limits + S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta; + T = -S; + U = 1.0f + S; + V = 1.0f - S; + inv_4T = 0.25f / T; + + updateX = cos_theta * inv_sin_theta; + + // get t + t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector); + if (switch_t) t = -t; + + // calculate left strip extremes (volume coordinates) + PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta; + PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW; + PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta; + + // calculate strip extremes (pixel coordinates) + XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH; + XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH; + xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH; + xR = xL + (DW * fabs_inv_sin_theta) * inv_PH; + + // for each col + for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { + + // get strip extremes in column indices + x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f); + x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f); + + // get coords w.r.t leftmost column hit by strip + x2L = xL - x1L; + x2R = xR - x1L; + + // update strip extremes for the next row + XLimitL += updateX; + XLimitR += updateX; + xL += updateX; + xR += updateX; + + // for each affected col + for (row = x1L; row <= x1R; ++row) { + + if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); + + // POLICY: PIXEL PRIOR + if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // right + if (x2R >= V) res = 1.0f; + else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T; + else if (x2R >= T) res = x2R; + else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // left + if (x2L <= S) {} // - 0.0f + else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T; + else if (x2L <= U) res -= x2L; + else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T; + else { x2L -= 1.0f; x2R -= 1.0f; continue; } + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + + x2L -= 1.0f; + x2R -= 1.0f; + + } // end row loop + + } // end col loop + + } // end theta switch + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); + +} diff --git a/include/astra/ParallelProjectionGeometry2D.h b/include/astra/ParallelProjectionGeometry2D.h new file mode 100644 index 0000000..c91fb4d --- /dev/null +++ b/include/astra/ParallelProjectionGeometry2D.h @@ -0,0 +1,153 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELPROJECTIONGEOMETRY2D +#define _INC_ASTRA_PARALLELPROJECTIONGEOMETRY2D + +#include "ProjectionGeometry2D.h" + +namespace astra +{ + +/** + * This class defines a 2D parallel beam projection geometry. + * + * <img src="../images/par_proj_geom.svg" width="600"/> + * This geometry is defined by a number of parameters: + * - The number of detectors (DetCount). + * The distance between the first detector and the projection of the origin \f$O\f$ is equal to + * the distance between the last detector and the projection of \f$O\f$. + * - The width of each detector (detector width). All detectors are equidistant. + * - A list of projection angles (\f$\theta\f$), measured w.r.t. the y-axis of the volume. In Radians. Should lie in the interval \f$[-\frac{\pi}{4},\frac{7\pi}{4}]\f$. + * + * This class provides functionality to convert between detector index and detector offset \f$t\f$. + * + * \par XML Configuration + * \astra_xml_item{DetectorCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorWidth, float, Width of each detector.} + * \astra_xml_item{ProjectionAngles, vector of float, projection angles w.r.t. the y-axis of the volume in radians.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('parallel');\n + * proj_geom.DetectorCount = 512;\n + * proj_geom.DetectorWidth = 1.0;\n + * proj_geom.ProjectionAngles = linspace(0\,pi\,100);\n + * } + */ +class _AstraExport CParallelProjectionGeometry2D : public CProjectionGeometry2D +{ +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CParallelProjectionGeometry2D(); + + /** Constructor. Create an instance of the CParallelProjectionGeometry2D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + CParallelProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets = 0); + + /** Copy constructor. + */ + CParallelProjectionGeometry2D(const CParallelProjectionGeometry2D& _projGeom); + + /** Destructor. + */ + ~CParallelProjectionGeometry2D(); + + /** Assignment operator. + */ + CParallelProjectionGeometry2D& operator=(const CParallelProjectionGeometry2D& _other); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialization. Initializes an instance of the CProjectionGeometry2D class. If the object has been + * initialized before, the object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets = 0); + + /** Create a hard copy. + */ + virtual CProjectionGeometry2D* clone(); + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(CProjectionGeometry2D*) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "parallel". + */ + virtual bool isOfType(const std::string& _sType); + + /** + * Returns a vector describing the direction of a ray belonging to a certain detector, + * the direction is the same for all detectors in one projection + * + * @param _iProjectionIndex index of projection + * @param _iProjectionIndex index of detector + * + * @return a unit vector describing the direction + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex = 0); +}; + +} // namespace astra + +#endif /* _INC_ASTRA_PARALLELPROJECTIONGEOMETRY2D */ diff --git a/include/astra/ParallelProjectionGeometry3D.h b/include/astra/ParallelProjectionGeometry3D.h new file mode 100644 index 0000000..85d0687 --- /dev/null +++ b/include/astra/ParallelProjectionGeometry3D.h @@ -0,0 +1,165 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D +#define _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D + +#include "ProjectionGeometry3D.h" +#include "ParallelProjectionGeometry2D.h" + +namespace astra +{ + +/** + * This class defines a 3D parallel beam projection geometry. + * + * \par XML Configuration + * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorWidth, float, Width of each detector.} + * \astra_xml_item{DetectorHeight, float, Width of each detector.} + * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('parallel');\n + * proj_geom.DetectorRowCount = 512;\n + * proj_geom.DetectorColCount = 512;\n + * proj_geom.DetectorWidth = 1.0;\n + * proj_geom.DetectorHeight = 1.0;\n + * proj_geom.ProjectionAngles = linspace(0,pi,100);\n + * } + */ +class _AstraExport CParallelProjectionGeometry3D : public CProjectionGeometry3D +{ +protected: + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling initialize() + * is not allowed, except calling the member function isInitialized(). + */ + CParallelProjectionGeometry3D(); + + /** Constructor. Create an instance of the CParallelProjectionGeometry3D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles + * are represented in radians and lie in the [0,2pi[ interval. + */ + CParallelProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX = NULL, + const float32* _pfExtraDetectorOffsetsY = NULL); + + /** Copy constructor. + */ + CParallelProjectionGeometry3D(const CParallelProjectionGeometry3D& _projGeom); + + /** Destructor. + */ + ~CParallelProjectionGeometry3D(); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the geometry. If the object has been initialized before, the object is reinitialized + * and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal height. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles + * are represented in radians and lie in the [0,2pi[ interval. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX = NULL, + const float32* _pfExtraDetectorOffsetsY = NULL); + + /** Create a hard copy. + */ + virtual CProjectionGeometry3D* clone() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(const CProjectionGeometry3D*) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "parallel". + */ + virtual bool isOfType(const std::string& _sType) const; + + /** Turn this object into an XML object. + * + * @param _sNode The XML object to fill. + */ + virtual void toXML(XMLNode* _sNode) const; + + /** + * Returns a vector giving the projection direction for a projection and detector index + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const; + + /** + * Creates (= allocates) a 2D projection geometry used when projecting one slice using a 2D projector + * + * @return the 2D geometry, this pointer needs to be delete-ed after use. + */ + CParallelProjectionGeometry2D * createProjectionGeometry2D() const; + +}; + +} // namespace astra + +#endif /* _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D */ diff --git a/include/astra/ParallelVecProjectionGeometry3D.h b/include/astra/ParallelVecProjectionGeometry3D.h new file mode 100644 index 0000000..0b4a766 --- /dev/null +++ b/include/astra/ParallelVecProjectionGeometry3D.h @@ -0,0 +1,157 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PARALLELVECPROJECTIONGEOMETRY3D +#define _INC_ASTRA_PARALLELVECPROJECTIONGEOMETRY3D + +#include "ProjectionGeometry3D.h" +#include "../cuda/3d/dims3d.h" + +namespace astra +{ + +/** + * This class defines a 3D parallel beam projection geometry. + * + * \par XML Configuration + * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.} + * + * \par MATLAB example + * \astra_code{ + * proj_geom = astra_struct('parallel3d_vec');\n + * proj_geom.DetectorRowCount = 512;\n + * proj_geom.DetectorColCount = 512;\n + * proj_geom.Vectors = V;\n + * } + * + * \par Vectors + * Vectors is a matrix containing the actual geometry. Each row corresponds + * to a single projection, and consists of: + * ( rayX, rayY, rayZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ ) + * ray: the ray direction + * d : the corner of the detector + * u : the vector from detector pixel (0,0) to (0,1) + * v : the vector from detector pixel (0,0) to (1,0) + */ +class _AstraExport CParallelVecProjectionGeometry3D : public CProjectionGeometry3D +{ +protected: + + SPar3DProjection *m_pProjectionAngles; + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling initialize() + * is not allowed, except calling the member function isInitialized(). + */ + CParallelVecProjectionGeometry3D(); + + /** Constructor. Create an instance of the CParallelProjectionGeometry3D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _pProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + CParallelVecProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SPar3DProjection* _pProjectionAngles); + + /** Copy constructor. + */ + CParallelVecProjectionGeometry3D(const CParallelVecProjectionGeometry3D& _projGeom); + + /** Destructor. + */ + ~CParallelVecProjectionGeometry3D(); + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the geometry. If the object has been initialized before, the object is reinitialized + * and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _pProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SPar3DProjection* _pProjectionAngles); + + + virtual bool _check(); + + /** Create a hard copy. + */ + virtual CProjectionGeometry3D* clone() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(const CProjectionGeometry3D*) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "parallel3d_vec". + */ + virtual bool isOfType(const std::string& _sType) const; + + /** Turn this object into an XML object. + * + * @param _sNode The XML object to fill. + */ + virtual void toXML(XMLNode* _sNode) const; + + /** + * Returns a vector giving the projection direction for a projection and detector index + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const; + + + const SPar3DProjection* getProjectionVectors() const { return m_pProjectionAngles; } + + +}; + +} // namespace astra + +#endif /* _INC_ASTRA_PARALLELVECPROJECTIONGEOMETRY3D */ diff --git a/include/astra/PlatformDepSystemCode.h b/include/astra/PlatformDepSystemCode.h new file mode 100644 index 0000000..1e254b4 --- /dev/null +++ b/include/astra/PlatformDepSystemCode.h @@ -0,0 +1,83 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef PLATFORMDEPSYSTEMCODE_H +#define PLATFORMDEPSYSTEMCODE_H + +#include <cstdio> + +#ifndef _WIN32 +#include <stdint.h> +#endif + +namespace astra +{ + +#ifdef _WIN32 + typedef __int64 int64; +#else + typedef int64_t int64; +#endif + +class CPlatformDepSystemCode +{ +public: + + /** + * Clock with resolution of 1 ms. Windows implementation will return number of ms since system start, + * but this is not a requirement for the implementation. Just as long as the subtraction of two acquired + * values will result in a time interval in ms. + * + * @return a value that increases with 1 every ms + */ + static unsigned long getMSCount(); + + /** + * fseek variant that works with 64 bit ints. + * + * @param _pStream file handler of file in which needs to be seek-ed + * @param _iOffset 64 bit int telling the new offset in the file + * @param _iOrigin typical fseek directive telling how _iOffset needs to be interpreted (SEEK_SET, ...) + * + * @return 0 if successful + */ + static int fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin); + + /** + * 64-bit ftell variant + * + * @param _pStream file handle + * + * @return the position in the file + */ + static astra::int64 ftell64(FILE * _pStream); +}; + +} + +#endif /* PLATFORMDEPSYSTEMCODE_H */ diff --git a/include/astra/ProjectionGeometry2D.h b/include/astra/ProjectionGeometry2D.h new file mode 100644 index 0000000..bcaee7a --- /dev/null +++ b/include/astra/ProjectionGeometry2D.h @@ -0,0 +1,373 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PROJECTIONGEOMETRY2D +#define _INC_ASTRA_PROJECTIONGEOMETRY2D + +#include "Globals.h" +#include "Config.h" +#include "Vector3D.h" + +#include <string> +#include <cmath> +#include <vector> + +namespace astra +{ + +/** + * This abstract base class defines the projection geometry. + * It has a number of data fields, such as width of detector + * pixels, projection angles, number of detector pixels and object offsets + * for every projection angle. + */ +class _AstraExport CProjectionGeometry2D +{ + +protected: + + bool m_bInitialized; ///< Has the object been intialized? + + /** Number of projection angles + */ + int m_iProjectionAngleCount; + + /** Number of detectors, i.e., the number of detector measurements for each projection angle. + */ + int m_iDetectorCount; + + /** Width of a detector pixel, i.e., the distance between projected rays (or width of projected strips). + */ + float32 m_fDetectorWidth; + + /** An array of m_iProjectionAngleCount elements containing an extra detector offset for each projection. + */ + float32* m_pfExtraDetectorOffset; + + /** Dynamically allocated array of projection angles. All angles are represented in radians and lie in + * the [0,2pi[ interval. + */ + float32* m_pfProjectionAngles; + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not + * allowed, except calling the member function isInitialized(). + * + */ + CProjectionGeometry2D(); + + /** Constructor. Create an instance of the CProjectionGeometry2D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + * All angles are represented in radians. + */ + CProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets = 0); + + /** Copy constructor. + */ + CProjectionGeometry2D(const CProjectionGeometry2D& _projGeom); + + /** Check variable values. + */ + bool _check(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + * Should only be used by constructors. Otherwise use the clear() function. + */ + void _clear(); + + /** Initialization. Initializes an instance of the CProjectionGeometry2D class. If the object has been + * initialized before, the object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. + */ + bool _initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets = 0); + +public: + + /** Destructor + */ + virtual ~CProjectionGeometry2D(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + virtual void clear(); + + /** Create a hard copy. + */ + virtual CProjectionGeometry2D* clone() = 0; + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Get the initialization state of the object. + * + * @return true iff the object has been initialized + */ + bool isInitialized() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(CProjectionGeometry2D*) const = 0; + + /** Get the number of projection angles. + * + * @return Number of projection angles + */ + int getProjectionAngleCount() const; + + /** Get the number of detectors. + * + * @return Number of detectors, i.e., the number of detector measurements for each projection angle. + */ + int getDetectorCount() const; + + /** Get the width of a detector. + * + * @return Width of a detector, in unit lengths + */ + float32 getDetectorWidth() const; + + /** Get a projection angle, given by its index. The angle is represented in Radians. + * + * @return Projection angle with index _iProjectionIndex + */ + float32 getProjectionAngle(int _iProjectionIndex) const; + + /** Returns a buffer containing all projection angles. The element count of the buffer is equal + * to the number given by getProjectionAngleCount. + * + * The angles are in radians. + * + * @return Pointer to buffer containing the angles. + */ + const float32* getProjectionAngles() const; + + /** Get a projection angle, given by its index. The angle is represented in degrees. + * + * @return Projection angle with index _iProjectionIndex + */ + float32 getProjectionAngleDegrees(int _iProjectionIndex) const; + + float32 getExtraDetectorOffset(int iAngle) const; + const float32* getExtraDetectorOffset() const { return m_pfExtraDetectorOffset; } + + /** Get the index coordinate of a point on a detector array. + * + * @param _fOffset distance between the center of the detector array and a certain point + * @return the location of the point in index coordinates (still float, not rounded) + */ + virtual float32 detectorOffsetToIndexFloat(float32 _fOffset) const; + + /** Get the index coordinate of a point on a detector array. + * + * @param _fOffset distance between the center of the detector array and a certain point + * @return the index of the detector that is hit, -1 if detector array isn't hit. + */ + virtual int detectorOffsetToIndex(float32 _fOffset) const; + + /** Get the offset of a detector based on its index coordinate. + * + * @param _iIndex the index of the detector. + * @return the offset from the center of the detector array. + */ + virtual float32 indexToDetectorOffset(int _iIndex) const; + + /** Get the angle and detector index of a sinogram pixel + * + * @param _iIndex the index of the detector pixel in the sinogram. + * @param _iAngleIndex output: index of angle + * @param _iDetectorIndex output: index of detector + */ + virtual void indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const; + + /** Get the value for t and theta, based upon the row and column index. + * + * @param _iRow row index + * @param _iColumn column index + * @param _fT output: value of t + * @param _fTheta output: value of theta, always lies within the [0,pi[ interval. + */ + virtual void getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if the type of geometry defined in this class is the one specified in _sType. + */ + virtual bool isOfType(const std::string& _sType) = 0; + + /** + * Returns a vector describing the direction of a ray belonging to a certain detector + * + * @param _iProjectionIndex index of projection + * @param _iProjectionIndex index of detector + * + * @return a unit vector describing the direction + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) = 0; + + + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CProjectionGeometry2D>; +}; + + + +//---------------------------------------------------------------------------------------- +// Inline member functions +//---------------------------------------------------------------------------------------- + + +inline float32 CProjectionGeometry2D::getExtraDetectorOffset(int _iAngle) const +{ + return m_pfExtraDetectorOffset ? m_pfExtraDetectorOffset[_iAngle] : 0.0f; +} + + +// Get the initialization state. +inline bool CProjectionGeometry2D::isInitialized() const +{ + return m_bInitialized; +} + + +// Get the number of detectors. +inline int CProjectionGeometry2D::getDetectorCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iDetectorCount; +} + +// Get the width of a single detector (in unit lengths). +inline float32 CProjectionGeometry2D::getDetectorWidth() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fDetectorWidth; +} + +// Get the number of projection angles. +inline int CProjectionGeometry2D::getProjectionAngleCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iProjectionAngleCount; +} + +// Get pointer to buffer used to store projection angles. +inline const float32* CProjectionGeometry2D::getProjectionAngles() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_pfProjectionAngles; +} + +// Get a projection angle, represented in Radians. +inline float32 CProjectionGeometry2D::getProjectionAngle(int _iProjectionIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iProjectionIndex >= 0); + ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount); + + return m_pfProjectionAngles[_iProjectionIndex]; +} + +// Get a projection angle, represented in degrees. +inline float32 CProjectionGeometry2D::getProjectionAngleDegrees(int _iProjectionIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iProjectionIndex >= 0); + ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount); + + return (m_pfProjectionAngles[_iProjectionIndex] * 180.0f / PI32); +} + +// Get T and Theta +inline void CProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const +{ + ASTRA_ASSERT(m_bInitialized); + _fT = indexToDetectorOffset(_iColumn); + _fTheta = getProjectionAngle(_iRow); + if (PI <= _fTheta) { + _fTheta -= PI; + _fT = -_fT; + } +} + +// detector offset -> detector index +inline int CProjectionGeometry2D::detectorOffsetToIndex(float32 _fOffset) const +{ + int res = (int)(detectorOffsetToIndexFloat(_fOffset) + 0.5f); + return (res > 0 && res <= m_iDetectorCount) ? res : -1; +} + +// detector offset -> detector index (float) +inline float32 CProjectionGeometry2D::detectorOffsetToIndexFloat(float32 _fOffset) const +{ + return (_fOffset / m_fDetectorWidth) + ((m_iDetectorCount-1.0f) * 0.5f); +} + +// detector index -> detector offset +inline float32 CProjectionGeometry2D::indexToDetectorOffset(int _iIndex) const +{ + return (_iIndex - (m_iDetectorCount-1.0f) * 0.5f) * m_fDetectorWidth; +} + +// sinogram index -> angle and detecor index +inline void CProjectionGeometry2D::indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const +{ + _iAngleIndex = _iIndex / m_iDetectorCount; + _iDetectorIndex = _iIndex % m_iDetectorCount; +} + +} // end namespace astra + +#endif /* _INC_ASTRA_PROJECTIONGEOMETRY2D */ diff --git a/include/astra/ProjectionGeometry3D.h b/include/astra/ProjectionGeometry3D.h new file mode 100644 index 0000000..0deffa6 --- /dev/null +++ b/include/astra/ProjectionGeometry3D.h @@ -0,0 +1,589 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PROJECTIONGEOMETRY3D +#define _INC_ASTRA_PROJECTIONGEOMETRY3D + +#include "Globals.h" +#include "Config.h" +#include "Vector3D.h" + +#include <string> +#include <cmath> +#include <vector> + +namespace astra +{ + +class XMLNode; + +/** + * This class defines the interface for each 3D projection geometry. + * It has a number of data fields, such as width and height of detector + * pixels, projection angles and number of rows and columns of detector pixels. + * + * \par XML Configuration + * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.} + * \astra_xml_item{DetectorWidth, float, Width of each detector.} + * \astra_xml_item{DetectorHeight, float, Width of each detector.} + * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.} + */ +class _AstraExport CProjectionGeometry3D +{ + +protected: + + /** Has the object been intialized with acceptable values? + */ + bool m_bInitialized; + + /** Number of projection angles. + */ + int m_iProjectionAngleCount; + + /** Number of rows of detectors. + */ + int m_iDetectorRowCount; + + /** Number of columns of detectors. + */ + int m_iDetectorColCount; + + /** Total number of detectors. + */ + int m_iDetectorTotCount; + + /** The x-distance between projected rays on the detector plate (or width of projected strips). + */ + float32 m_fDetectorSpacingX; + + /** The y-distance between projected rays on the detector plate (or height of projected strips). + */ + float32 m_fDetectorSpacingY; + + /** Dynamically allocated array of projection angles. All angles are represented in radians and lie in + * the [0,2pi[ interval. + */ + float32* m_pfProjectionAngles; + + /** Dynamically allocated array of vectors that represents the amount by which an image has been shifted after + * projection. Each projection image has a 2 shifts associated with it, one x-translation and y-translation + */ + float32* m_pfExtraDetectorOffsetsX; + float32* m_pfExtraDetectorOffsetsY; + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the initialize() methods before the object can be used. Any use before calling initialize() + * is not allowed, except calling the member function isInitialized(). + * + */ + CProjectionGeometry3D(); + + /** Constructor. Create an instance of the CProjectionGeometry3D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _fDetectorSpacingX Spacing between the detector points on the X-axis, in unit lengths. Assumed to be constant throughout the entire detector plate. + * @param _fDetectorSpacingY Spacing between the detector points on the Y-axis, in unit lengths. Assumed to be constant throughout the entire detector plate. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles + * are represented in radians and lie in the [0,2pi[ interval. + */ + CProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorSpacingX, + float32 _fDetectorSpacingY, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX = NULL, + const float32* _pfExtraDetectorOffsetsY = NULL); + + /** Copy constructor. + */ + CProjectionGeometry3D(const CProjectionGeometry3D& _projGeom); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - number of rows and columns is larger than zero + * - detector spacing is larger than zero + * - number of angles is larger than zero + * - (autofix) each angle lies in [0,2pi[ + */ + bool _check(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + * Should only be used by constructors. Otherwise use the clear() function. + */ + void _clear(); + + /** Initialize the geometry. If the object has been initialized before, the object is reinitialized + * and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorRowCount Number of rows of detectors. + * @param _iDetectorColCount Number of columns detectors. + * @param _fDetectorSpacingX Spacing between the detector points on the X-axis, in unit lengths. Assumed to be constant throughout the entire detector plate. + * @param _fDetectorSpacingY Spacing between the detector points on the Y-axis, in unit lengths. Assumed to be constant throughout the entire detector plate. + * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles + * are represented in radians and lie in the [0,2pi[ interval. + */ + bool _initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorSpacingX, + float32 _fDetectorSpacingY, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX = NULL, + const float32* _pfExtraDetectorOffsetsY = NULL); + +public: + + /** Destructor + */ + virtual ~CProjectionGeometry3D(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + virtual void clear(); + + /** Create a hard copy. + */ + virtual CProjectionGeometry3D* clone() const = 0; + + /** Initialize the geometry with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Get the initialization state of the object. + * + * @return true iff the object has been initialized + */ + bool isInitialized() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(const CProjectionGeometry3D *) const = 0; + + /** Get the number of projections. + * + * @return Number of projections + */ + int getProjectionCount() const; + + /** Get the number of rows of detectors. + * + * @return Number of rows of detectors. + */ + int getDetectorRowCount() const; + + /** Get the number of columns of detectors. + * + * @return Number of columns of detectors. + */ + int getDetectorColCount() const; + + /** Get the total number of detectors. + * + * @return Total number of detectors. + */ + int getDetectorTotCount() const; + + /** Get the width of a detector. + * + * @return Width of a detector, in unit lengths + */ + float32 getDetectorSpacingX() const; + + /** Get the height of a detector. + * + * @return Height of a detector, in unit lengths + */ + float32 getDetectorSpacingY() const; + + /** Get a projection angle, given by its index. The angle is represented in Radians. + * + * @return Projection angle with index _iProjectionIndex + */ + float32 getProjectionAngle(int _iProjectionIndex) const; + + /** Get a projection angle, given by its index. The angle is represented in degrees. + * + * @return Projection angle with index _iProjectionIndex + */ +// float32 getProjectionAngleDegrees(int _iProjectionIndex) const; + + /** Returns a buffer containing all projection angles. The element count of the buffer is equal + * to the number given by getProjectionAngleCount. + * + * The angles are in radians. + * + * @return Pointer to buffer containing the angles. + */ + const float32* getProjectionAngles() const; + + const float32* getExtraDetectorOffsetsX() const; + + const float32* getExtraDetectorOffsetsY() const; + + float32 getExtraDetectorOffsetX(int _iProjectionIndex) const; + + float32 getExtraDetectorOffsetY(int _iProjectionIndex) const; + + AstraError setExtraDetectorOffsetsX(float32* _pfExtraDetectorOffsetsX); + + AstraError setExtraDetectorOffsetsY(float32* _pfExtraDetectorOffsetsY); + + /** Get the column index coordinate of a point on a detector array. + * + * @param _fOffsetX Distance between the center of the detector array and a certain point (both on the X-axis). + * @return The location of the point in index X-coordinates (still float, not rounded) + */ + virtual float32 detectorOffsetXToColIndexFloat(float32 _fOffsetX) const; + + /** Get the row index coordinate of a point on a detector array. + * + * @param _fOffsetY Distance between the center of the detector array and a certain point (both on the Y-axis). + * @return The location of the point in index Y-coordinates (still float, not rounded) + */ + virtual float32 detectorOffsetYToRowIndexFloat(float32 _fOffsetY) const; + + /** Get the offset of a detector on the X-axis based on its index coordinate. + * + * @param _iIndex the index of the detector. + * @return the offset from the center of the detector array on the X-axis. + */ + virtual float32 indexToDetectorOffsetX(int _iIndex) const; + + /** Get the offset of a detector on the Y-axis based on its index coordinate. + * + * @param _iIndex the index of the detector. + * @return the offset from the center of the detector array on the Y-axis. + */ + virtual float32 indexToDetectorOffsetY(int _iIndex) const; + + /** Get the offset of a detector on the X-axis based on its column index coordinate. + * + * @param _iIndex the index of the detector. + * @return the offset from the center of the detector array on the X-axis. + */ + virtual float32 colIndexToDetectorOffsetX(int _iIndex) const; + + /** Get the offset of a detector on the Y-axis based on its row index coordinate. + * + * @param _iIndex the index of the detector. + * @return the offset from the center of the detector array on the Y-axis. + */ + virtual float32 rowIndexToDetectorOffsetY(int _iIndex) const; + + /** Get the row and column index of a detector based on its index. + * + * @param _iDetectorIndex in: the index of the detector. + * @param _iDetectorRow out: the row index of the detector. + * @param _iDetectorCol out: the column index of the detector. + */ + virtual void detectorIndexToRowCol(int _iDetectorIndex, int& _iDetectorRow, int& _iDetectorCol) const; + + /** Get the angle and detector index of a detector + * + * @param _iIndex the index of the detector. + * @param _iAngleIndex output: index of angle + * @param _iDetectorIndex output: index of dectecor + */ + virtual void indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if the type of geometry defined in this class is the one specified in _sType. + */ + virtual bool isOfType(const std::string& _sType) const = 0; + + /** Turn this object into an XML object. + * + * @param _sNode The XML object to fill. + */ + virtual void toXML(XMLNode* _sNode) const = 0; + + /** + * Returns a vector giving the projection direction for a projection and detector index + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const = 0; + + + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CProjectionGeometry3D>; +}; + + + +//---------------------------------------------------------------------------------------- +// Inline member functions +//---------------------------------------------------------------------------------------- +// Get the initialization state. +inline bool CProjectionGeometry3D::isInitialized() const +{ + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CProjectionGeometry3D::getDetectorRowCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iDetectorRowCount; +} + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CProjectionGeometry3D::getDetectorColCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iDetectorColCount; +} + +//---------------------------------------------------------------------------------------- +// Get the number of detectors. +inline int CProjectionGeometry3D::getDetectorTotCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iDetectorTotCount; +} + +//---------------------------------------------------------------------------------------- +// Get the width of a single detector (in unit lengths). +inline float32 CProjectionGeometry3D::getDetectorSpacingX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fDetectorSpacingX; +} +//---------------------------------------------------------------------------------------- +// Get the width of a single detector (in unit lengths). +inline float32 CProjectionGeometry3D::getDetectorSpacingY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fDetectorSpacingY; +} + +//---------------------------------------------------------------------------------------- +// Get the number of projection angles. +inline int CProjectionGeometry3D::getProjectionCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iProjectionAngleCount; +} + +//---------------------------------------------------------------------------------------- +// Get a projection angle, represented in Radians. +inline float32 CProjectionGeometry3D::getProjectionAngle(int _iProjectionIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iProjectionIndex >= 0); + ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount); + + return m_pfProjectionAngles[_iProjectionIndex]; +} + +/* +//---------------------------------------------------------------------------------------- +// Get a projection angle, represented in degrees. +inline float32 CProjectionGeometry3D::getProjectionAngleDegrees(int _iProjectionIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iProjectionIndex >= 0); + ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount); + + return (m_pfProjectionAngles[_iProjectionIndex] * 180.0f / PI32); +} +*/ + + +//---------------------------------------------------------------------------------------- +// Get pointer to buffer used to store projection angles. +inline const float32* CProjectionGeometry3D::getProjectionAngles() const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return m_pfProjectionAngles; +} + + +//---------------------------------------------------------------------------------------- +// Get pointer to buffer used to store x-translations of the projection images. +inline const float32* CProjectionGeometry3D::getExtraDetectorOffsetsX() const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return m_pfExtraDetectorOffsetsX; +} + +//---------------------------------------------------------------------------------------- +// Get pointer to buffer used to store y-translations of the projection images. +inline const float32* CProjectionGeometry3D::getExtraDetectorOffsetsY() const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return m_pfExtraDetectorOffsetsY; +} +//---------------------------------------------------------------------------------------- +// Get the x-translation of a specific projection image. +inline float32 CProjectionGeometry3D::getExtraDetectorOffsetX(int _iProjectionIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return m_pfExtraDetectorOffsetsX[_iProjectionIndex]; +} + +//---------------------------------------------------------------------------------------- +// Get the y-translation of a specific projection image. +inline float32 CProjectionGeometry3D::getExtraDetectorOffsetY(int _iProjectionIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return m_pfExtraDetectorOffsetsX[_iProjectionIndex]; +} +//---------------------------------------------------------------------------------------- +// detector offset X -> detector column index (float) +inline float32 CProjectionGeometry3D::detectorOffsetXToColIndexFloat(float32 _fOffsetX) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return (_fOffsetX / m_fDetectorSpacingX) + ((m_iDetectorColCount-1.0f) / 2.0f); +} + +//---------------------------------------------------------------------------------------- +// detector offset Y -> detector row index (float) +inline float32 CProjectionGeometry3D::detectorOffsetYToRowIndexFloat(float32 _fOffsetY) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + + return (_fOffsetY / m_fDetectorSpacingY) + ((m_iDetectorRowCount-1.0f) / 2.0f); +} + +//---------------------------------------------------------------------------------------- +// detector index -> detector offset X +inline float32 CProjectionGeometry3D::indexToDetectorOffsetX(int _iIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iIndex >= 0); + ASTRA_ASSERT(_iIndex < m_iDetectorTotCount); + + _iIndex = _iIndex % m_iDetectorColCount; + return (_iIndex - (m_iDetectorColCount-1.0f) / 2.0f) * m_fDetectorSpacingX; +} + +//---------------------------------------------------------------------------------------- +// detector index -> detector offset Y +inline float32 CProjectionGeometry3D::indexToDetectorOffsetY(int _iIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iIndex >= 0); + ASTRA_ASSERT(_iIndex < m_iDetectorTotCount); + + _iIndex = _iIndex / m_iDetectorColCount; + return -(_iIndex - (m_iDetectorRowCount-1.0f) / 2.0f) * m_fDetectorSpacingY; +} + +//---------------------------------------------------------------------------------------- +// detector index -> detector offset X +inline float32 CProjectionGeometry3D::colIndexToDetectorOffsetX(int _iIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iIndex >= 0); + ASTRA_ASSERT(_iIndex < m_iDetectorColCount); + + return (_iIndex - (m_iDetectorColCount-1.0f) / 2.0f) * m_fDetectorSpacingX; +} + +//---------------------------------------------------------------------------------------- +// detector index -> detector offset Y +inline float32 CProjectionGeometry3D::rowIndexToDetectorOffsetY(int _iIndex) const +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iIndex >= 0); + ASTRA_ASSERT(_iIndex < m_iDetectorRowCount); + + return (_iIndex - (m_iDetectorRowCount-1.0f) / 2.0f) * m_fDetectorSpacingY; +} + +//---------------------------------------------------------------------------------------- +// detector index -> row index & column index +inline void CProjectionGeometry3D::detectorIndexToRowCol(int _iDetectorIndex, int& _iDetectorRow, int& _iDetectorCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iDetectorIndex >= 0); + ASTRA_ASSERT(_iDetectorIndex < m_iDetectorTotCount); + + _iDetectorRow = _iDetectorIndex / m_iDetectorColCount; + _iDetectorCol = _iDetectorIndex % m_iDetectorColCount; +} + +//---------------------------------------------------------------------------------------- +inline void CProjectionGeometry3D::indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iIndex >= 0); + ASTRA_ASSERT(_iIndex < m_iDetectorTotCount * m_iProjectionAngleCount); + +// int det_row = _iIndex / (m_iDetectorColCount*m_iProjectionAngleCount); +// int det_col = _iIndex % m_iDetectorColCount; +// +// _iAngleIndex = _iIndex % (m_iDetectorColCount*m_iProjectionAngleCount) / m_iDetectorColCount; +// _iDetectorIndex = det_row * m_iDetectorColCount + det_col; + + _iAngleIndex = (_iIndex % (m_iDetectorColCount*m_iProjectionAngleCount)) / m_iDetectorColCount; + _iDetectorIndex = _iIndex / m_iProjectionAngleCount + (_iIndex % m_iDetectorColCount); + +} + +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif /* _INC_ASTRA_PROJECTIONGEOMETRY2D */ diff --git a/include/astra/Projector2D.h b/include/astra/Projector2D.h new file mode 100644 index 0000000..a359aba --- /dev/null +++ b/include/astra/Projector2D.h @@ -0,0 +1,204 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef INC_ASTRA_PROJECTOR2D +#define INC_ASTRA_PROJECTOR2D + +#include <cmath> +#include <vector> + +#include "Globals.h" +#include "Config.h" +#include "Float32Data2D.h" +#include "ParallelProjectionGeometry2D.h" +#include "ProjectionGeometry2D.h" +#include "VolumeGeometry2D.h" + +namespace astra +{ + +class CSparseMatrix; + + +/** This is a base interface class for a two-dimensional projector. Each subclass should at least + * implement the core projection functions computeProjectionRayWeights and projectPoint. For + * extra efficiency one might also like to overwrite other functions such as computeProjectionRayWeights, + * computeRayForwardProj_ART, ... + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + */ +class _AstraExport CProjector2D +{ + +protected: + CProjectionGeometry2D* m_pProjectionGeometry; ///< Used projection geometry + CVolumeGeometry2D* m_pVolumeGeometry; ///< Used volume geometry + bool m_bIsInitialized; ///< Has this class been initialized? + + /** Default Constructor. + */ + CProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pVolumeGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CProjector2D(CProjectionGeometry2D* _pProjectionGeometry, CVolumeGeometry2D* _pVolumeGeometry); + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + */ + virtual bool _check(); + +public: + + /** Destructor. + */ + virtual ~CProjector2D(); + + /** Clear this class. + */ + virtual void clear(); + + /** Initialize the projector with a config object. + * This function does not set m_bInitialized to true. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Fetch the Projection Geometry of this projector. + * + * @return Projection Geometry class. + */ + CProjectionGeometry2D* getProjectionGeometry(); + + /** Fetch the Volume Geometry of this projector. + * + * @return Volume Geometry class. + */ + CVolumeGeometry2D* getVolumeGeometry(); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight *_pWeightedPixels, + int _iMaxPixelCount, + int &_iStoredPixelCount) = 0; + + /** Compute the pixel weights for all rays in a single projection, from the source to a each of the + * detector pixels. All pixels and their weights are stored consecutively in the array _pWeightedPixels. + * The array starts with all pixels on the first ray, followed by all pixels on the second ray, the third + * ray, etc. Note that a pixel may occur in the list more than once, as it can be on several rays. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @param _pfWeightedPixels Pointer to a pre-allocated array, consisting of getProjectionWeightsCount() + * elements of type SPixelWeight. On return, this array contains a list of + * the index and weight for all pixels on each of the rays. The elements for + * every ray start at equal offsets (ray_index * _pWeightedPixels / ray_count). + * @param _piRayStoredPixelCount Pointer to a pre-allocated array, containing a single integer for each + * ray in the projection. On return, this array contains the number of + * pixels on the ray, for each ray in the given projection. + */ + virtual void computeProjectionRayWeights(int _iProjectionIndex, + SPixelWeight* _pfWeightedPixels, + int* _piRayStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol) = 0; + + /** Returns the number of weights required for storage of all weights of one projection ray. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex) = 0; + + /** Returns the projection as an explicit sparse matrix. + * @return a newly allocated CSparseMatrix. Delete afterwards. + */ + CSparseMatrix* getMatrix(); + + /** Has the projector been initialized? + * + * @return initialized successfully + */ + bool isInitialized(); + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const {return " ";}; + + virtual std::string getType() { return " "; } + +private: + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CProjector2D>; +}; + +// inline functions +inline bool CProjector2D::isInitialized() { return m_bIsInitialized; } +inline CProjectionGeometry2D* CProjector2D::getProjectionGeometry() { return m_pProjectionGeometry; } +inline CVolumeGeometry2D* CProjector2D::getVolumeGeometry() { return m_pVolumeGeometry; } + + + + + +} // namespace astra + +#endif /* INC_ASTRA_PROJECTOR2D */ diff --git a/include/astra/Projector2DImpl.inl b/include/astra/Projector2DImpl.inl new file mode 100644 index 0000000..97341c8 --- /dev/null +++ b/include/astra/Projector2DImpl.inl @@ -0,0 +1,37 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#include "ParallelBeamLinearKernelProjector2D.inl" +#include "ParallelBeamLineKernelProjector2D.inl" +#include "ParallelBeamStripKernelProjector2D.inl" +#include "ParallelBeamBlobKernelProjector2D.inl" +#include "FanFlatBeamStripKernelProjector2D.inl" +#include "FanFlatBeamLineKernelProjector2D.inl" +#include "SparseMatrixProjector2D.inl" + diff --git a/include/astra/Projector3D.h b/include/astra/Projector3D.h new file mode 100644 index 0000000..ec81bc8 --- /dev/null +++ b/include/astra/Projector3D.h @@ -0,0 +1,185 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef INC_ASTRA_PROJECTOR3D +#define INC_ASTRA_PROJECTOR3D + +#include <cmath> +#include <vector> + +#include "Globals.h" +#include "Config.h" +#include "ProjectionGeometry3D.h" +#include "VolumeGeometry3D.h" + +namespace astra +{ + +class CSparseMatrix; + + +/** This is a base interface class for a three-dimensional projector. Each subclass should at least + * implement the core projection functions computeProjectionRayWeights and projectPoint. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + */ +class _AstraExport CProjector3D +{ + +protected: + + CProjectionGeometry3D* m_pProjectionGeometry; ///< Used projection geometry + CVolumeGeometry3D* m_pVolumeGeometry; ///< Used volume geometry + bool m_bIsInitialized; ///< Has this class been initialized? + + /** Check variable values. + */ + bool _check(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + * Should only be used by constructors. Otherwise use the clear() function. + */ + void _clear(); + +public: + + /** + * Default Constructor. + */ + CProjector3D(); + + /** Destructor, is virtual to show that we are aware subclass destructor is called. + */ + virtual ~CProjector3D(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + void clear(); + + /** Initialize the projector with a config object. + * This function does not set m_bInitialized to true. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Fetch the Projection Geometry of this projector. + * + * @return Projection Geometry class. + */ + CProjectionGeometry3D* getProjectionGeometry(); + + /** Fetch the Volume Geometry of this projector. + * + * @return Volume Geometry class. + */ + CVolumeGeometry3D* getVolumeGeometry(); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection. + * @param _iSliceIndex Index of the detector pixel (1-d index). + * @param _iDetectorIndex Index of the detector pixel (1-d index). + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, int _iSliceIndex, int _iDetectorIndex, SPixelWeight* _pWeightedPixels, int _iMaxPixelCount, int& _iStoredPixelCount) = 0; + + /** Compute the pixel weights for all rays in a single projection, from the source to a each of the + * detector pixels. All pixels and their weights are stored consecutively in the array _pWeightedPixels. + * The array starts with all pixels on the first ray, followed by all pixels on the second ray, the third + * ray, etc. Note that a pixel may occur in the list more than once, as it can be on several rays. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @param _pfWeightedPixels Pointer to a pre-allocated array, consisting of getProjectionWeightsCount() + * elements of type SPixelWeight. On return, this array contains a list of + * the index and weight for all pixels on each of the rays. The elements for + * every ray start at equal offsets (ray_index * _pWeightedPixels / ray_count). + * @param _piRayStoredPixelCount Pointer to a pre-allocated array, containing a single integer for each + * ray in the projection. On return, this array contains the number of + * pixels on the ray, for each ray in the given projection. + */ + virtual void computeProjectionRayWeights(int _iProjectionIndex, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + //virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol) = 0; + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SWeightedPixel3D elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex) = 0; + + /** Has the projector been initialized? + * + * @return initialized successfully + */ + bool isInitialized(); + + /** get a description of the class + * + * @return description string + */ + virtual std::string description() const = 0; + + /** + * Returns a string describing the projector type + */ + virtual std::string getType() = 0; + +private: + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CProjector3D>; + +}; + +// inline functions +inline bool CProjector3D::isInitialized() { return m_bIsInitialized; } +inline CProjectionGeometry3D* CProjector3D::getProjectionGeometry() { return m_pProjectionGeometry; } +inline CVolumeGeometry3D* CProjector3D::getVolumeGeometry() { return m_pVolumeGeometry; } + + + +} // namespace astra + +#endif /* INC_ASTRA_PROJECTOR3D */ diff --git a/include/astra/ProjectorTypelist.h b/include/astra/ProjectorTypelist.h new file mode 100644 index 0000000..ddc345a --- /dev/null +++ b/include/astra/ProjectorTypelist.h @@ -0,0 +1,104 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_PROJECTORTYPELIST +#define _INC_ASTRA_PROJECTORTYPELIST + +#include "Projector2D.h" +#include "TypeList.h" + +using namespace astra; +using namespace astra::typelist; + +// Projector2D +#include "Projector2D.h" +#include "ParallelBeamLineKernelProjector2D.h" +#include "ParallelBeamLinearKernelProjector2D.h" +#include "ParallelBeamBlobKernelProjector2D.h" +#include "ParallelBeamStripKernelProjector2D.h" +#include "SparseMatrixProjector2D.h" +#include "FanFlatBeamLineKernelProjector2D.h" +#include "FanFlatBeamStripKernelProjector2D.h" + +#ifdef ASTRA_CUDA +#include "CudaProjector2D.h" +namespace astra{ + + typedef TYPELIST_8( + CFanFlatBeamLineKernelProjector2D, + CFanFlatBeamStripKernelProjector2D, + CParallelBeamLinearKernelProjector2D, + CParallelBeamLineKernelProjector2D, + CParallelBeamBlobKernelProjector2D, + CParallelBeamStripKernelProjector2D, + CSparseMatrixProjector2D, + CCudaProjector2D) + Projector2DTypeList; +} + + + +#else + +namespace astra{ + typedef TYPELIST_7( + CFanFlatBeamLineKernelProjector2D, + CFanFlatBeamStripKernelProjector2D, + CParallelBeamLinearKernelProjector2D, + CParallelBeamLineKernelProjector2D, + CParallelBeamBlobKernelProjector2D, + CParallelBeamStripKernelProjector2D, + CSparseMatrixProjector2D) + Projector2DTypeList; +} + +#endif + +// Projector3D +#include "Projector3D.h" + +#ifdef ASTRA_CUDA + +#include "CudaProjector3D.h" +namespace astra { + typedef TYPELIST_1( + CCudaProjector3D + ) + Projector3DTypeList; +} + +#else + +namespace astra { + typedef TYPELIST_0 Projector3DTypeList; +} + +#endif + + +#endif diff --git a/include/astra/ReconstructionAlgorithm2D.h b/include/astra/ReconstructionAlgorithm2D.h new file mode 100644 index 0000000..25a6c0a --- /dev/null +++ b/include/astra/ReconstructionAlgorithm2D.h @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_RECONSTRUCTIONALGORITHM2D +#define _INC_ASTRA_RECONSTRUCTIONALGORITHM2D + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + + +namespace astra { + +/** + * This is a base class for the different implementations of 2D reconstruction algorithms. + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.} + * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.} + * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} + * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} + * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + */ +class _AstraExport CReconstructionAlgorithm2D : public CAlgorithm { + +public: + + /** Default constructor, containing no code. + */ + CReconstructionAlgorithm2D(); + + /** Destructor. + */ + virtual ~CReconstructionAlgorithm2D(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Clear this class. + */ + virtual void clear(); + + /** Add a min/max constraint to the reconstruction process + * + * @param _bUseMin True if the algorithm should use a min constraint. + * @param _fMinValue Lower value to clip pixel values to. + * @param _bUseMax True if the algorithm should use a max constraint. + * @param _fMaxValue Upper value to clip pixel values to. + */ + void setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue); + + /** Set a fixed reconstruction mask. A pixel will only be used in the reconstruction if the + * corresponding value in the mask is 1. + * + * @param _pMask Volume Data object containing fixed reconstruction mask + * @param _bEnable enable the use of this mask + */ + void setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable = true); + + /** Set a fixed sinogram mask. A detector value will only be used in the reconstruction if the + * corresponding value in the mask is 1. + * + * @param _pMask Projection Data object containing fixed sinogram mask + * @param _bEnable enable the use of this mask + */ + void setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable = true); + + /** Get all information parameters. + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information. + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get projector object + * + * @return projector + */ + CProjector2D* getProjector() const; + + /** Get sinogram data object + * + * @return sinogram data object + */ + CFloat32ProjectionData2D* getSinogram() const; + + /** Get Reconstructed Data + * + * @return reconstruction + */ + CFloat32VolumeData2D* getReconstruction() const; + + /** Get Fixed Reconstruction Mask + * + * @return fixed reconstruction mask + */ + CFloat32VolumeData2D* getReconstructionMask() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0) = 0; + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Get the norm of the residual image. + * Only a few algorithms support this method. + * + * @param _fNorm if supported, the norm is returned here + * @return true if this operation is supported + */ + virtual bool getResidualNorm(float32& _fNorm) { return false; } + +protected: + + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + /** Initial clearing. Only to be used by constructors. + */ + void _clear(); + + //< Projector object. + CProjector2D* m_pProjector; + //< ProjectionData2D object containing the sinogram. + CFloat32ProjectionData2D* m_pSinogram; + //< VolumeData2D object for storing the reconstruction volume. + CFloat32VolumeData2D* m_pReconstruction; + + //< Use minimum value constraint? + bool m_bUseMinConstraint; + //< Minimum value constraint. + float32 m_fMinValue; + //< Use maximum value constraint? + bool m_bUseMaxConstraint; + //< Maximum value constraint. + float32 m_fMaxValue; + + //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct) + CFloat32VolumeData2D* m_pReconstructionMask; + //< Use the fixed reconstruction mask? + bool m_bUseReconstructionMask; + + //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct) + CFloat32ProjectionData2D* m_pSinogramMask; + //< Use the fixed reconstruction mask? + bool m_bUseSinogramMask; + +}; + +// inline functions +inline std::string CReconstructionAlgorithm2D::description() const { return "3D Reconstruction Algorithm"; }; +inline CProjector2D* CReconstructionAlgorithm2D::getProjector() const { return m_pProjector; } +inline CFloat32ProjectionData2D* CReconstructionAlgorithm2D::getSinogram() const { return m_pSinogram; } +inline CFloat32VolumeData2D* CReconstructionAlgorithm2D::getReconstruction() const { return m_pReconstruction; } +inline CFloat32VolumeData2D* CReconstructionAlgorithm2D::getReconstructionMask() const { return m_pReconstructionMask; } + +} // end namespace + +#endif diff --git a/include/astra/ReconstructionAlgorithm3D.h b/include/astra/ReconstructionAlgorithm3D.h new file mode 100644 index 0000000..063ff6e --- /dev/null +++ b/include/astra/ReconstructionAlgorithm3D.h @@ -0,0 +1,223 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_RECONSTRUCTIONALGORITHM3D +#define _INC_ASTRA_RECONSTRUCTIONALGORITHM3D + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" + +#include "Float32ProjectionData3D.h" +#include "Float32VolumeData3D.h" + + +namespace astra { + +class CProjector3D; + +/** + * This is a base class for the different implementations of 3D reconstruction algorithms. + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.} + * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.} + * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} + * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} + * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + */ +class _AstraExport CReconstructionAlgorithm3D : public CAlgorithm { + +public: + + /** Default constructor, containing no code. + */ + CReconstructionAlgorithm3D(); + + /** Destructor. + */ + virtual ~CReconstructionAlgorithm3D(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData3D object containing the sinogram data. + * @param _pReconstruction VolumeData3D object for storing the reconstructed volume. + */ + bool initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3D* _pSinogram, + CFloat32VolumeData3D* _pReconstruction); + + /** Clear this class. + */ + virtual void clear(); + + /** Add a min/max constraint to the reconstruction process + * + * @param _bUseMin True if the algorithm should use a min constraint. + * @param _fMinValue Lower value to clip pixel values to. + * @param _bUseMax True if the algorithm should use a max constraint. + * @param _fMaxValue Upper value to clip pixel values to. + */ + void setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue); + + /** Set a fixed reconstruction mask. A pixel will only be used in the reconstruction if the + * corresponding value in the mask is 1. + * + * @param _pMask Volume Data object containing fixed reconstruction mask + * @param _bEnable enable the use of this mask + */ + void setReconstructionMask(CFloat32VolumeData3D* _pMask, bool _bEnable = true); + + /** Set a fixed sinogram mask. A detector value will only be used in the reconstruction if the + * corresponding value in the mask is 1. + * + * @param _pMask Projection Data object containing fixed sinogram mask + * @param _bEnable enable the use of this mask + */ + void setSinogramMask(CFloat32ProjectionData3D* _pMask, bool _bEnable = true); + + /** Get all information parameters. + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information. + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Get projector object + * + * @return projector + */ + CProjector3D* getProjector() const; + + /** Get sinogram data object + * + * @return sinogram data object + */ + CFloat32ProjectionData3D* getSinogram() const; + + /** Get Reconstructed Data + * + * @return reconstruction + */ + CFloat32VolumeData3D* getReconstruction() const; + + /** Get Fixed Reconstruction Mask + * + * @return fixed reconstruction mask + */ + CFloat32VolumeData3D* getReconstructionMask() const; + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0) = 0; + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + + /** Get the norm of the residual image. + * Only a few algorithms support this method. + * + * @param _fNorm if supported, the norm is returned here + * @return true if this operation is supported + */ + virtual bool getResidualNorm(float32& _fNorm) { return false; } + +protected: + + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + //< Projector object. + CProjector3D* m_pProjector; + //< ProjectionData3D object containing the sinogram. + CFloat32ProjectionData3D* m_pSinogram; + //< VolumeData3D object for storing the reconstruction volume. + CFloat32VolumeData3D* m_pReconstruction; + + //< Use minimum value constraint? + bool m_bUseMinConstraint; + //< Minimum value constraint. + float32 m_fMinValue; + //< Use maximum value constraint? + bool m_bUseMaxConstraint; + //< Maximum value constraint. + float32 m_fMaxValue; + + //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct) + CFloat32VolumeData3D* m_pReconstructionMask; + //< Use the fixed reconstruction mask? + bool m_bUseReconstructionMask; + + //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct) + CFloat32ProjectionData3D* m_pSinogramMask; + //< Use the fixed reconstruction mask? + bool m_bUseSinogramMask; + +}; + +// inline functions +inline std::string CReconstructionAlgorithm3D::description() const { return "3D Reconstruction Algorithm"; }; +inline CProjector3D* CReconstructionAlgorithm3D::getProjector() const { return m_pProjector; } +inline CFloat32ProjectionData3D* CReconstructionAlgorithm3D::getSinogram() const { return m_pSinogram; } +inline CFloat32VolumeData3D* CReconstructionAlgorithm3D::getReconstruction() const { return m_pReconstruction; } +inline CFloat32VolumeData3D* CReconstructionAlgorithm3D::getReconstructionMask() const { return m_pReconstructionMask; } + +} // end namespace + +#endif diff --git a/include/astra/SartAlgorithm.h b/include/astra/SartAlgorithm.h new file mode 100644 index 0000000..1a79a60 --- /dev/null +++ b/include/astra/SartAlgorithm.h @@ -0,0 +1,226 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SARTALGORITHM +#define _INC_ASTRA_SARTALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" +#include "ReconstructionAlgorithm2D.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +#include "DataProjector.h" + +namespace astra { + +/** + * \brief + * This class contains the implementation of the SART (Simultaneous Algebraic Reconstruction Technique) algorithm. + * + * The update step of pixel \f$v_j\f$ for projection \f$phi\f$ and iteration \f$k\f$ is given by: + * \f[ + * v_j^{(k+1)} = v_j^{(k)} + \frac{\sum_{p_i \in P_\phi} \left( \lambda \frac{p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}} {\sum_{r=1}^{N}w_{ir} } \right)} {\sum_{p_i \in P_\phi}w_{ij}} + * \f] + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.} + * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.} + * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} + * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} + * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + * \astra_xml_item_option{ProjectionOrder, string, "sequential", the order in which the projections are updated. 'sequential', 'random' or 'custom'} + * \astra_xml_item_option{ProjectionOrderList, vector of float, not used, if ProjectionOrder='custom': use this order.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('SART');\n + * cfg.ProjectorId = proj_id;\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.MaskId = mask_id;\n + * cfg.option.UseMinConstraint = 'yes';\n + * cfg.option.UseMaxConstraint = 'yes';\n + * cfg.option.MaxConstraintValue = 1024;\n + * cfg.option.ProjectionOrder = 'custom';\n +* cfg.option.ProjectionOrderList = randperm(100);\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 10);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + */ +class _AstraExport CSartAlgorithm : public CReconstructionAlgorithm2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - valid projector + * - valid data objects + * - projection order all within range + */ + virtual bool _check(); + + // temporary data objects + CFloat32ProjectionData2D* m_pTotalRayLength; + CFloat32VolumeData2D* m_pTotalPixelWeight; + CFloat32ProjectionData2D* m_pDiffSinogram; + + int m_iIterationCount; + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CSartAlgorithm(); + + /** Constructor. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + CSartAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Constructor. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _piProjectionOrder array containing a projection order. + * @param _iProjectionCount number of elements in _piProjectionOrder. + */ + CSartAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int* _piProjectionOrder, + int _iProjectionCount); + + /** Destructor. + */ + virtual ~CSartAlgorithm(); + + /** Clear this class. + */ + virtual void clear(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class, no optionals, use sequential order. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @return initialization successful? + */ + virtual bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Initialize class, use custom order. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @param _piProjectionOrder array containing a projection order. + * @param _iProjectionCount number of elements in _piProjectionOrder. + * @return initialization successful? + */ + virtual bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int* _piProjectionOrder, + int _iProjectionCount); + + /** Get all information parameters + * + * @return map with all boost::any object + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier identifier string to specify which piece of information you want + * @return boost::any object + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. Each iteration is a forward and backprojection of + * a single projection index. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 1); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +protected: + + + //< Order of the projections. + int* m_piProjectionOrder; + //< Number of projections specified in m_piProjectionOrder. + int m_iProjectionCount; + //< Current index in the projection order array. + int m_iCurrentProjection; + +}; + +// inline functions +inline std::string CSartAlgorithm::description() const { return CSartAlgorithm::type; }; + + +} // end namespace + +#endif diff --git a/include/astra/Singleton.h b/include/astra/Singleton.h new file mode 100644 index 0000000..5a494e4 --- /dev/null +++ b/include/astra/Singleton.h @@ -0,0 +1,87 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SINGLETON +#define _INC_ASTRA_SINGLETON + +#include <cassert> + +#ifndef _MSC_VER +#include <stdint.h> +#endif + +namespace astra { + /** + * This singleton interface class ensures that any of its children can be instatiated only once. This is used by the ObjectFactories. + **/ +template<typename T> +class Singleton { + + public: + + // constructor + Singleton() { + assert(!m_singleton); + int offset = (uintptr_t)(T*)1 - (uintptr_t)(Singleton<T>*)(T*)1; + m_singleton = (T*)((uintptr_t)this + offset); + }; + + // destructor + virtual ~Singleton() { + assert(m_singleton); + m_singleton = 0; + } + + // get singleton + static T& getSingleton() { + if (!m_singleton) + m_singleton = new T(); + return *m_singleton; + } + static T* getSingletonPtr() { + if (!m_singleton) + m_singleton = new T(); + return m_singleton; + } + + private: + + // the singleton + static T* m_singleton; + +}; + +#define DEFINE_SINGLETON(T) template<> T* Singleton<T >::m_singleton = 0 + +// This is a hack to support statements like +// DEFINE_SINGLETON2(CTemplatedClass<C1, C2>); +#define DEFINE_SINGLETON2(A,B) template<> A,B* Singleton<A,B >::m_singleton = 0 + +} // end namespace + +#endif diff --git a/include/astra/SirtAlgorithm.h b/include/astra/SirtAlgorithm.h new file mode 100644 index 0000000..5cbc4d4 --- /dev/null +++ b/include/astra/SirtAlgorithm.h @@ -0,0 +1,217 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SIRTALGORITHM +#define _INC_ASTRA_SIRTALGORITHM + +#include "Globals.h" +#include "Config.h" + +#include "Algorithm.h" +#include "ReconstructionAlgorithm2D.h" + +#include "Projector2D.h" +#include "Float32ProjectionData2D.h" +#include "Float32VolumeData2D.h" + +#include "DataProjector.h" + +namespace astra { + +/** + * \brief + * This class contains the implementation of the SIRT (Simultaneous Iterative Reconstruction Technique) algorithm. + * + * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by: + * \f[ + * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} + * \f] + * + * \par XML Configuration + * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.} + * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} + * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} + * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.} + * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.} + * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.} + * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} + * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} + * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + * + * \par XML Example + * \astra_code{ + * <Algorithm type="SIRT">\n + * <ProjectorID>proj_id</ProjectorID>\n + * <ProjectionDataId>sino_id</ProjectionDataId>\n + * <ReconstructionDataId>recon_id</ReconstructionDataId>\n + * <Option key="ReconstructionMaskId" value="3"/>\n + * <Option key="SinogramMaskId" value="4"/>\n + * <Option key="UseMinConstraint" value="yes"/>\n + * <Option key="UseMaxConstraint" value="yes"/>\n + * <Option key="MaxConstraintValue" value="1024"/>\n + * </Algorithm> + * } + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('SIRT');\n + * cfg.ProjectorId = proj_id;\n + * cfg.ProjectionDataId = sino_id;\n + * cfg.ReconstructionDataId = recon_id;\n + * cfg.option.SinogramMaskId = smask_id;\n + * cfg.option.ReconstructionMaskId = mask_id;\n + * cfg.option.UseMinConstraint = 'yes';\n + * cfg.option.UseMaxConstraint = 'yes';\n + * cfg.option.MaxConstraintValue = 1024;\n + * alg_id = astra_mex_algorithm('create'\, cfg);\n + * astra_mex_algorithm('iterate'\, alg_id\, 10);\n + * astra_mex_algorithm('delete'\, alg_id);\n + * } + * + * \par References + * [1] "Computational Analysis and Improvement of SIRT", J. Gregor, T. Benson, IEEE Transactions on Medical Imaging, Vol. 22, No. 7, July 2008. + */ +class _AstraExport CSirtAlgorithm : public CReconstructionAlgorithm2D { + +protected: + + /** Init stuff + */ + virtual void _init(); + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - valid projector + * - valid data objects + */ + virtual bool _check(); + + /** Temporary data object for storing the total ray lengths + */ + CFloat32ProjectionData2D* m_pTotalRayLength; + + /** Temporary data object for storing the total pixel weigths + */ + CFloat32VolumeData2D* m_pTotalPixelWeight; + + /** Temporary data object for storing the difference between the forward projected + * reconstruction, and the measured projection data + */ + CFloat32ProjectionData2D* m_pDiffSinogram; + + /** Temporary data object for storing volume data + */ + CFloat32VolumeData2D* m_pTmpVolume; + + /** The number of performed iterations + */ + int m_iIterationCount; + +public: + + // type of the algorithm, needed to register with CAlgorithmFactory + static std::string type; + + /** Default constructor, containing no code. + */ + CSirtAlgorithm(); + + /** Default constructor + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + */ + CSirtAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Destructor. + */ + virtual ~CSirtAlgorithm(); + + /** Clear this class. + */ + virtual void clear(); + + /** Initialize the algorithm with a config object. + * + * @param _cfg Configuration Object + * @return Initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize class. + * + * @param _pProjector Projector Object. + * @param _pSinogram ProjectionData2D object containing the sinogram data. + * @param _pReconstruction VolumeData2D object for storing the reconstructed volume. + * @return Initialization successful? + */ + bool initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction); + + /** Get all information parameters. + * + * @return Map with all available identifier strings and their values. + */ + virtual map<string,boost::any> getInformation(); + + /** Get a single piece of information represented as a boost::any + * + * @param _sIdentifier Identifier string to specify which piece of information you want. + * @return One piece of information. + */ + virtual boost::any getInformation(std::string _sIdentifier); + + /** Perform a number of iterations. + * + * @param _iNrIterations amount of iterations to perform. + */ + virtual void run(int _iNrIterations = 0); + + /** Get a description of the class. + * + * @return description string + */ + virtual std::string description() const; + +}; + +// inline functions +inline std::string CSirtAlgorithm::description() const { return CSirtAlgorithm::type; }; + + +} // end namespace + +#endif diff --git a/include/astra/SparseMatrix.h b/include/astra/SparseMatrix.h new file mode 100644 index 0000000..e07be87 --- /dev/null +++ b/include/astra/SparseMatrix.h @@ -0,0 +1,144 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SPARSEMATRIX +#define _INC_ASTRA_SPARSEMATRIX + +namespace astra +{ + + +/** This class implements a sparse matrix. It is stored as three arrays. + * The values are stored row-by-row. + * m_pfValues contains the values + * m_piColIndices contains the col indices of the values + * m_plRowStarts contains the start offsets of the rows + */ + + +class _AstraExport CSparseMatrix { +public: + CSparseMatrix(); + + // TODO: are ints large enough for width/height? + CSparseMatrix(unsigned int _iHeight, unsigned int _iWidth, + unsigned long _lSize); + + /** Initialize the matrix structure. + * It does not initialize any values. + * + * @param _iHeight number of rows + * @param _iWidth number of columns + * @param _lSize maximum number of non-zero entries + * @return initialization successful? + */ + + bool initialize(unsigned int _iHeight, unsigned int _iWidth, + unsigned long _lSize); + + /** Destructor. + */ + ~CSparseMatrix(); + + /** Has the matrix structure been initialized? + * + * @return initialized successfully + */ + bool isInitialized() const { return m_bInitialized; } + + /** get a description of the class + * + * @return description string + */ + std::string description() const; + + /** get the data for a single row. Entries are stored from left to right. + * + * @param _iRow the row + * @param _iSize the returned number of elements in the row + * @param _pfValues the values of the non-zero entries in the row + * @param _piColIndices the column indices of the non-zero entries + */ + void getRowData(unsigned int _iRow, unsigned int& _iSize, + const float32*& _pfValues, const unsigned int*& _piColIndices) const + { + assert(_iRow < m_iHeight); + unsigned long lStart = m_plRowStarts[_iRow]; + _iSize = m_plRowStarts[_iRow+1] - lStart; + _pfValues = &m_pfValues[lStart]; + _piColIndices = &m_piColIndices[lStart]; + } + + /** get the number of elements in a row + * + * @param _iRow the row + * @return number of stored entries in the row + */ + unsigned int getRowSize(unsigned int _iRow) const + { + assert(_iRow < m_iHeight); + return m_plRowStarts[_iRow+1] - m_plRowStarts[_iRow]; + } + + + /** Matrix width + */ + unsigned int m_iHeight; + + /** Matrix height + */ + unsigned int m_iWidth; + + /** Maximum number of non-zero entries + */ + unsigned long m_lSize; + + /** Contains the numeric values of all non-zero elements + */ + float32* m_pfValues; + + /** Contains the colon index of all non-zero elements + */ + unsigned int* m_piColIndices; + + /** The indices in this array point to the first element of each row in the m_pfValues array + */ + unsigned long* m_plRowStarts; + +protected: + + /** Is the class initialized? + */ + bool m_bInitialized; +}; + + +} + + +#endif diff --git a/include/astra/SparseMatrixProjectionGeometry2D.h b/include/astra/SparseMatrixProjectionGeometry2D.h new file mode 100644 index 0000000..e334dd1 --- /dev/null +++ b/include/astra/SparseMatrixProjectionGeometry2D.h @@ -0,0 +1,154 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SPARSEMATRIXPROJECTIONGEOMETRY2D +#define _INC_ASTRA_SPARSEMATRIXPROJECTIONGEOMETRY2D + +#include "ProjectionGeometry2D.h" + +namespace astra +{ + +class CSparseMatrix; + +/** + * This class defines a projection geometry determined by an arbitrary + * sparse matrix. + * + * The projection data is assumed to be grouped by 'angle' and 'detector pixel'. + * This does not have any effect on the algorithms, but only on the + * way the projection data is stored and accessed. + */ +class _AstraExport CSparseMatrixProjectionGeometry2D : public CProjectionGeometry2D +{ +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + * + */ + CSparseMatrixProjectionGeometry2D(); + + /** Constructor. Create an instance of the CSparseMatrixProjectionGeometry2D class. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _pMatrix Pointer to a CSparseMatrix. The caller is responsible for keeping this matrix valid until it is no longer required. + */ + CSparseMatrixProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + const CSparseMatrix* _pMatrix); + + /** Copy constructor. + */ + CSparseMatrixProjectionGeometry2D(const CSparseMatrixProjectionGeometry2D& _projGeom); + + /** Destructor. + */ + ~CSparseMatrixProjectionGeometry2D(); + + /** Assignment operator. + */ + CSparseMatrixProjectionGeometry2D& operator=(const CSparseMatrixProjectionGeometry2D& _other); + + /** Initialize the geometry with a config object. This does not allow + * setting a matrix. Use the setMatrix() method for that afterwards. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialization. Initializes an instance of the CProjectionGeometry2D class. If the object has been + * initialized before, the object is reinitialized and memory is freed and reallocated if necessary. + * + * @param _iProjectionAngleCount Number of projection angles. + * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle. + * @param _pMatrix Pointer to a CSparseMatrix. The caller is responsible for keeping this matrix valid until it is no longer required. + */ + bool initialize(int _iProjectionAngleCount, + int _iDetectorCount, + const CSparseMatrix* _pMatrix); + + /** Set the associated sparse matrix. The previous one is deleted. + * + * @param _pMatrix Pointer to a CSparseMatrix. The caller is responsible for keeping this matrix valid until it is no longer required. + * @return initialization successful? + */ + + bool setMatrix(CSparseMatrix* _pMatrix); + + /** Get a pointer to the associated sparse matrix. + * @return the associated sparse matrix + */ + const CSparseMatrix* getMatrix() const { return m_pMatrix; } + + /** Create a hard copy. + */ + virtual CProjectionGeometry2D* clone(); + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(CProjectionGeometry2D*) const; + + /** Returns true if the type of geometry defined in this class is the one specified in _sType. + * + * @param _sType geometry type to compare to. + * @return true if _sType == "parallel". + */ + virtual bool isOfType(const std::string& _sType); + + /** + * Returns a vector describing the direction of a ray belonging to a certain detector + * + * @param _iProjectionIndex index of projection + * @param _iProjectionIndex index of detector + * + * @return a unit vector describing the direction + */ + virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex); + +protected: + + /** Check this object. + * + * @return object initialized + */ + bool _check(); + + const CSparseMatrix* m_pMatrix; +}; + +} // namespace astra + +#endif /* _INC_ASTRA_SPARSEMATRIXPROJECTIONGEOMETRY2D */ diff --git a/include/astra/SparseMatrixProjector2D.h b/include/astra/SparseMatrixProjector2D.h new file mode 100644 index 0000000..f2554bf --- /dev/null +++ b/include/astra/SparseMatrixProjector2D.h @@ -0,0 +1,210 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SPARSEMATRIXPROJECTOR2D +#define _INC_ASTRA_SPARSEMATRIXPROJECTOR2D + +#include "SparseMatrixProjectionGeometry2D.h" +#include "SparseMatrix.h" +#include "Float32Data2D.h" +#include "Projector2D.h" + +namespace astra +{ + + +/** This class implements a two-dimensional projector using a projection geometry defined by an arbitrary sparse matrix. + * + * \par XML Configuration + * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.} + * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.} + * + * \par MATLAB example + * \astra_code{ + * cfg = astra_struct('sparse_matrix');\n + * cfg.ProjectionGeometry = proj_geom;\n + * cfg.VolumeGeometry = vol_geom;\n + * proj_id = astra_mex_projector('create'\, cfg);\n + * } + */ +class _AstraExport CSparseMatrixProjector2D : public CProjector2D { + +protected: + + /** Initial clearing. Only to be used by constructors. + */ + virtual void _clear(); + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - no NULL pointers + * - all sub-objects are initialized properly + * - matrix dimensions match volume geometry + */ + virtual bool _check(); + +public: + + // type of the projector, needed to register with CProjectorFactory + static std::string type; + + /** Default constructor. + */ + CSparseMatrixProjector2D(); + + /** Constructor. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + */ + CSparseMatrixProjector2D(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Destructor, is virtual to show that we are aware subclass destructor are called. + */ + ~CSparseMatrixProjector2D(); + + /** Initialize the projector with a config object. + * + * @param _cfg Configuration Object + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialize the projector. + * + * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED. + * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED. + * @return initialization successful? + */ + virtual bool initialize(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry); + + /** Clear this class. + */ + virtual void clear(); + + /** Returns the number of weights required for storage of all weights of one projection. + * + * @param _iProjectionIndex Index of the projection (zero-based). + * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels. + */ + virtual int getProjectionWeightsCount(int _iProjectionIndex); + + /** Compute the pixel weights for a single ray, from the source to a detector pixel. + * + * @param _iProjectionIndex Index of the projection + * @param _iDetectorIndex Index of the detector pixel + * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements + * of type SPixelWeight. On return, this array contains a list of the index + * and weight for all pixels on the ray. + * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels. + * This number MUST be greater than the total number of pixels on the ray. + * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the + * ray (that have been stored in the list _pWeightedPixels). + */ + virtual void computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount); + + /** Create a list of detectors that are influenced by point [_iRow, _iCol]. + * + * @param _iRow row of the point + * @param _iCol column of the point + * @return list of SDetector2D structs + */ + virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol); + + /** Policy-based projection of all rays. This function will calculate each non-zero projection + * weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void project(Policy& _policy); + + /** Policy-based projection of all rays of a single projection. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Wwhich projection should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleProjection(int _iProjection, Policy& _policy); + + /** Policy-based projection of a single ray. This function will calculate each non-zero + * projection weight and use this value for a task provided by the policy object. + * + * @param _iProjection Which projection should be projected? + * @param _iDetector Which detector should be projected? + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy); + + /** Policy-based voxel-projection of a single pixel. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _iRow + * @param _iCol + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectSingleVoxel(int _iRow, int _iCol, Policy& _policy) {} + + /** Policy-based voxel-projection of all voxels. This function will calculate + * each non-zero projection weight and use this value for a task provided by the policy object. + * + * @param _policy Policy object. Should contain prior, addWeight and posterior function. + */ + template <typename Policy> + void projectAllVoxels(Policy& _policy) {} + +protected: + + /** Return the type of this projector. + * + * @return identification type of this projector + */ + virtual std::string getType(); + +}; + +//---------------------------------------------------------------------------------------- + +inline std::string CSparseMatrixProjector2D::getType() +{ + return type; +} + +} // namespace astra + +#endif + diff --git a/include/astra/SparseMatrixProjector2D.inl b/include/astra/SparseMatrixProjector2D.inl new file mode 100644 index 0000000..8256232 --- /dev/null +++ b/include/astra/SparseMatrixProjector2D.inl @@ -0,0 +1,90 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +//---------------------------------------------------------------------------------------- +// PROJECT ALL +template <typename Policy> +void CSparseMatrixProjector2D::project(Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + for (int i = 0; i < m_pProjectionGeometry->getProjectionAngleCount(); ++i) + for (int j = 0; j < m_pProjectionGeometry->getDetectorCount(); ++j) + projectSingleRay(i, j, p); +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE PROJECTION +template <typename Policy> +void CSparseMatrixProjector2D::projectSingleProjection(int _iProjection, Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + for (int j = 0; j < m_pProjectionGeometry->getDetectorCount(); ++j) + projectSingleRay(_iProjection, j, p); +} + + +//---------------------------------------------------------------------------------------- +// PROJECT SINGLE RAY +template <typename Policy> +void CSparseMatrixProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p) +{ + ASTRA_ASSERT(m_bIsInitialized); + + int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + + // POLICY: RAY PRIOR + if (!p.rayPrior(iRayIndex)) return; + + const unsigned int* piColIndices; + const float32* pfValues; + unsigned int iSize; + + pMatrix->getRowData(iRayIndex, iSize, pfValues, piColIndices); + + for (unsigned int i = 0; i < iSize; ++i) { + unsigned int iVolumeIndex = piColIndices[i]; + + // POLICY: PIXEL PRIOR + if (p.pixelPrior(iVolumeIndex)) { + + // POLICY: ADD + p.addWeight(iRayIndex, iVolumeIndex, pfValues[i]); + + // POLICY: PIXEL POSTERIOR + p.pixelPosterior(iVolumeIndex); + } + } + + // POLICY: RAY POSTERIOR + p.rayPosterior(iRayIndex); +} diff --git a/include/astra/TypeList.h b/include/astra/TypeList.h new file mode 100644 index 0000000..fcf985d --- /dev/null +++ b/include/astra/TypeList.h @@ -0,0 +1,236 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_TYPELIST +#define _INC_ASTRA_TYPELIST + +#include "Globals.h" +#include <cstring> + +namespace astra { +namespace typelist { + + //----------------------------------------------------------------------------------------- + // basic types + /** + * Type to serve as tail of typelist + **/ + class NullType { }; + struct FalseType { enum { value = false }; }; + struct TrueType { enum { value = true }; }; + + //----------------------------------------------------------------------------------------- + // define typelist + /** + * Typelist definition + * \par References + * [1] Modern C++ design: generic programming and design patterns applied, Andrei Alexandrescu + **/ + template <class T, class U> + struct TypeList + { + typedef T Head; + typedef U Tail; + }; + + //----------------------------------------------------------------------------------------- + // linearize typelist + #define TYPELIST_0 NullType + #define TYPELIST_1(T1) TypeList<T1, NullType> + #define TYPELIST_2(T1,T2) TypeList<T1, TYPELIST_1(T2) > + #define TYPELIST_3(T1,T2,T3) TypeList<T1, TYPELIST_2(T2,T3) > + #define TYPELIST_4(T1,T2,T3,T4) TypeList<T1, TYPELIST_3(T2,T3,T4) > + #define TYPELIST_5(T1,T2,T3,T4,T5) TypeList<T1, TYPELIST_4(T2,T3,T4,T5) > + #define TYPELIST_6(T1,T2,T3,T4,T5,T6) TypeList<T1, TYPELIST_5(T2,T3,T4,T5,T6) > + #define TYPELIST_7(T1,T2,T3,T4,T5,T6,T7) TypeList<T1, TYPELIST_6(T2,T3,T4,T5,T6,T7) > + #define TYPELIST_8(T1,T2,T3,T4,T5,T6,T7,T8) TypeList<T1, TYPELIST_7(T2,T3,T4,T5,T6,T7,T8) > + #define TYPELIST_9(T1,T2,T3,T4,T5,T6,T7,T8,T9) TypeList<T1, TYPELIST_8(T2,T3,T4,T5,T6,T7,T8,T9)> + #define TYPELIST_10(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10) \ + TypeList<T1, TYPELIST_9(T2,T3,T4,T5,T6,T7,T8,T9,T10) > + #define TYPELIST_11(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11) \ + TypeList<T1, TYPELIST_10(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11) > + #define TYPELIST_12(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12) \ + TypeList<T1, TYPELIST_11(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12) > + #define TYPELIST_13(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13) \ + TypeList<T1, TYPELIST_12(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13) > + #define TYPELIST_14(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14) \ + TypeList<T1, TYPELIST_13(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14) > + #define TYPELIST_15(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15) \ + TypeList<T1, TYPELIST_14(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15) > + #define TYPELIST_16(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16) \ + TypeList<T1, TYPELIST_15(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16) > + #define TYPELIST_17(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17) \ + TypeList<T1, TYPELIST_16(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17) > + #define TYPELIST_18(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18) \ + TypeList<T1, TYPELIST_17(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18) > + #define TYPELIST_19(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19) \ + TypeList<T1, TYPELIST_18(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19) > + #define TYPELIST_20(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20) \ + TypeList<T1, TYPELIST_19(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20) > + #define TYPELIST_21(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21) \ + TypeList<T1, TYPELIST_20(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21) > + #define TYPELIST_22(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22) \ + TypeList<T1, TYPELIST_21(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22) > + #define TYPELIST_23(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23) \ + TypeList<T1, TYPELIST_22(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23) > + + #define TYPELIST_24(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24) \ + TypeList<T1, TYPELIST_23(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24) > + + #define TYPELIST_25(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25) \ + TypeList<T1, TYPELIST_24(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25) > + + #define TYPELIST_26(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26) \ + TypeList<T1, TYPELIST_25(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26) > + + #define TYPELIST_27(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27) \ + TypeList<T1, TYPELIST_26(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27) > + + #define TYPELIST_28(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28) \ + TypeList<T1, TYPELIST_27(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28) > + + #define TYPELIST_29(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29) \ + TypeList<T1, TYPELIST_28(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29) > + + #define TYPELIST_30(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30) \ + TypeList<T1, TYPELIST_29(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30) > + + #define TYPELIST_31(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31) \ + TypeList<T1, TYPELIST_30(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31) > + + #define TYPELIST_32(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32) \ + TypeList<T1, TYPELIST_31(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32) > + + #define TYPELIST_33(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33) \ + TypeList<T1, TYPELIST_32(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33) > + + #define TYPELIST_34(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34) \ + TypeList<T1, TYPELIST_33(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34) > + + #define TYPELIST_35(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35) \ + TypeList<T1, TYPELIST_34(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35) > + + #define TYPELIST_36(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36) \ + TypeList<T1, TYPELIST_35(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36) > + + #define TYPELIST_37(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37) \ + TypeList<T1, TYPELIST_36(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37) > + + #define TYPELIST_38(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38) \ + TypeList<T1, TYPELIST_37(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38) > + + #define TYPELIST_39(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39) \ + TypeList<T1, TYPELIST_38(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39) > + + #define TYPELIST_40(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39,T40) \ + TypeList<T1, TYPELIST_39(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39,T40) > + + + //----------------------------------------------------------------------------------------- + // calculate length of a typelist + template <class TList> struct Length; + template <> struct Length<NullType> + { + enum { value = 0 }; + }; + template <class T, class U> + struct Length< TypeList<T,U> > + { + enum { value = 1 + Length<U>::value }; + }; + + //----------------------------------------------------------------------------------------- + // indexed access + template <class TList, unsigned int i> struct TypeAt; + template <class Head, class Tail> + struct TypeAt<TypeList<Head,Tail> , 0> + { + typedef Head Result; + }; + template <class Head, class Tail, unsigned int i> + struct TypeAt<TypeList<Head,Tail>, i> + { + typedef typename TypeAt<Tail, i-1>::Result Result; + }; + + + //----------------------------------------------------------------------------------------- + // append to typelist + template <class TList, class T> struct Append; + template <> + struct Append<NullType, NullType> { + typedef NullType Result; + }; + template <class T> + struct Append<NullType, T> { + typedef TYPELIST_1(T) Result; + }; + template <class Head, class Tail> + struct Append<NullType, TypeList<Head,Tail> > { + typedef TypeList<Head,Tail> Result; + }; + template <class Head, class Tail, class T> + struct Append<TypeList<Head,Tail>, T> { + typedef TypeList<Head, typename Append<Tail, T>::Result> Result; + }; + + //----------------------------------------------------------------------------------------- + // create a new object + template <class TList> + struct CreateObject { + template <class U> + static void find (U& functor) { + if (functor(TList::Head::type)) { + functor.res = new typename TList::Head(); + } + CreateObject<typename TList::Tail>::find(functor); + } + }; + template <> + struct CreateObject<NullType> { + template <class U> + static void find(U& functor) {} + }; + + template <typename Base> + struct functor_find { + functor_find() { res = NULL; } + bool operator() (string name) { + return strcmp(tofind.c_str(), name.c_str()) == 0; + } + string tofind; + Base* res; + }; + + + + +} // end namespace typelist +} // end namespace astra + +#endif diff --git a/include/astra/Utilities.h b/include/astra/Utilities.h new file mode 100644 index 0000000..7bf0cae --- /dev/null +++ b/include/astra/Utilities.h @@ -0,0 +1,131 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_UTILIES +#define _INC_ASTRA_UTILIES + +#include <string> +#include <vector> +#include <algorithm> +#include <sstream> +#include <map> + +#include "Globals.h" + +namespace astra { + +/** + * This class contains some usefull static utility functions for std strings. + */ +class StringUtil { + +public: + /** + * Removes whitespace characters such as spaces and tabs at the extremas. + * Optionally you can specify which extrema to trim (default=both) + * + * @param _sString The string to trim. + * @param _bLeft Trim the left extrema? Default = true. + * @param _bRight Trim the right extrema? Default = true. + */ + static void trim(std::string& _sString, bool _bLeft = true, bool _bRight = true); + + /** + * Returns a vector of strings that contains all the substrings delimited by + * the characters in _sDelims. + * + * @param _sString The string to split. + * @param _sDelims The delimiter string. + * @return Vector of strings. + */ + static std::vector<std::string> split(const std::string& _sString, const std::string& _sDelims); + + /** + * Cast a string to an integer. + * + * @param _sString The string to cast. + * @param _iValue Output integer parameter. + * @return success? + */ + static bool toInt(const std::string& _sString, int& _iValue); + + /** + * Cast a string to a float32. + * + * @param _sString The string to cast. + * @param _fValue Output float32 parameter. + * @return success? + */ + static bool toFloat32(const std::string& _sString, float32& _fValue); + + /** + * Convert a string to lower case. + * + * @param _sString The string to convert. + */ + static void toLowerCase(std::string& _sString); + + /** + * Convert a string to upper case. + * + * @param _sString The string to convert. + */ + static void toUpperCase(std::string& _sString); +}; + +/** + * This class contains some usefull static utility functions for std strings. + */ +class FileSystemUtil { + +public: + /** + * Get the extensions of a filename. Always in lower case. + * + * @param _sFilename file to get extensions from. + * @return Extension (lower case). Empty string if filename is a directory or not a valid file format. + */ + static std::string getExtension(std::string& _sFilename); + + +}; + + +template<typename T, typename S> +std::map<T,S> mergeMap(std::map<T,S> _mMap1, std::map<T,S> _mMap2) +{ + std::map<T,S> result = _mMap1; + for (typename std::map<T,S>::iterator it = _mMap2.begin(); it != _mMap2.end(); it++) { + result[(*it).first] = (*it).second; + } + return result; +} + +} // end namespace + +#endif diff --git a/include/astra/Vector3D.h b/include/astra/Vector3D.h new file mode 100644 index 0000000..ee923c9 --- /dev/null +++ b/include/astra/Vector3D.h @@ -0,0 +1,131 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_VECTOR3D +#define _INC_ASTRA_VECTOR3D + +#include "Globals.h" + +namespace astra { + +/** + * This class defines a three-dimensional vector type. + */ +class CVector3D +{ + float32 m_fX; ///< X Coordinate + float32 m_fY; ///< Y Coordinate + float32 m_fZ; ///< Z Coordinate + +public: + /** + * Default constructor + */ + CVector3D(); + + /** + * Constructor initializing member variables + */ + CVector3D(float32 _fX, float32 _fY, float32 _fZ); + + /** + * Returns the X-coordinate stored in this vector + */ + float32 getX() const; + + /** + * Returns the Y-coordinate stored in this vector + */ + float32 getY() const; + + /** + * Returns the Z-coordinate stored in this vector + */ + float32 getZ() const; + + /** + * Sets the X-coordinate stored in this vector + */ + void setX(float32 _fX); + + /** + * Sets the X-coordinate stored in this vector + */ + void setY(float32 _fY); + + /** + * Sets the X-coordinate stored in this vector + */ + void setZ(float32 _fZ); +}; + +inline CVector3D::CVector3D() +{ + m_fX = m_fY = m_fZ = 0.0f; +} + +inline CVector3D::CVector3D(float32 _fX, float32 _fY, float32 _fZ) +{ + m_fX = _fX; + m_fY = _fY; + m_fZ = _fZ; +} + +inline float32 CVector3D::getX() const +{ + return m_fX; +} + +inline float32 CVector3D::getY() const +{ + return m_fY; +} + +inline float32 CVector3D::getZ() const +{ + return m_fZ; +} + +inline void CVector3D::setX(float32 _fX) +{ + m_fX = _fX; +} + +inline void CVector3D::setY(float32 _fY) +{ + m_fY = _fY; +} + +inline void CVector3D::setZ(float32 _fZ) +{ + m_fZ = _fZ; +} + +} + +#endif /* _INC_ASTRA_VECTOR3D */ diff --git a/include/astra/VolumeGeometry2D.h b/include/astra/VolumeGeometry2D.h new file mode 100644 index 0000000..99d480d --- /dev/null +++ b/include/astra/VolumeGeometry2D.h @@ -0,0 +1,608 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_VOLUMEGEOMETRY2D +#define _INC_ASTRA_VOLUMEGEOMETRY2D + +#include "Globals.h" +#include "Config.h" + +namespace astra +{ + +/** + * This class represents a pixel grid that is placed in the geometry. It defines a rectangular volume window. + * + * \par XML Configuration + * \astra_xml_item{GridColCount, integer, Number of columns in this geometry.} + * \astra_xml_item{GridRowCount, integer, Number of rows in this geometry.} + * \astra_xml_item_option{WindowMinX, float, Minimal X-coordinate in the volume window.} + * \astra_xml_item_option{WindowMaxX, float, Maximal X-coordinate in the volume window.} + * \astra_xml_item_option{WindowMinY, float, Minimal Y-coordinate in the volume window.} + * \astra_xml_item_option{WindowMaxY, float, Maximal Y-coordinate in the volume window.} + * + * \par MATLAB example + * \astra_code{ + * vol_geom = struct();\n + * vol_geom.GridColCount = 1024;\n + * vol_geom.GridRowCount = 768;\n + * vol_geom.option.WindowMinX = -512;\n + * vol_geom.option.WindowMaxX = -384;\n + * vol_geom.option.WindowMinY = 512;\n + * vol_geom.option.WindowMaxY = 384;\n + * } + */ +class _AstraExport CVolumeGeometry2D { + +protected: + bool m_bInitialized; ///< Has this object been initialized? + + int m_iGridColCount; ///< number of columns in the volume grid. + int m_iGridRowCount; ///< number of rows in the volume grid. + int m_iGridTotCount; ///< total number of pixels in the volume grid (= m_iGridColCount * m_iGridRowCount). + + /** Width of the volume window, in unit lengths. + * + * Note that this width is independent of the number of pixels in the X-direction, as the width of a pixel can + * be different from 1. + */ + float32 m_fWindowLengthX; + + /** Height of the volume window, in unit lengths. + * + * Note that this height is independent of the number of pixels in the Y-direction, as the height of a pixel can + * be different from 1. + */ + float32 m_fWindowLengthY; + + float32 m_fWindowArea; ///< Total area of the volume window, in unit lengths squared. + + float32 m_fPixelLengthX; ///< Width of a single pixel, in unit lengths. + float32 m_fPixelLengthY; ///< Height of a single pixel, in unit lengths. + float32 m_fPixelArea; ///< Area of a single pixel, in unit lengths squared. + + float32 m_fDivPixelLengthX; ///< 1/m_fPixelLengthX, used for fast division. + float32 m_fDivPixelLengthY; ///< 1/m_fPixelLengthY, used for fast division. + + float32 m_fWindowMinX; ///< Minimal X-coordinate in the volume window. + float32 m_fWindowMinY; ///< Maximal X-coordinate in the volume window. + float32 m_fWindowMaxX; ///< Minimal Y-coordinate in the volume window. + float32 m_fWindowMaxY; ///< Maximal Y-coordinate in the volume window. + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - number of rows and columns is larger than zero + * - window minima is smaller than window maxima + * - m_iGridTotCount, m_fWindowLengthX, m_fWindowLengthY, m_fWindowArea, m_fPixelLengthX, + * m_fPixelLengthY, m_fPixelArea, m_fDivPixelLengthX and m_fDivPixelLengthY are initialized ok + */ + bool _check(); + + + /** Calculate values of all member variables from m_iGridRow/ColCount, m_fWindow* + */ + void _calculateDependents(); +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + */ + CVolumeGeometry2D(); + + /** Constructor. Create an instance of the CVolumeGeometry2D class. + * The minimal and coordinates values of the geometry will be set to -/+ the number of rows/columns. + * + * @param _iGridCountX Number of columns in the volume grid. + * @param _iGridCountY Number of rows in the volume grid. + */ + CVolumeGeometry2D(int _iGridCountX, + int _iGridCountY); + + /** Constructor. Create an instance of the CVolumeGeometry2D class. + * + * @param _iGridCountX Number of columns in the volume grid. + * @param _iGridCountY Number of rows in the volume grid. + * @param _fWindowMinX Minimal X-coordinate in the volume window. + * @param _fWindowMinY Minimal Y-coordinate in the volume window. + * @param _fWindowMaxX Maximal X-coordinate in the volume window. + * @param _fWindowMaxY Maximal Y-coordinate in the volume window. + */ + CVolumeGeometry2D(int _iGridCountX, + int _iGridCountY, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMaxX, + float32 _fWindowMaxY); + + /** Destructor. + */ + virtual ~CVolumeGeometry2D(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + void clear(); + + /** Create a hard copy. + */ + CVolumeGeometry2D* clone(); + + /** Initialize the volume geometry with a config object. + * + * @param _cfg Configuration Object. + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialization. Initializes an instance of the CVolumeGeometry2D class. + * The minimal and maximal coordinates of the geometry will be set to -/+ half the number of rows/columns. + * + * If the object has been initialized before, the object is reinitialized and + * memory is freed and reallocated if necessary. + * + * @param _iGridColCount Number of columns in the volume grid. + * @param _iGridRowCount Number of rows in the volume grid. + * @return initialization successful + */ + bool initialize(int _iGridColCount, int _iGridRowCount); + + /** Initialization. Initializes an instance of the CVolumeGeometry2D class. + * + * If the object has been initialized before, the object is reinitialized and + * memory is freed and reallocated if necessary. + * + * @param _iGridColCount Number of columns in the volume grid. + * @param _iGridRowCount Number of rows in the volume grid. + * @param _fWindowMinX Minimal X-coordinate in the volume window. + * @param _fWindowMinY Minimal Y-coordinate in the volume window. + * @param _fWindowMaxX Maximal X-coordinate in the volume window. + * @param _fWindowMaxY Maximal Y-coordinate in the volume window. + * @return initialization successful + */ + bool initialize(int _iGridColCount, + int _iGridRowCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMaxX, + float32 _fWindowMaxY); + + /** Get the initialization state of the object. + * + * @return true iff the object has been initialized. + */ + bool isInitialized() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(CVolumeGeometry2D*) const; + + /** Get the number of columns in the volume grid. + * + * @return Number of columns in the volume grid. + */ + int getGridColCount() const; + + /** Get the number of rows in the volume grid. + * + * @return Number of rows in the volume grid. + */ + int getGridRowCount() const; + + /** Get the total number of pixels in the volume grid. + * + * @return Total number of pixels. + */ + int getGridTotCount() const; + + /** Get the horizontal length of the volume window, in unit lengths. + * + * @return Horizontal length of the volume window. + */ + float32 getWindowLengthX() const; + + /** Get the vertical length of the volume window, in unit lengths. + * + * @return Vertical length of the volume window. + */ + float32 getWindowLengthY() const; + + /** Get the total area of the volume window, in unit lengths squared. + * + * @return Total area of the volume window. + */ + float32 getWindowArea() const; + + /** Get the horizontal length of a single pixel (i.e., width), in unit lengths. + * + * @return Horizontal length of a single pixel. + */ + float32 getPixelLengthX() const; + + /** Get the vertical length of a single pixel (i.e., height), in unit lengths. + * + * @return Vertical length of a single pixel. + */ + float32 getPixelLengthY() const; + + /** Get the area of a single pixel (width*height), in unit lengths squared. + * + * @return Area of a single pixel. + */ + float32 getPixelArea() const; + + /** Get the minimal X-coordinate in the volume window. + * + * @return Minimal X-coordinate in the volume window. + */ + float32 getWindowMinX() const; + + /** Get the minimal Y-coordinate in the volume window. + * + * @return Minimal Y-coordinate in the volume window. + */ + float32 getWindowMinY() const; + + /** Get the maximal X-coordinate in the volume window. + * + * @return Maximal X-coordinate in the volume window. + */ + float32 getWindowMaxX() const; + + /** Get the maximal Y-coordinate in the volume window. + * + * @return Maximal Y-coordinate in the volume window. + */ + float32 getWindowMaxY() const; + + /** Convert column and row index of a pixel to a single index in the interval [0..getGridTotCount()-1]. + * + * @param _iPixelCol Column index of the pixel, in the interval [0..getGridColCount()-1]. + * @param _iPixelRow Row index of the pixel, in the interval [0..getGridRowCount()-1]. + * @return Computed index of the pixel, in the interval [0..getGridTotCount()-1]. + */ + int pixelRowColToIndex(int _iPixelRow, int _iPixelCol) const; + + /** Convert a pixel index (from the interval [0..getGridTotCount()-1] to a column and row index. + * + * @param _iPixelIndex Index of the pixel, in the interval [0..getGridTotCount()-1]. + * @param _iPixelRow Computed row index of the pixel, in the interval [0..getGridRowCount()-1]. + * @param _iPixelCol Computed column index of the pixel, in the interval [0..getGridColCount()-1]. + */ + void pixelIndexToRowCol(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol) const; + + /** Convert a pixel column index to the X-coordinate of its center. + * + * @param _iPixelCol Column index of the pixel. + * @return X-coordinate of the pixel center. + */ + float32 pixelColToCenterX(int _iPixelCol) const; + + /** Convert a pixel column index to the minimum X-coordinate of points in that column. + * + * @param _iPixelCol Column index of the pixel. + * @return Minimum X-coordinate. + */ + float32 pixelColToMinX(int _iPixelCol) const; + + /** Convert a pixel column index to the maximum X-coordinate of points in that column. + * + * @param _iPixelCol Column index of the pixel. + * @return Maximum X-coordinate. + */ + float32 pixelColToMaxX(int _iPixelCol) const; + + /** Convert a pixel row index to the Y-coordinate of its center. + * + * @param _iPixelRow Row index of the pixel. + * @return Y-coordinate of the pixel center. + */ + float32 pixelRowToCenterY(int _iPixelRow) const; + + /** Convert a pixel row index to the minimum Y-coordinate of points in that row. + * + * @param _iPixelRow Row index of the pixel. + * @return Minimum Y-coordinate. + */ + float32 pixelRowToMinY(int _iPixelRow) const; + + /** Convert a pixel row index to the maximum Y-coordinate of points in that row. + * + * @param _iPixelRow Row index of the pixel. + * @return Maximum Y-coordinate. + */ + float32 pixelRowToMaxY(int _iPixelRow) const; + + /** Convert an X-coordinate to a column index in the volume grid. + * + * @param _fCoordX X-coordinate. + * @return If the X-coordinate falls within a column of the volume grid, the column index is returned. + * Otherwise, a value of -1 is returned. + */ + int coordXToCol(float32 _fCoordX) const; + + /** Convert a Y-coordinate to a row index in the volume grid. + * + * @param _fCoordY Y-coordinate + * @return If the Y-coordinate falls within a row of the volume grid, the row index is returned. + * Otherwise, a value of -1 is returned. + */ + int coordYToRow(float32 _fCoordY) const; + + /** Convert an X-coordinate to an offset in the volume grid. + * WindowMinX is converted to 0. + * + * @param _fCoordX X-coordinate. + * @return The corresponding offset in the volume grid + */ + float coordXToColF(float32 _fCoordX) const; + + /** Convert a Y-coordinate to an offset in the volume grid. + * WindowMaxY is converted to 0. + * + * @param _fCoordY Y-coordinate + * @return The corresponding offset in the volume grid + */ + float coordYToRowF(float32 _fCoordY) const; + + + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CVolumeGeometry2D>; +}; + + + +// Get the initialization state of the object. +inline bool CVolumeGeometry2D::isInitialized() const +{ + return m_bInitialized; +} + +// Get the number of columns in the volume grid. +inline int CVolumeGeometry2D::getGridColCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridColCount; +} + +// Get the number of rows in the volume grid. +inline int CVolumeGeometry2D::getGridRowCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridRowCount; +} + +// Get the total number of pixels in the volume window. +inline int CVolumeGeometry2D::getGridTotCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridTotCount; +} + +// Get the horizontal length of the volume window, in unit lengths. +inline float32 CVolumeGeometry2D::getWindowLengthX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowLengthX; +} + +// Get the vertical length of the volume window, in unit lengths. +inline float32 CVolumeGeometry2D::getWindowLengthY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowLengthY; +} + +// Get the total area of the volume window, in unit lengths squared. +inline float32 CVolumeGeometry2D::getWindowArea() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowArea; +} + +// Get the horizontal length of a single pixel (i.e., width), in unit lengths. +inline float32 CVolumeGeometry2D::getPixelLengthX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelLengthX; +} + +// Get the vertical length of a single pixel (i.e., height), in unit lengths. +inline float32 CVolumeGeometry2D::getPixelLengthY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelLengthY; +} + +// Get the area of a single pixel (width*height), in unit lengths squared. +inline float32 CVolumeGeometry2D::getPixelArea() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelArea; +} + + // Get the minimal X-coordinate in the volume window. +inline float32 CVolumeGeometry2D::getWindowMinX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMinX; +} + + // Get the minimal Y-coordinate in the volume window. +inline float32 CVolumeGeometry2D::getWindowMinY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMinY; +} + + // Get the maximal X-coordinate in the volume window. +inline float32 CVolumeGeometry2D::getWindowMaxX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMaxX; +} + + // Get the maximal Y-coordinate in the volume window. +inline float32 CVolumeGeometry2D::getWindowMaxY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMaxY; +} + +// Convert column and row index of a pixel to a single index in the interval [0..getGridCountTot()-1]. +inline int CVolumeGeometry2D::pixelRowColToIndex(int _iPixelRow, int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + return (_iPixelRow * m_iGridColCount + _iPixelCol); +} + + +// Convert a pixel index (from the interval [0..getGridCountTot()-1] to a column and row index. +inline void CVolumeGeometry2D::pixelIndexToRowCol(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelIndex >= 0); + ASTRA_ASSERT(_iPixelIndex < m_iGridTotCount); + + _iPixelCol = (_iPixelIndex % m_iGridColCount); + _iPixelRow = (_iPixelIndex / m_iGridColCount); +} + +// Convert a pixel column index to the X-coordinate of its center +inline float32 CVolumeGeometry2D::pixelColToCenterX(int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + + return (m_fWindowMinX + (float32(_iPixelCol) + 0.5f) * m_fPixelLengthX); +} + +// Convert a pixel column index to the minimum X-coordinate of points in that column +inline float32 CVolumeGeometry2D::pixelColToMinX(int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + + return (m_fWindowMinX + float32(_iPixelCol) * m_fPixelLengthX); +} + +// Convert a pixel column index to the maximum X-coordinate of points in that column +inline float32 CVolumeGeometry2D::pixelColToMaxX(int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + + return (m_fWindowMinX + (float32(_iPixelCol) + 1.0f) * m_fPixelLengthX); +} + +// Convert a pixel row index to the Y-coordinate of its center +inline float32 CVolumeGeometry2D::pixelRowToCenterY(int _iPixelRow) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + + return (m_fWindowMaxY - (float32(_iPixelRow) + 0.5f) * m_fPixelLengthY); +} + +// Convert a pixel row index to the minimum Y-coordinate of points in that row +inline float32 CVolumeGeometry2D::pixelRowToMinY(int _iPixelRow) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + + return (m_fWindowMaxY - (float32(_iPixelRow) + 1.0f) * m_fPixelLengthY); +} + +// Convert a pixel row index to the maximum Y-coordinate of points in that row +inline float32 CVolumeGeometry2D::pixelRowToMaxY(int _iPixelRow) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + + return (m_fWindowMaxY - (float32(_iPixelRow) * m_fPixelLengthY)); +} + +// Convert an X-coordinate to a column index in the volume grid +inline int CVolumeGeometry2D::coordXToCol(float32 _fCoordX) const +{ + if (_fCoordX < m_fWindowMinX) return -1; + if (_fCoordX > m_fWindowMaxX) return -1; + + int iCol = int((_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX); + ASTRA_ASSERT(iCol >= 0); + ASTRA_ASSERT(iCol < m_iGridColCount); + + return iCol; +} + +// Convert a Y-coordinate to a row index in the volume grid +inline int CVolumeGeometry2D::coordYToRow(float32 _fCoordY) const +{ + if (_fCoordY < m_fWindowMinY) return -1; + if (_fCoordY > m_fWindowMaxY) return -1; + + int iRow = int((m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY); + ASTRA_ASSERT(iRow >= 0); + ASTRA_ASSERT(iRow < m_iGridRowCount); + + return iRow; +} + +// Convert an X-coordinate to an offset in the volume grid +// (WindowMinX is converted to 0) +inline float CVolumeGeometry2D::coordXToColF(float32 _fCoordX) const +{ + return (_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX; +} + +// Convert a Y-coordinate to an offset in the volume grid +// (WindowMaxY is converted to 0) +inline float CVolumeGeometry2D::coordYToRowF(float32 _fCoordY) const +{ + return (m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY; +} + + + +} // end namespace astra + +#endif /* _INC_ASTRA_VOLUMEGEOMETRY2D */ diff --git a/include/astra/VolumeGeometry3D.h b/include/astra/VolumeGeometry3D.h new file mode 100644 index 0000000..4ca8042 --- /dev/null +++ b/include/astra/VolumeGeometry3D.h @@ -0,0 +1,842 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_VOLUMEGEOMETRY3D +#define _INC_ASTRA_VOLUMEGEOMETRY3D + +#include "Globals.h" +#include "Config.h" +#include "VolumeGeometry2D.h" + +namespace astra +{ + +/** + * This class represents a 3D pixel grid that is placed in the geometry. It defines a rectangular volume window. + * + * \par XML Configuration + * \astra_xml_item{GridColCount, integer, Number of columns in this geometry.} + * \astra_xml_item{GridRowCount, integer, Number of rows in this geometry.} + * \astra_xml_item{GridSliceCount, integer, Number of slices in this geometry.} + * \astra_xml_item_option{WindowMinX, float, -GridColCount/2, Minimal X-coordinate in the volume window.} + * \astra_xml_item_option{WindowMaxX, float, GridColCount/2, Maximal X-coordinate in the volume window.} + * \astra_xml_item_option{WindowMinY, float, -GridRowCount/2, Minimal Y-coordinate in the volume window.} + * \astra_xml_item_option{WindowMaxY, float, GridRowCount/2, Maximal Y-coordinate in the volume window.} + * \astra_xml_item_option{WindowMinZ, float, -GridSliceCount/2, Minimal Z-coordinate in the volume window.} + * \astra_xml_item_option{WindowMaxZ, float, GridSliceCount/2, Maximal Z-coordinate in the volume window.} + * + * \par MATLAB example + * \astra_code{ + * vol_geom = struct();\n + * vol_geom.GridColCount = 1024;\n + * vol_geom.GridRowCount = 768;\n + * vol_geom.GridSliceCount = 300;\n + * vol_geom.option.WindowMinX = -512;\n + * vol_geom.option.WindowMaxX = -384;\n + * vol_geom.option.WindowMinY = 512;\n + * vol_geom.option.WindowMaxY = 384;\n + * vol_geom.option.WindowMinZ = -150;\n + * vol_geom.option.WindowMaxZ = 150;\n + * } + */ +class _AstraExport CVolumeGeometry3D { + +protected: + bool m_bInitialized; ///< Has this object been initialized? + + int m_iGridColCount; ///< number of columns in the volume grid. + int m_iGridRowCount; ///< number of rows in the volume grid. + int m_iGridSliceCount; ///< number of slices in the volume grid. + int m_iGridTotCount; ///< total number of pixels in the volume grid (= m_iGridColCount * m_iGridRowCount * m_iGridSliceCount). + + /** Width of the volume window, in unit lengths. + * + * Note that this width is independent of the number of pixels in the X-direction, as the width of a pixel can + * be different from 1. + */ + float32 m_fWindowLengthX; + + /** Height of the volume window, in unit lengths. + * + * Note that this height is independent of the number of pixels in the Y-direction, as the height of a pixel can + * be different from 1. + */ + float32 m_fWindowLengthY; + + /** Depth of the volume window, in unit lengths. + * + * Note that this depth is independent of the number of pixels in the Z-direction, as the depth of a pixel can + * be different from 1. + */ + float32 m_fWindowLengthZ; + + /** Total area of the volume window, in unit lengths squared. + */ + float32 m_fWindowArea; + + float32 m_fPixelLengthX; ///< Width of a single pixel, in unit lengths. + float32 m_fPixelLengthY; ///< Height of a single pixel, in unit lengths. + float32 m_fPixelLengthZ; ///< Depth of a single pixel, in unit lengths. + float32 m_fPixelArea; ///< Area of a single pixel, in unit lengths squared. + + float32 m_fDivPixelLengthX; ///< 1/m_fPixelLengthX, used for fast division. + float32 m_fDivPixelLengthY; ///< 1/m_fPixelLengthY, used for fast division. + float32 m_fDivPixelLengthZ; ///< 1/m_fPixelLengthZ, used for fast division. + + float32 m_fWindowMinX; ///< Minimal X-coordinate in the volume window. + float32 m_fWindowMinY; ///< Minimal Y-coordinate in the volume window. + float32 m_fWindowMinZ; ///< Minimal Z-coordinate in the volume window. + float32 m_fWindowMaxX; ///< Maximal X-coordinate in the volume window. + float32 m_fWindowMaxY; ///< Maximal Y-coordinate in the volume window. + float32 m_fWindowMaxZ; ///< Maximal Z-coordinate in the volume window. + + /** Check the values of this object. If everything is ok, the object can be set to the initialized state. + * The following statements are then guaranteed to hold: + * - number of rows, columns and slices is larger than zero + * - window minima is smaller than window maxima + * - m_iGridTotCount, m_fWindowLengthX, m_fWindowLengthY, m_fWindowLengthZ, m_fWindowArea, m_fPixelLengthX, + * m_fPixelLengthY, m_fPixelLengthZ, m_fPixelArea, m_fDivPixelLengthX, m_fDivPixelLengthY + * and m_fDivPixelLengthZ are initialized ok + */ + bool _check(); + +public: + + /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL. + * + * If an object is constructed using this default constructor, it must always be followed by a call + * to one of the init() methods before the object can be used. Any use before calling init() is not allowed, + * except calling the member function isInitialized(). + */ + CVolumeGeometry3D(); + + /** Constructor. Create an instance of the CVolumeGeometry2D class. + * The minimal and coordinates values of the geometry will be set to -/+ the number of rows/columns. + * + * @param _iGridCountX Number of columns in the volume grid. + * @param _iGridCountY Number of rows in the volume grid. + * @param _iGridCountZ Number of slices in the volume grid. + */ + CVolumeGeometry3D(int _iGridCountX, int _iGridCountY, int _iGridCountZ); + + /** Constructor. Create an instance of the CVolumeGeometry2D class. + * + * @param _iGridCountX Number of columns in the volume grid. + * @param _iGridCountY Number of rows in the volume grid. + * @param _iGridCountZ Number of slices in the volume grid. + * @param _fWindowMinX Minimal X-coordinate in the volume window. + * @param _fWindowMinY Minimal Y-coordinate in the volume window. + * @param _fWindowMinZ Minimal Z-coordinate in the volume window. + * @param _fWindowMaxX Maximal X-coordinate in the volume window. + * @param _fWindowMaxY Maximal Y-coordinate in the volume window. + * @param _fWindowMaxZ Maximal Z-coordinate in the volume window. + */ + CVolumeGeometry3D(int _iGridCountX, + int _iGridCountY, + int _iGridCountZ, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMinZ, + float32 _fWindowMaxX, + float32 _fWindowMaxY, + float32 _fWindowMaxZ); + + /** + * Copy constructor + */ + CVolumeGeometry3D(const CVolumeGeometry3D& _other); + + /** + * Assignment operator + */ + CVolumeGeometry3D& operator=(const CVolumeGeometry3D& _other); + + /** Destructor. + */ + virtual ~CVolumeGeometry3D(); + + /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. + */ + void clear(); + + /** Create a hard copy. + */ + CVolumeGeometry3D* clone() const; + + /** Initialize the volume geometry with a config object. + * + * @param _cfg Configuration Object. + * @return initialization successful? + */ + virtual bool initialize(const Config& _cfg); + + /** Initialization. Initializes an instance of the CVolumeGeometry3D class. + * The minimal and maximal coordinates of the geometry will be set to -/+ half the number of rows/columns/slices. + * + * If the object has been initialized before, the object is reinitialized and + * memory is freed and reallocated if necessary. + * + * @param _iGridColCount Number of columns in the volume grid. + * @param _iGridRowCount Number of rows in the volume grid. + * @param _iGridSliceCount Number of slices in the volume grid. + * @return initialization successful + */ + bool initialize(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount); + + /** Initialization. Initializes an instance of the CVolumeGeometry3D class. + * + * If the object has been initialized before, the object is reinitialized and + * memory is freed and reallocated if necessary. + * + * @param _iGridColCount Number of columns in the volume grid. + * @param _iGridRowCount Number of rows in the volume grid. + * @param _iGridSliceCount Number of slices in the volume grid. + * @param _fWindowMinX Minimal X-coordinate in the volume window. + * @param _fWindowMinY Minimal Y-coordinate in the volume window. + * @param _fWindowMinZ Minimal Z-coordinate in the volume window. + * @param _fWindowMaxX Maximal X-coordinate in the volume window. + * @param _fWindowMaxY Maximal Y-coordinate in the volume window. + * @param _fWindowMaxZ Maximal Z-coordinate in the volume window. + * @return initialization successful + */ + bool initialize(int _iGridColCount, + int _iGridRowCount, + int _iGridSliceCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMinZ, + float32 _fWindowMaxX, + float32 _fWindowMaxY, + float32 _fWindowMaxZ); + + /** Get the initialization state of the object. + * + * @return true iff the object has been initialized. + */ + bool isInitialized() const; + + /** Return true if this geometry instance is the same as the one specified. + * + * @return true if this geometry instance is the same as the one specified. + */ + virtual bool isEqual(const CVolumeGeometry3D*) const; + + /** Get the number of columns in the volume grid. + * + * @return Number of columns in the volume grid. + */ + int getGridColCount() const; + + /** Get the number of rows in the volume grid. + * + * @return Number of rows in the volume grid. + */ + int getGridRowCount() const; + + /** Get the number of slices in the volume grid. + * + * @return Number of slices in the volume grid. + */ + int getGridSliceCount() const; + + /** Get the total number of pixels in the volume grid. + * + * @return Total number of pixels. + */ + int getGridTotCount() const; + + /** Get the horizontal length of the volume window, in unit lengths. + * + * @return Horizontal length of the volume window. + */ + float32 getWindowLengthX() const; + + /** Get the vertical length of the volume window, in unit lengths. + * + * @return Vertical length of the volume window. + */ + float32 getWindowLengthY() const; + + /** Get the depth of the volume window, in unit lengths. + * + * @return Depth of the volume window. + */ + float32 getWindowLengthZ() const; + + /** Get the total area of the volume window, in unit lengths squared. + * + * @return Total area of the volume window. + */ + float32 getWindowArea() const; + + /** Get the horizontal length of a single pixel (i.e., width), in unit lengths. + * + * @return Horizontal length of a single pixel. + */ + float32 getPixelLengthX() const; + + /** Get the vertical length of a single pixel (i.e., height), in unit lengths. + * + * @return Vertical length of a single pixel. + */ + float32 getPixelLengthY() const; + + /** Get the depth of a single pixel in unit lengths. + * + * @return Depth of a single pixel. + */ + float32 getPixelLengthZ() const; + + /** Get the area of a single pixel (width*height*depth), in unit lengths squared. + * + * @return Area of a single pixel. + */ + float32 getPixelArea() const; + + /** Get the minimal X-coordinate in the volume window. + * + * @return Minimal X-coordinate in the volume window. + */ + float32 getWindowMinX() const; + + /** Get the minimal Y-coordinate in the volume window. + * + * @return Minimal Y-coordinate in the volume window. + */ + float32 getWindowMinY() const; + + /** Get the minimal Z-coordinate in the volume window. + * + * @return Minimal Z-coordinate in the volume window. + */ + float32 getWindowMinZ() const; + + /** Get the maximal X-coordinate in the volume window. + * + * @return Maximal X-coordinate in the volume window. + */ + float32 getWindowMaxX() const; + + /** Get the maximal Y-coordinate in the volume window. + * + * @return Maximal Y-coordinate in the volume window. + */ + float32 getWindowMaxY() const; + + /** Get the maximal Z-coordinate in the volume window. + * + * @return Maximal Z-coordinate in the volume window. + */ + float32 getWindowMaxZ() const; + + /** Convert row, column and slice index of a pixel to a single index in the interval [0..getGridTotCount()-1]. + * + * @param _iPixelRow Row index of the pixel, in the interval [0..getGridRowCount()-1]. + * @param _iPixelCol Column index of the pixel, in the interval [0..getGridColCount()-1]. + * @param _iPixelSlice Slice index of the pixel, in the interval [0..getGridSliceCount()-1]. + * @return Computed index of the pixel, in the interval [0..getGridTotCount()-1]. + */ + int pixelRowColSliceToIndex(int _iPixelRow, int _iPixelCol, int _iPixelSlice) const; + + /** Convert a pixel index (from the interval [0..getGridTotCount()-1] to row, column and slice index. + * + * @param _iPixelIndex Index of the pixel, in the interval [0..getGridTotCount()-1]. + * @param _iPixelRow Computed row index of the pixel, in the interval [0..getGridRowCount()-1]. + * @param _iPixelCol Computed column index of the pixel, in the interval [0..getGridColCount()-1]. + * @param _iPixelSlice Computed slice index of the pixel, in the interval [0..getGridSliceCount()-1]. + */ + void pixelIndexToRowColSlice(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol, int &_iPixelSlice) const; + + /** Convert a pixel column index to the X-coordinate of its center. + * + * @param _iPixelCol Column index of the pixel. + * @return X-coordinate of the pixel center. + */ + float32 pixelColToCenterX(int _iPixelCol) const; + + /** Convert a pixel column index to the minimum X-coordinate of points in that column. + * + * @param _iPixelCol Column index of the pixel. + * @return Minimum X-coordinate. + */ + float32 pixelColToMinX(int _iPixelCol) const; + + /** Convert a pixel column index to the maximum X-coordinate of points in that column. + * + * @param _iPixelCol Column index of the pixel. + * @return Maximum X-coordinate. + */ + float32 pixelColToMaxX(int _iPixelCol) const; + + /** Convert a pixel row index to the Y-coordinate of its center. + * + * @param _iPixelRow Row index of the pixel. + * @return Y-coordinate of the pixel center. + */ + float32 pixelRowToCenterY(int _iPixelRow) const; + + /** Convert a pixel row index to the minimum Y-coordinate of points in that row. + * + * @param _iPixelRow Row index of the pixel. + * @return Minimum Y-coordinate. + */ + float32 pixelRowToMinY(int _iPixelRow) const; + + /** Convert a pixel row index to the maximum Y-coordinate of points in that row. + * + * @param _iPixelRow Row index of the pixel. + * @return Maximum Y-coordinate. + */ + float32 pixelRowToMaxY(int _iPixelRow) const; + + /** Convert a pixel slice index to the Z-coordinate of its center. + * + * @param _iPixelSlice Slice index of the pixel. + * @return Z-coordinate of the pixel center. + */ + float32 pixelSliceToCenterZ(int _iPixelSlice) const; + + /** Convert a pixel slice index to the minimum Z-coordinate of points in that slice. + * + * @param _iPixelSlice Slice index of the pixel. + * @return Minimum Z-coordinate. + */ + float32 pixelSliceToMinZ(int _iPixelSlice) const; + + /** Convert a pixel slice index to the maximum Z-coordinate of points in that slice. + * + * @param _iPixelSlice Slice index of the pixel. + * @return Maximum Z-coordinate. + */ + float32 pixelSliceToMaxZ(int _iPixelSlice) const; + + /** Convert an X-coordinate to a column index in the volume grid. + * + * @param _fCoordX X-coordinate. + * @return If the X-coordinate falls within a column of the volume grid, the column index is returned. + * Otherwise, a value of -1 is returned. + */ + int coordXToCol(float32 _fCoordX) const; + + /** Convert a Y-coordinate to a row index in the volume grid. + * + * @param _fCoordY Y-coordinate + * @return If the Y-coordinate falls within a row of the volume grid, the row index is returned. + * Otherwise, a value of -1 is returned. + */ + int coordYToRow(float32 _fCoordY) const; + + /** Convert a Z-coordinate to a slice index in the volume grid. + * + * @param _fCoordZ Z-coordinate + * @return If the Z-coordinate falls within a slice of the volume grid, the slice index is returned. + * Otherwise, a value of -1 is returned. + */ + int coordZToSlice(float32 _fCoordZ) const; + + /** Convert an X-coordinate to a column index in the volume grid. + * + * @param _fCoordX X-coordinate. + * @return If the X-coordinate falls within a column of the volume grid, the column index is returned. + * Otherwise, a value of -1 is returned. + */ + float32 coordXToColFloat(float32 _fCoordX) const; + + /** Convert a Y-coordinate to a row index in the volume grid. + * + * @param _fCoordY Y-coordinate + * @return If the Y-coordinate falls within a row of the volume grid, the row index is returned. + * Otherwise, a value of -1 is returned. + */ + float32 coordYToRowFloat(float32 _fCoordY) const; + + /** Convert a Z-coordinate to a slice index in the volume grid. + * + * @param _fCoordZ Z-coordinate + * @return If the Z-coordinate falls within a slice of the volume grid, the slice index is returned. + * Otherwise, a value of -1 is returned. + */ + float32 coordZToSliceFloat(float32 _fCoordZ) const; + + CVolumeGeometry2D * createVolumeGeometry2D() const; + + + //< For Config unused argument checking + ConfigCheckData* configCheckData; + friend class ConfigStackCheck<CVolumeGeometry3D>; +}; + + +//---------------------------------------------------------------------------------------- +// Get the initialization state of the object. +inline bool CVolumeGeometry3D::isInitialized() const +{ + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get the number of columns in the volume grid. +inline int CVolumeGeometry3D::getGridColCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridColCount; +} + +//---------------------------------------------------------------------------------------- +// Get the number of rows in the volume grid. +inline int CVolumeGeometry3D::getGridRowCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridRowCount; +} + +//---------------------------------------------------------------------------------------- +// Get the number of rows in the volume grid. +inline int CVolumeGeometry3D::getGridSliceCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridSliceCount; +} + +//---------------------------------------------------------------------------------------- +// Get the total number of pixels in the volume window. +inline int CVolumeGeometry3D::getGridTotCount() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_iGridTotCount; +} + +//---------------------------------------------------------------------------------------- +// Get the horizontal length of the volume window, in unit lengths. +inline float32 CVolumeGeometry3D::getWindowLengthX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowLengthX; +} + +//---------------------------------------------------------------------------------------- +// Get the vertical length of the volume window, in unit lengths. +inline float32 CVolumeGeometry3D::getWindowLengthY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowLengthY; +} + +//---------------------------------------------------------------------------------------- +// Get the vertical length of the volume window, in unit lengths. +inline float32 CVolumeGeometry3D::getWindowLengthZ() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowLengthZ; +} + +//---------------------------------------------------------------------------------------- +// Get the total area of the volume window, in unit lengths squared. +inline float32 CVolumeGeometry3D::getWindowArea() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowArea; +} + +//---------------------------------------------------------------------------------------- +// Get the horizontal length of a single pixel (i.e., width), in unit lengths. +inline float32 CVolumeGeometry3D::getPixelLengthX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelLengthX; +} + +//---------------------------------------------------------------------------------------- +// Get the vertical length of a single pixel (i.e., height), in unit lengths. +inline float32 CVolumeGeometry3D::getPixelLengthY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelLengthY; +} + +//---------------------------------------------------------------------------------------- +// Get the depth of a single pixel in unit lengths. +inline float32 CVolumeGeometry3D::getPixelLengthZ() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelLengthZ; +} + +//---------------------------------------------------------------------------------------- +// Get the area of a single pixel (width*height), in unit lengths squared. +inline float32 CVolumeGeometry3D::getPixelArea() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fPixelArea; +} + +//---------------------------------------------------------------------------------------- +// Get the minimal X-coordinate in the volume window. +inline float32 CVolumeGeometry3D::getWindowMinX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMinX; +} + +//---------------------------------------------------------------------------------------- +// Get the minimal Y-coordinate in the volume window. +inline float32 CVolumeGeometry3D::getWindowMinY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMinY; +} + +//---------------------------------------------------------------------------------------- +// Get the minimal Y-coordinate in the volume window. +inline float32 CVolumeGeometry3D::getWindowMinZ() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMinZ; +} + +//---------------------------------------------------------------------------------------- +// Get the maximal X-coordinate in the volume window. +inline float32 CVolumeGeometry3D::getWindowMaxX() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMaxX; +} + +//---------------------------------------------------------------------------------------- +// Get the maximal Y-coordinate in the volume window. +inline float32 CVolumeGeometry3D::getWindowMaxY() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMaxY; +} + +//---------------------------------------------------------------------------------------- +// Get the maximal Z-coordinate in the volume window. +inline float32 CVolumeGeometry3D::getWindowMaxZ() const +{ + ASTRA_ASSERT(m_bInitialized); + return m_fWindowMaxZ; +} + +//---------------------------------------------------------------------------------------- +// Convert row, column and slice index of a pixel to a single index in the interval [0..getGridCountTot()-1]. +inline int CVolumeGeometry3D::pixelRowColSliceToIndex(int _iPixelRow, int _iPixelCol, int _iPixelSlice) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + ASTRA_ASSERT(_iPixelSlice >= 0); + ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount); + + return (m_iGridColCount*m_iGridRowCount*_iPixelSlice + _iPixelRow * m_iGridColCount + _iPixelCol); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel index (from the interval [0..getGridCountTot()-1] to a row, column and slice index. +inline void CVolumeGeometry3D::pixelIndexToRowColSlice(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol, int &_iPixelSlice) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelIndex >= 0); + ASTRA_ASSERT(_iPixelIndex < m_iGridTotCount); + + _iPixelSlice = _iPixelIndex / (m_iGridRowCount*m_iGridColCount); + _iPixelRow = (_iPixelIndex-_iPixelSlice*m_iGridRowCount*m_iGridColCount) / m_iGridColCount; + _iPixelCol = (_iPixelIndex-_iPixelSlice*m_iGridRowCount*m_iGridColCount) % m_iGridColCount; +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel column index to the X-coordinate of its center +inline float32 CVolumeGeometry3D::pixelColToCenterX(int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + + return (m_fWindowMinX + (float32(_iPixelCol) + 0.5f) * m_fPixelLengthX); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel column index to the minimum X-coordinate of points in that column +inline float32 CVolumeGeometry3D::pixelColToMinX(int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + + return (m_fWindowMinX + float32(_iPixelCol) * m_fPixelLengthX); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel column index to the maximum X-coordinate of points in that column +inline float32 CVolumeGeometry3D::pixelColToMaxX(int _iPixelCol) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelCol >= 0); + ASTRA_ASSERT(_iPixelCol < m_iGridColCount); + + return (m_fWindowMaxX + (float32(_iPixelCol) + 1.0f) * m_fPixelLengthX); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel row index to the Y-coordinate of its center +inline float32 CVolumeGeometry3D::pixelRowToCenterY(int _iPixelRow) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + + return (m_fWindowMaxY - (float32(_iPixelRow) + 0.5f) * m_fPixelLengthY); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel row index to the minimum Y-coordinate of points in that row +inline float32 CVolumeGeometry3D::pixelRowToMinY(int _iPixelRow) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + + return (m_fWindowMaxY - (float32(_iPixelRow) + 1.0f) * m_fPixelLengthY); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel row index to the maximum Y-coordinate of points in that row +inline float32 CVolumeGeometry3D::pixelRowToMaxY(int _iPixelRow) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelRow >= 0); + ASTRA_ASSERT(_iPixelRow < m_iGridRowCount); + + return (m_fWindowMaxY - (float32(_iPixelRow) * m_fPixelLengthY)); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel slice index to the Z-coordinate of its center +inline float32 CVolumeGeometry3D::pixelSliceToCenterZ(int _iPixelSlice) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelSlice >= 0); + ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount); + + return (m_fWindowMaxZ - (float32(_iPixelSlice) + 0.5f) * m_fPixelLengthZ); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel row index to the minimum Y-coordinate of points in that row +inline float32 CVolumeGeometry3D::pixelSliceToMinZ(int _iPixelSlice) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelSlice >= 0); + ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount); + + return (m_fWindowMaxZ - (float32(_iPixelSlice) + 1.0f) * m_fPixelLengthZ); +} + +//---------------------------------------------------------------------------------------- +// Convert a pixel row index to the maximum Y-coordinate of points in that row +inline float32 CVolumeGeometry3D::pixelSliceToMaxZ(int _iPixelSlice) const +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_iPixelSlice >= 0); + ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount); + + return (m_fWindowMaxZ - (float32(_iPixelSlice) * m_fPixelLengthZ)); +} + +//---------------------------------------------------------------------------------------- +// Convert an X-coordinate to a column index in the volume grid +inline int CVolumeGeometry3D::coordXToCol(float32 _fCoordX) const +{ + if (_fCoordX < m_fWindowMinX) return -1; + if (_fCoordX > m_fWindowMaxX) return -1; + + int iCol = int((_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX); + ASTRA_ASSERT(iCol >= 0); + ASTRA_ASSERT(iCol < m_iGridColCount); + + return iCol; +} + +//---------------------------------------------------------------------------------------- +// Convert a Y-coordinate to a row index in the volume grid +inline int CVolumeGeometry3D::coordYToRow(float32 _fCoordY) const +{ + if (_fCoordY < m_fWindowMinY) return -1; + if (_fCoordY > m_fWindowMaxY) return -1; + + int iRow = int((m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY); + ASTRA_ASSERT(iRow >= 0); + ASTRA_ASSERT(iRow < m_iGridRowCount); + + return iRow; +} + +//---------------------------------------------------------------------------------------- +// Convert a Z-coordinate to a slice index in the volume grid +inline int CVolumeGeometry3D::coordZToSlice(float32 _fCoordZ) const +{ + if (_fCoordZ < m_fWindowMinZ) return -1; + if (_fCoordZ > m_fWindowMaxZ) return -1; + + int iSlice = int((m_fWindowMaxZ - _fCoordZ) * m_fDivPixelLengthZ); + ASTRA_ASSERT(iSlice >= 0); + ASTRA_ASSERT(iSlice < m_iGridSliceCount); + + return iSlice; +} + +//---------------------------------------------------------------------------------------- +// Convert an X-coordinate to a column index in the volume grid +inline float32 CVolumeGeometry3D::coordXToColFloat(float32 _fCoordX) const +{ + ASTRA_ASSERT(m_bInitialized); + return (_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX; +} + +//---------------------------------------------------------------------------------------- +// Convert a Y-coordinate to a row index in the volume grid +inline float32 CVolumeGeometry3D::coordYToRowFloat(float32 _fCoordY) const +{ + ASTRA_ASSERT(m_bInitialized); + return (m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY; +} + +//---------------------------------------------------------------------------------------- +// Convert a Z-coordinate to a slice index in the volume grid +inline float32 CVolumeGeometry3D::coordZToSliceFloat(float32 _fCoordZ) const +{ + ASTRA_ASSERT(m_bInitialized); + return (m_fWindowMaxZ - _fCoordZ) * m_fDivPixelLengthZ; +} +//---------------------------------------------------------------------------------------- + +} // end namespace astra + +#endif /* _INC_ASTRA_VOLUMEGEOMETRY2D */ diff --git a/include/astra/XMLDocument.h b/include/astra/XMLDocument.h new file mode 100644 index 0000000..dbcc679 --- /dev/null +++ b/include/astra/XMLDocument.h @@ -0,0 +1,101 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_XMLDOCUMENT +#define _INC_ASTRA_XMLDOCUMENT + +#include <string> + +#if 1 +namespace rapidxml { + template<class Ch> class xml_document; +} +#else +#include "rapidxml.hpp" +#endif + +#include "Globals.h" +#include "XMLNode.h" + +using namespace std; + +namespace astra { + +/** This class encapsulates an XML Document of the Xerces DOM Parser. + */ +class _AstraExport XMLDocument { + +public: + + /** Default Constructor + */ + XMLDocument(); + + /** Destructor + */ + ~XMLDocument(); + + /** Construct an XML DOM tree and Document from an XML file + * + * @param sFilename Location of the XML file. + * @return XML Document containing the DOM tree + */ + static XMLDocument* readFromFile(string sFilename); + + /** Construct an empty XML DOM tree with a specific root tag. + * + * @param sRootName Element name of the root tag. + * @return XML Document with an empty root node + */ + static XMLDocument* createDocument(string sRootName); + + /** Get the rootnode of the XML document + * + * @return first XML node of the document + */ + XMLNode* getRootNode(); + + /** Save an XML DOM tree to an XML file + * + * @param sFilename Location of the XML file. + */ + void saveToFile(string sFilename); + + +private: + + //!< Document of rapidxml + rapidxml::xml_document<char>* fDOMDocument; + + std::string fBuf; + +}; + +} // end namespace + +#endif diff --git a/include/astra/XMLNode.h b/include/astra/XMLNode.h new file mode 100644 index 0000000..3ed6417 --- /dev/null +++ b/include/astra/XMLNode.h @@ -0,0 +1,325 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_XMLNODE +#define _INC_ASTRA_XMLNODE + +#include <list> +#include <string> +#include <vector> + +#if 1 +namespace rapidxml { + template<class Ch> class xml_node; +} +#else +#include "rapidxml.hpp" +#endif + +#include "Globals.h" +#include "Utilities.h" + +using namespace std; + +namespace astra { + +/** + * This class encapsulates an XML Node of the Xerces DOM Parser. + */ +class _AstraExport XMLNode { + +friend class XMLDocument; + +public: + + /** Default Constructor + */ + XMLNode(); + + /** Deconstructor + */ + ~XMLNode(); + + + /** Get a single child XML node. If there are more, the first one is returned + * + * @param _sName tagname of the requested child node + * @return first child node with the correct tagname, null pointer if it doesn't exist + */ + XMLNode* getSingleNode(string _sName); + + /** Get all child XML nodes that have the tagname name + * + * @param _sName tagname of the requested child nodes + * @return list with all child nodes with the correct tagname + */ + std::list<XMLNode*> getNodes(string _sName); + + /** Get all child XML nodes + * + * @return list with all child nodes + */ + std::list<XMLNode*> getNodes(); + + /** Get the name of this node + * + * @return name of node + */ + std::string getName(); + + /** Get the content of the XML node as a single string. + * + * @return node content + */ + string getContent(); + + /** Get the content of the XML node as a numerical. + * + * @return node content + */ + float32 getContentNumerical(); + + /** Get the content of the XML node as a boolean. + * + * @return node content + */ + bool getContentBool(); + + /** Get the content of the XML node as a vector of strings. + * + * @return node content + */ + vector<string> getContentArray(); + + /** Get the content of the XML node as a c-array of float32 data. + * + * @param _pfData data array, shouldn't be initialized already. + * @param _iSize number of elements stored in _pfData + */ + void getContentNumericalArray(float32*& _pfData, int& _iSize); + + /** Get the content of the XML node as a stl container of float32 data. + * + * @return node content + */ + vector<float32> getContentNumericalArray(); + vector<double> getContentNumericalArrayDouble(); + + + + /** Does this node contain an attribute with a certain name? + * + * @param _sName of the attribute. + * @return attribute value, empty string if it doesn't exist. + */ + bool hasAttribute(string _sName); + + /** Get the value of an attribute. + * + * @param _sName of the attribute. + * @param _sDefaultValue value to return if the attribute isn't found + * @return attribute value, _sDefaultValue if it doesn't exist. + */ + string getAttribute(string _sName, string _sDefaultValue = ""); + + /** Get the value of a numerical attribute. + * + * @param _sName of the attribute. + * @param _fDefaultValue value to return if the attribute isn't found + * @return attribute value, _fDefaultValue if it doesn't exist. + */ + float32 getAttributeNumerical(string _sName, float32 _fDefaultValue = 0); + double getAttributeNumericalDouble(string _sName, double _fDefaultValue = 0); + + /** Get the value of a boolean attribute. + * + * @param _sName of the attribute. + * @param _bDefaultValue value to return if the attribute isn't found + * @return attribute value, _bDefaultValue if it doesn't exist. + */ + bool getAttributeBool(string _sName, bool _bDefaultValue = false); + + + + + /** Does this node contain an option with a certain key? + * + * @param _sKey option key + * @return true if option does exist + */ + bool hasOption(string _sKey); + + /** Get the value of an option within this XML Node + * + * @param _sKey option key + * @param _sDefaultValue value to return if key isn't found + * @return option value, _sDefaultValue if the option doesn't exist + */ + string getOption(string _sKey, string _sDefaultValue = ""); + + /** Get the value of an option within this XML Node + * + * @param _sKey option key + * @param _fDefaultValue value to return if key isn't found + * @return option value, _fDefaultValue if the option doesn't exist + */ + float32 getOptionNumerical(string _sKey, float32 _fDefaultValue = 0); + + /** Get the value of an option within this XML Node + * + * @param _sKey option key + * @param _bDefaultValue value to return if key isn't found + * @return option value, _bDefaultValue if the option doesn't exist + */ + bool getOptionBool(string _sKey, bool _bDefaultValue = false); + + /** Get the value of an option within this XML Node + * + * @param _sKey option key + * @return numerical array + */ + vector<float32> getOptionNumericalArray(string _sKey); + + + + + + /** Create a new XML node as a child to this one: <...><_sNodeName/></...> + * + * @param _sNodeName the name of the new childnode + * @return new child node + */ + XMLNode* addChildNode(string _sNodeName); + + /** Create a new XML node as a child to this one, also add some content: + * <...><_sNodeName>_sValue</_sNodeName></...> + * + * @param _sNodeName the name of the new childnode + * @param _sValue some node content + * @return new child node + */ + XMLNode* addChildNode(string _sNodeName, string _sValue); + + /** Create a new XML node as a child to this one, also add some numerical content: + * <...><_sNodeName>_sValue</_sNodeName></...> + * + * @param _sNodeName the name of the new childnode + * @param _fValue some node content + * @return new child node + */ + XMLNode* addChildNode(string _sNodeName, float32 _fValue); + + /** Create a new XML node as a child to this one, also add a list of numerical content: + * <...><_sNodeName>_sValue</_sNodeName></...> + * + * @param _sNodeName the name of the new childnode + * @param _pfList list data + * @param _iSize number of elements in _pfList + * @return new child node + */ + XMLNode* addChildNode(string _sNodeName, float32* _pfList, int _iSize); + + /** Add some text to the node: <...>_sText</...> + * + * @param _sText text to insert + */ + void setContent(string _sText); + + /** Add a number to the node: <...>_sText</...> + * + * @param _fValue number to insert + */ + void setContent(float32 _fValue); + + /** Add a list of numerical data to the node: <...>_sText</...> + * + * @param _pfList data + * @param _iSize number of elements in the list + */ + void setContent(float32* _pfList, int _iSize); + + /** Add an attribute to this node: <... _sName="_sValue"> + * + * @param _sName name of the attribute + * @param _sValue value of the attribute + */ + void addAttribute(string _sName, string _sValue); + + /** Add an attribute with numerical data to this node: <... _sName="_fValue"> + * + * @param _sName name of the attribute + * @param _sValue value of the attribute + */ + void addAttribute(string _sName, float32 _fValue); + + /** Add an option node as a child: <Option key="<_sKey>" value="<_sValue>"/> + * + * @param _sKey option key + * @param _sValue option value + */ + void addOption(string _sKey, string _sValue); + + /** Add an option node as a child: <Option key="<_sKey>" value="<_sValue>"/> + * + * @param _sKey option key + * @param _sValue option value + */ + void addOption(string _sKey, float32 _fValue); + + + /** Print to String + */ + std::string toString(); + + /** Print the node + */ + void print(); + +protected: + + /** Private Constructor. + * + * @param n rapidxml node + */ + XMLNode(rapidxml::xml_node<char>* n); + + /** Link this object to a rapidxml node + * @param n object of the Xerces C++ library + */ + void setDOMNode(rapidxml::xml_node<char>* n); + + // todo: rename "fDOMElement" to "m_fDOMElement"? + + //!< Node of rapidxml + rapidxml::xml_node<char>* fDOMElement; + +}; + +} // end namespace + +#endif diff --git a/include/astra/jama_wrapper.h b/include/astra/jama_wrapper.h new file mode 100644 index 0000000..2fbdef8 --- /dev/null +++ b/include/astra/jama_wrapper.h @@ -0,0 +1,35 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +// Wrapper include for jama header files + +#ifdef JAMA_NO_SUBDIR +#include "jama_lu.h" +#else +#include <tnt/jama_lu.h> +#endif diff --git a/include/astra/swrap.h b/include/astra/swrap.h new file mode 100644 index 0000000..af45838 --- /dev/null +++ b/include/astra/swrap.h @@ -0,0 +1,41 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_SWRAP_H +#define _INC_ASTRA_SWRAP_H + +#ifndef _MSC_VER + +#include <cstdio> + +typedef int errno_t; +errno_t fopen_s(FILE** pFile, const char *filename, const char *mode); + +#endif + +#endif diff --git a/lib/include/rapidxml/rapidxml.hpp b/lib/include/rapidxml/rapidxml.hpp new file mode 100644 index 0000000..ae91e08 --- /dev/null +++ b/lib/include/rapidxml/rapidxml.hpp @@ -0,0 +1,2596 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include <cstdlib> // For std::size_t + #include <cassert> // For assert + #include <new> // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //! <br><br> + //! This function cannot return. If it does, the results are undefined. + //! <br><br> + //! A very simple definition might look like that: + //! <pre> + //! void %rapidxml::%parse_error_handler(const char *what, void *where) + //! { + //! std::cout << "Parse error: " << what << "\n"; + //! std::abort(); + //! } + //! </pre> + //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include <exception> // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //! <br><br> + //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //! <br><br> + //! This class derives from <code>std::exception</code> class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template<class Ch> + Ch *where() const + { + return reinterpret_cast<Ch *>(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template<class Ch> class xml_node; + template<class Ch> class xml_attribute; + template<class Ch> class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //! <br><br> + //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a <i>negation</i> of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default, + //! and using the flag will disable it. + //! <br><br> + //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //! <ul> + //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li> + //! <li>entities will not be translated</li> + //! <li>whitespace will not be normalized</li> + //! </ul> + //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //! <br><br> + //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //! <br><br> + //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template<int Dummy> + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template<class Ch> + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template<class Ch> + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using <code>new</code> operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //! <br><br> + //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //! <br><br> + //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //! <br><br> + //! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each, + //! by using global <code>new[]</code> and <code>delete[]</code> operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //! <br><br> + //! Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes. + //! This value defaults to the size of pointer on target architecture. + //! <br><br> + //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code> + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template<class Ch = char> + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node<Ch> *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node<Ch>)); + xml_node<Ch> *node = new(memory) xml_node<Ch>(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute<Ch>)); + xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //! <br><br> + //! User defined allocation functions must have the following forms: + //! <br><code> + //! <br>void *allocate(std::size_t size); + //! <br>void free(void *pointer); + //! </code><br> + //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast<char *>(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast<header *>(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template<class Ch = char> + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //! <br><br> + //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //! <br><br> + //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //! <br><br> + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //! <br><br> + //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast<Ch *>(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //! <br><br> + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //! <br><br> + //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! <br><br> + //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast<Ch *>(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node<Ch> *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node<Ch> *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template<class Ch = char> + class xml_attribute: public xml_base<Ch> + { + + friend class xml_node<Ch>; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document<Ch> *document() const + { + if (xml_node<Ch> *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute<Ch> *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute<Ch> *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //! <br><br> + //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template<class Ch = char> + class xml_node: public xml_base<Ch> + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document<Ch> *document() const + { + xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node<Ch> *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node<Ch> *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node<Ch> *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node<Ch> *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node<Ch> *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node<Ch> *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node<Ch> *where, xml_node<Ch> *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node<Ch> *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node<Ch> *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node<Ch> *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute<Ch> *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute<Ch> *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute<Ch> *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute<Ch> *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute<Ch> *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node<Ch> *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node<Ch> *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute<Ch> *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute<Ch> *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node<Ch> *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node<Ch> *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template<class Ch = char> + class xml_document: public xml_node<Ch>, public memory_pool<Ch> + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node<Ch>(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //! <br><br> + //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //! <br><br> + //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template<int Flags> + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom<Flags>(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip<whitespace_pred, Flags>(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node<Ch> *node = parse_node<Flags>(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool<Ch>::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast<unsigned char>(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast<unsigned char>(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast<unsigned char>(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast<unsigned char>(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast<unsigned char>(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast<unsigned char>(ch)]; + } + }; + + // Detect attribute value character + template<Ch Quote> + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template<Ch Quote> + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template<int Flags> + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast<unsigned char>(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast<unsigned char>(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast<unsigned char>(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast<unsigned char>(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast<unsigned char>(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template<class StopPred, int Flags> + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template<class StopPred, class StopPredPure, int Flags> + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip<StopPred, Flags>(text); + return text; + } + + // Use simple skip until first modification is detected + skip<StopPredPure, Flags>(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character<Flags>(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character<Flags>(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template<int Flags> + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast<unsigned char>(text[0]) == 0xEF && + static_cast<unsigned char>(text[1]) == 0xBB && + static_cast<unsigned char>(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration (<?xml...) + template<int Flags> + xml_node<Ch> *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node<Ch> *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip<whitespace_pred, Flags>(text); + + // Parse declaration attributes + parse_node_attributes<Flags>(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (<!--...) + template<int Flags> + xml_node<Ch> *parse_comment(Ch *&text) + { + // If parsing of comments is disabled + if (!(Flags & parse_comment_nodes)) + { + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip '-->' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node<Ch> *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template<int Flags> + xml_node<Ch> *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node<Ch> *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template<int Flags> + xml_node<Ch> *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node<Ch> *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip<node_name_pred, Flags>(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip<whitespace_pred, Flags>(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template<int Flags> + Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text); + else + end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node<Ch> *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template<int Flags> + xml_node<Ch> *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node<Ch> *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template<int Flags> + xml_node<Ch> *parse_element(Ch *&text) + { + // Create element node + xml_node<Ch> *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip<node_name_pred, Flags>(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip<whitespace_pred, Flags>(text); + + // Parse attributes, if any + parse_node_attributes<Flags>(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents<Flags>(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template<int Flags> + xml_node<Ch> *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element<Flags>(text); + + // <?... + case Ch('?'): + ++text; // Skip ? + if ((text[0] == Ch('x') || text[0] == Ch('X')) && + (text[1] == Ch('m') || text[1] == Ch('M')) && + (text[2] == Ch('l') || text[2] == Ch('L')) && + whitespace_pred::test(text[3])) + { + // '<?xml ' - xml declaration + text += 4; // Skip 'xml ' + return parse_xml_declaration<Flags>(text); + } + else + { + // Parse PI + return parse_pi<Flags>(text); + } + + // <!... + case Ch('!'): + + // Parse proper subset of <! node + switch (text[1]) + { + + // <!- + case Ch('-'): + if (text[2] == Ch('-')) + { + // '<!--' - xml comment + text += 3; // Skip '!--' + return parse_comment<Flags>(text); + } + break; + + // <![ + case Ch('['): + if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') && + text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('[')) + { + // '<![CDATA[' - cdata + text += 8; // Skip '![CDATA[' + return parse_cdata<Flags>(text); + } + break; + + // <!D + case Ch('D'): + if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') && + text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') && + whitespace_pred::test(text[8])) + { + // '<!DOCTYPE ' - doctype + text += 9; // skip '!DOCTYPE ' + return parse_doctype<Flags>(text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with <! + ++text; // Skip ! + while (*text != Ch('>')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template<int Flags> + void parse_node_contents(Ch *&text, xml_node<Ch> *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip<whitespace_pred, Flags>(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '</' + if (Flags & parse_validate_closing_tags) + { + // Skip and validate closing tag name + Ch *closing_name = text; + skip<node_name_pred, Flags>(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip<node_name_pred, Flags>(text); + } + // Skip remaining whitespace after node name + skip<whitespace_pred, Flags>(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node<Ch> *child = parse_node<Flags>(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data<Flags>(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template<int Flags> + void parse_node_attributes(Ch *&text, xml_node<Ch> *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip<attribute_name_pred, Flags>(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute<Ch> *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip<whitespace_pred, Flags>(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip<whitespace_pred, Flags>(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text); + else + end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip<whitespace_pred, Flags>(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template<int Dummy> + const unsigned char lookup_tables<Dummy>::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/lib/include/rapidxml/rapidxml_print.hpp b/lib/include/rapidxml/rapidxml_print.hpp new file mode 100644 index 0000000..4432273 --- /dev/null +++ b/lib/include/rapidxml/rapidxml_print.hpp @@ -0,0 +1,424 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include <ostream> + #include <iterator> +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template<class OutIt, class Ch> + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template<class OutIt, class Ch> + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template<class OutIt, class Ch> + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template<class Ch, Ch ch> + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + template<class OutIt, class Ch> + inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent); + + // Print children of the node + template<class OutIt, class Ch> + inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template<class OutIt, class Ch> + inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags) + { + for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template<class OutIt, class Ch> + inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template<class OutIt, class Ch> + inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template<class OutIt, class Ch> + inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node<Ch> *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template<class OutIt, class Ch> + inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template<class OutIt, class Ch> + inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template<class OutIt, class Ch> + inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template<class OutIt, class Ch> + inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print node + template<class OutIt, class Ch> + inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template<class OutIt, class Ch> + inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template<class Ch> + inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0) + { + print(std::ostream_iterator<Ch>(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template<class Ch> + inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/lib/include/tnt/jama_cholesky.h b/lib/include/tnt/jama_cholesky.h new file mode 100644 index 0000000..371d2f7 --- /dev/null +++ b/lib/include/tnt/jama_cholesky.h @@ -0,0 +1,258 @@ +#ifndef JAMA_CHOLESKY_H +#define JAMA_CHOLESKY_H + +#include "math.h" + /* needed for sqrt() below. */ + + +namespace JAMA +{ + +using namespace TNT; + +/** + <P> + For a symmetric, positive definite matrix A, this function + computes the Cholesky factorization, i.e. it computes a lower + triangular matrix L such that A = L*L'. + If the matrix is not symmetric or positive definite, the function + computes only a partial decomposition. This can be tested with + the is_spd() flag. + + <p>Typical usage looks like: + <pre> + Array2D<double> A(n,n); + Array2D<double> L; + + ... + + Cholesky<double> chol(A); + + if (chol.is_spd()) + L = chol.getL(); + + else + cout << "factorization was not complete.\n"; + + </pre> + + + <p> + (Adapted from JAMA, a Java Matrix Library, developed by jointly + by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama). + + */ + +template <class Real> +class Cholesky +{ + Array2D<Real> L_; // lower triangular factor + int isspd; // 1 if matrix to be factored was SPD + +public: + + Cholesky(); + Cholesky(const Array2D<Real> &A); + Array2D<Real> getL() const; + Array1D<Real> solve(const Array1D<Real> &B); + Array2D<Real> solve(const Array2D<Real> &B); + int is_spd() const; + +}; + +template <class Real> +Cholesky<Real>::Cholesky() : L_(0,0), isspd(0) {} + +/** + @return 1, if original matrix to be factored was symmetric + positive-definite (SPD). +*/ +template <class Real> +int Cholesky<Real>::is_spd() const +{ + return isspd; +} + +/** + @return the lower triangular factor, L, such that L*L'=A. +*/ +template <class Real> +Array2D<Real> Cholesky<Real>::getL() const +{ + return L_; +} + +/** + Constructs a lower triangular matrix L, such that L*L'= A. + If A is not symmetric positive-definite (SPD), only a + partial factorization is performed. If is_spd() + evalutate true (1) then the factorizaiton was successful. +*/ +template <class Real> +Cholesky<Real>::Cholesky(const Array2D<Real> &A) +{ + + + int m = A.dim1(); + int n = A.dim2(); + + isspd = (m == n); + + if (m != n) + { + L_ = Array2D<Real>(0,0); + return; + } + + L_ = Array2D<Real>(n,n); + + + // Main loop. + for (int j = 0; j < n; j++) + { + Real d(0.0); + for (int k = 0; k < j; k++) + { + Real s(0.0); + for (int i = 0; i < k; i++) + { + s += L_[k][i]*L_[j][i]; + } + L_[j][k] = s = (A[j][k] - s)/L_[k][k]; + d = d + s*s; + isspd = isspd && (A[k][j] == A[j][k]); + } + d = A[j][j] - d; + isspd = isspd && (d > 0.0); + L_[j][j] = sqrt(d > 0.0 ? d : 0.0); + for (int k = j+1; k < n; k++) + { + L_[j][k] = 0.0; + } + } +} + +/** + + Solve a linear system A*x = b, using the previously computed + cholesky factorization of A: L*L'. + + @param B A Matrix with as many rows as A and any number of columns. + @return x so that L*L'*x = b. If b is nonconformat, or if A + was not symmetric posidtive definite, a null (0x0) + array is returned. +*/ +template <class Real> +Array1D<Real> Cholesky<Real>::solve(const Array1D<Real> &b) +{ + int n = L_.dim1(); + if (b.dim1() != n) + return Array1D<Real>(); + + + Array1D<Real> x = b.copy(); + + + // Solve L*y = b; + for (int k = 0; k < n; k++) + { + for (int i = 0; i < k; i++) + x[k] -= x[i]*L_[k][i]; + x[k] /= L_[k][k]; + + } + + // Solve L'*X = Y; + for (int k = n-1; k >= 0; k--) + { + for (int i = k+1; i < n; i++) + x[k] -= x[i]*L_[i][k]; + x[k] /= L_[k][k]; + } + + return x; +} + + +/** + + Solve a linear system A*X = B, using the previously computed + cholesky factorization of A: L*L'. + + @param B A Matrix with as many rows as A and any number of columns. + @return X so that L*L'*X = B. If B is nonconformat, or if A + was not symmetric posidtive definite, a null (0x0) + array is returned. +*/ +template <class Real> +Array2D<Real> Cholesky<Real>::solve(const Array2D<Real> &B) +{ + int n = L_.dim1(); + if (B.dim1() != n) + return Array2D<Real>(); + + + Array2D<Real> X = B.copy(); + int nx = B.dim2(); + +// Cleve's original code +#if 0 + // Solve L*Y = B; + for (int k = 0; k < n; k++) { + for (int i = k+1; i < n; i++) { + for (int j = 0; j < nx; j++) { + X[i][j] -= X[k][j]*L_[k][i]; + } + } + for (int j = 0; j < nx; j++) { + X[k][j] /= L_[k][k]; + } + } + + // Solve L'*X = Y; + for (int k = n-1; k >= 0; k--) { + for (int j = 0; j < nx; j++) { + X[k][j] /= L_[k][k]; + } + for (int i = 0; i < k; i++) { + for (int j = 0; j < nx; j++) { + X[i][j] -= X[k][j]*L_[k][i]; + } + } + } +#endif + + + // Solve L*y = b; + for (int j=0; j< nx; j++) + { + for (int k = 0; k < n; k++) + { + for (int i = 0; i < k; i++) + X[k][j] -= X[i][j]*L_[k][i]; + X[k][j] /= L_[k][k]; + } + } + + // Solve L'*X = Y; + for (int j=0; j<nx; j++) + { + for (int k = n-1; k >= 0; k--) + { + for (int i = k+1; i < n; i++) + X[k][j] -= X[i][j]*L_[i][k]; + X[k][j] /= L_[k][k]; + } + } + + + + return X; +} + + +} +// namespace JAMA + +#endif +// JAMA_CHOLESKY_H diff --git a/lib/include/tnt/jama_eig.h b/lib/include/tnt/jama_eig.h new file mode 100644 index 0000000..8e3572f --- /dev/null +++ b/lib/include/tnt/jama_eig.h @@ -0,0 +1,1034 @@ +#ifndef JAMA_EIG_H +#define JAMA_EIG_H + + +#include "tnt_array1d.h" +#include "tnt_array2d.h" +#include "tnt_math_utils.h" + +#include <algorithm> +// for min(), max() below + +#include <cmath> +// for abs() below + +using namespace TNT; +using namespace std; + +// Modification by Willem Jan Palenstijn, 2010-03-11: +// Use std::min() instead of min(), std::max() instead of max() + + +namespace JAMA +{ + +/** + + Computes eigenvalues and eigenvectors of a real (non-complex) + matrix. +<P> + If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is + diagonal and the eigenvector matrix V is orthogonal. That is, + the diagonal values of D are the eigenvalues, and + V*V' = I, where I is the identity matrix. The columns of V + represent the eigenvectors in the sense that A*V = V*D. + +<P> + If A is not symmetric, then the eigenvalue matrix D is block diagonal + with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues, + a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex + eigenvalues look like +<pre> + + u + iv . . . . . + . u - iv . . . . + . . a + ib . . . + . . . a - ib . . + . . . . x . + . . . . . y +</pre> + then D looks like +<pre> + + u v . . . . + -v u . . . . + . . a b . . + . . -b a . . + . . . . x . + . . . . . y +</pre> + This keeps V a real matrix in both symmetric and non-symmetric + cases, and A*V = V*D. + + + + <p> + The matrix V may be badly + conditioned, or even singular, so the validity of the equation + A = V*D*inverse(V) depends upon the condition number of V. + + <p> + (Adapted from JAMA, a Java Matrix Library, developed by jointly + by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama). +**/ + +template <class Real> +class Eigenvalue +{ + + + /** Row and column dimension (square matrix). */ + int n; + + int issymmetric; /* boolean*/ + + /** Arrays for internal storage of eigenvalues. */ + + TNT::Array1D<Real> d; /* real part */ + TNT::Array1D<Real> e; /* img part */ + + /** Array for internal storage of eigenvectors. */ + TNT::Array2D<Real> V; + + /** Array for internal storage of nonsymmetric Hessenberg form. + @serial internal storage of nonsymmetric Hessenberg form. + */ + TNT::Array2D<Real> H; + + + /** Working storage for nonsymmetric algorithm. + @serial working storage for nonsymmetric algorithm. + */ + TNT::Array1D<Real> ort; + + + // Symmetric Householder reduction to tridiagonal form. + + void tred2() { + + // This is derived from the Algol procedures tred2 by + // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for + // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + for (int j = 0; j < n; j++) { + d[j] = V[n-1][j]; + } + + // Householder reduction to tridiagonal form. + + for (int i = n-1; i > 0; i--) { + + // Scale to avoid under/overflow. + + Real scale = 0.0; + Real h = 0.0; + for (int k = 0; k < i; k++) { + scale = scale + abs(d[k]); + } + if (scale == 0.0) { + e[i] = d[i-1]; + for (int j = 0; j < i; j++) { + d[j] = V[i-1][j]; + V[i][j] = 0.0; + V[j][i] = 0.0; + } + } else { + + // Generate Householder vector. + + for (int k = 0; k < i; k++) { + d[k] /= scale; + h += d[k] * d[k]; + } + Real f = d[i-1]; + Real g = sqrt(h); + if (f > 0) { + g = -g; + } + e[i] = scale * g; + h = h - f * g; + d[i-1] = f - g; + for (int j = 0; j < i; j++) { + e[j] = 0.0; + } + + // Apply similarity transformation to remaining columns. + + for (int j = 0; j < i; j++) { + f = d[j]; + V[j][i] = f; + g = e[j] + V[j][j] * f; + for (int k = j+1; k <= i-1; k++) { + g += V[k][j] * d[k]; + e[k] += V[k][j] * f; + } + e[j] = g; + } + f = 0.0; + for (int j = 0; j < i; j++) { + e[j] /= h; + f += e[j] * d[j]; + } + Real hh = f / (h + h); + for (int j = 0; j < i; j++) { + e[j] -= hh * d[j]; + } + for (int j = 0; j < i; j++) { + f = d[j]; + g = e[j]; + for (int k = j; k <= i-1; k++) { + V[k][j] -= (f * e[k] + g * d[k]); + } + d[j] = V[i-1][j]; + V[i][j] = 0.0; + } + } + d[i] = h; + } + + // Accumulate transformations. + + for (int i = 0; i < n-1; i++) { + V[n-1][i] = V[i][i]; + V[i][i] = 1.0; + Real h = d[i+1]; + if (h != 0.0) { + for (int k = 0; k <= i; k++) { + d[k] = V[k][i+1] / h; + } + for (int j = 0; j <= i; j++) { + Real g = 0.0; + for (int k = 0; k <= i; k++) { + g += V[k][i+1] * V[k][j]; + } + for (int k = 0; k <= i; k++) { + V[k][j] -= g * d[k]; + } + } + } + for (int k = 0; k <= i; k++) { + V[k][i+1] = 0.0; + } + } + for (int j = 0; j < n; j++) { + d[j] = V[n-1][j]; + V[n-1][j] = 0.0; + } + V[n-1][n-1] = 1.0; + e[0] = 0.0; + } + + // Symmetric tridiagonal QL algorithm. + + void tql2 () { + + // This is derived from the Algol procedures tql2, by + // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for + // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + for (int i = 1; i < n; i++) { + e[i-1] = e[i]; + } + e[n-1] = 0.0; + + Real f = 0.0; + Real tst1 = 0.0; + Real eps = pow(2.0,-52.0); + for (int l = 0; l < n; l++) { + + // Find small subdiagonal element + + tst1 = std::max(tst1,abs(d[l]) + abs(e[l])); + int m = l; + + // Original while-loop from Java code + while (m < n) { + if (abs(e[m]) <= eps*tst1) { + break; + } + m++; + } + + + // If m == l, d[l] is an eigenvalue, + // otherwise, iterate. + + if (m > l) { + int iter = 0; + do { + iter = iter + 1; // (Could check iteration count here.) + + // Compute implicit shift + + Real g = d[l]; + Real p = (d[l+1] - g) / (2.0 * e[l]); + Real r = hypot(p,1.0); + if (p < 0) { + r = -r; + } + d[l] = e[l] / (p + r); + d[l+1] = e[l] * (p + r); + Real dl1 = d[l+1]; + Real h = g - d[l]; + for (int i = l+2; i < n; i++) { + d[i] -= h; + } + f = f + h; + + // Implicit QL transformation. + + p = d[m]; + Real c = 1.0; + Real c2 = c; + Real c3 = c; + Real el1 = e[l+1]; + Real s = 0.0; + Real s2 = 0.0; + for (int i = m-1; i >= l; i--) { + c3 = c2; + c2 = c; + s2 = s; + g = c * e[i]; + h = c * p; + r = hypot(p,e[i]); + e[i+1] = s * r; + s = e[i] / r; + c = p / r; + p = c * d[i] - s * g; + d[i+1] = h + s * (c * g + s * d[i]); + + // Accumulate transformation. + + for (int k = 0; k < n; k++) { + h = V[k][i+1]; + V[k][i+1] = s * V[k][i] + c * h; + V[k][i] = c * V[k][i] - s * h; + } + } + p = -s * s2 * c3 * el1 * e[l] / dl1; + e[l] = s * p; + d[l] = c * p; + + // Check for convergence. + + } while (abs(e[l]) > eps*tst1); + } + d[l] = d[l] + f; + e[l] = 0.0; + } + + // Sort eigenvalues and corresponding vectors. + + for (int i = 0; i < n-1; i++) { + int k = i; + Real p = d[i]; + for (int j = i+1; j < n; j++) { + if (d[j] < p) { + k = j; + p = d[j]; + } + } + if (k != i) { + d[k] = d[i]; + d[i] = p; + for (int j = 0; j < n; j++) { + p = V[j][i]; + V[j][i] = V[j][k]; + V[j][k] = p; + } + } + } + } + + // Nonsymmetric reduction to Hessenberg form. + + void orthes () { + + // This is derived from the Algol procedures orthes and ortran, + // by Martin and Wilkinson, Handbook for Auto. Comp., + // Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutines in EISPACK. + + int low = 0; + int high = n-1; + + for (int m = low+1; m <= high-1; m++) { + + // Scale column. + + Real scale = 0.0; + for (int i = m; i <= high; i++) { + scale = scale + abs(H[i][m-1]); + } + if (scale != 0.0) { + + // Compute Householder transformation. + + Real h = 0.0; + for (int i = high; i >= m; i--) { + ort[i] = H[i][m-1]/scale; + h += ort[i] * ort[i]; + } + Real g = sqrt(h); + if (ort[m] > 0) { + g = -g; + } + h = h - ort[m] * g; + ort[m] = ort[m] - g; + + // Apply Householder similarity transformation + // H = (I-u*u'/h)*H*(I-u*u')/h) + + for (int j = m; j < n; j++) { + Real f = 0.0; + for (int i = high; i >= m; i--) { + f += ort[i]*H[i][j]; + } + f = f/h; + for (int i = m; i <= high; i++) { + H[i][j] -= f*ort[i]; + } + } + + for (int i = 0; i <= high; i++) { + Real f = 0.0; + for (int j = high; j >= m; j--) { + f += ort[j]*H[i][j]; + } + f = f/h; + for (int j = m; j <= high; j++) { + H[i][j] -= f*ort[j]; + } + } + ort[m] = scale*ort[m]; + H[m][m-1] = scale*g; + } + } + + // Accumulate transformations (Algol's ortran). + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + V[i][j] = (i == j ? 1.0 : 0.0); + } + } + + for (int m = high-1; m >= low+1; m--) { + if (H[m][m-1] != 0.0) { + for (int i = m+1; i <= high; i++) { + ort[i] = H[i][m-1]; + } + for (int j = m; j <= high; j++) { + Real g = 0.0; + for (int i = m; i <= high; i++) { + g += ort[i] * V[i][j]; + } + // Double division avoids possible underflow + g = (g / ort[m]) / H[m][m-1]; + for (int i = m; i <= high; i++) { + V[i][j] += g * ort[i]; + } + } + } + } + } + + + // Complex scalar division. + + Real cdivr, cdivi; + void cdiv(Real xr, Real xi, Real yr, Real yi) { + Real r,d; + if (abs(yr) > abs(yi)) { + r = yi/yr; + d = yr + r*yi; + cdivr = (xr + r*xi)/d; + cdivi = (xi - r*xr)/d; + } else { + r = yr/yi; + d = yi + r*yr; + cdivr = (r*xr + xi)/d; + cdivi = (r*xi - xr)/d; + } + } + + + // Nonsymmetric reduction from Hessenberg to real Schur form. + + void hqr2 () { + + // This is derived from the Algol procedure hqr2, + // by Martin and Wilkinson, Handbook for Auto. Comp., + // Vol.ii-Linear Algebra, and the corresponding + // Fortran subroutine in EISPACK. + + // Initialize + + int nn = this->n; + int n = nn-1; + int low = 0; + int high = nn-1; + Real eps = pow(2.0,-52.0); + Real exshift = 0.0; + Real p=0,q=0,r=0,s=0,z=0,t,w,x,y; + + // Store roots isolated by balanc and compute matrix norm + + Real norm = 0.0; + for (int i = 0; i < nn; i++) { + if ((i < low) || (i > high)) { + d[i] = H[i][i]; + e[i] = 0.0; + } + for (int j = std::max(i-1,0); j < nn; j++) { + norm = norm + abs(H[i][j]); + } + } + + // Outer loop over eigenvalue index + + int iter = 0; + while (n >= low) { + + // Look for single small sub-diagonal element + + int l = n; + while (l > low) { + s = abs(H[l-1][l-1]) + abs(H[l][l]); + if (s == 0.0) { + s = norm; + } + if (abs(H[l][l-1]) < eps * s) { + break; + } + l--; + } + + // Check for convergence + // One root found + + if (l == n) { + H[n][n] = H[n][n] + exshift; + d[n] = H[n][n]; + e[n] = 0.0; + n--; + iter = 0; + + // Two roots found + + } else if (l == n-1) { + w = H[n][n-1] * H[n-1][n]; + p = (H[n-1][n-1] - H[n][n]) / 2.0; + q = p * p + w; + z = sqrt(abs(q)); + H[n][n] = H[n][n] + exshift; + H[n-1][n-1] = H[n-1][n-1] + exshift; + x = H[n][n]; + + // Real pair + + if (q >= 0) { + if (p >= 0) { + z = p + z; + } else { + z = p - z; + } + d[n-1] = x + z; + d[n] = d[n-1]; + if (z != 0.0) { + d[n] = x - w / z; + } + e[n-1] = 0.0; + e[n] = 0.0; + x = H[n][n-1]; + s = abs(x) + abs(z); + p = x / s; + q = z / s; + r = sqrt(p * p+q * q); + p = p / r; + q = q / r; + + // Row modification + + for (int j = n-1; j < nn; j++) { + z = H[n-1][j]; + H[n-1][j] = q * z + p * H[n][j]; + H[n][j] = q * H[n][j] - p * z; + } + + // Column modification + + for (int i = 0; i <= n; i++) { + z = H[i][n-1]; + H[i][n-1] = q * z + p * H[i][n]; + H[i][n] = q * H[i][n] - p * z; + } + + // Accumulate transformations + + for (int i = low; i <= high; i++) { + z = V[i][n-1]; + V[i][n-1] = q * z + p * V[i][n]; + V[i][n] = q * V[i][n] - p * z; + } + + // Complex pair + + } else { + d[n-1] = x + p; + d[n] = x + p; + e[n-1] = z; + e[n] = -z; + } + n = n - 2; + iter = 0; + + // No convergence yet + + } else { + + // Form shift + + x = H[n][n]; + y = 0.0; + w = 0.0; + if (l < n) { + y = H[n-1][n-1]; + w = H[n][n-1] * H[n-1][n]; + } + + // Wilkinson's original ad hoc shift + + if (iter == 10) { + exshift += x; + for (int i = low; i <= n; i++) { + H[i][i] -= x; + } + s = abs(H[n][n-1]) + abs(H[n-1][n-2]); + x = y = 0.75 * s; + w = -0.4375 * s * s; + } + + // MATLAB's new ad hoc shift + + if (iter == 30) { + s = (y - x) / 2.0; + s = s * s + w; + if (s > 0) { + s = sqrt(s); + if (y < x) { + s = -s; + } + s = x - w / ((y - x) / 2.0 + s); + for (int i = low; i <= n; i++) { + H[i][i] -= s; + } + exshift += s; + x = y = w = 0.964; + } + } + + iter = iter + 1; // (Could check iteration count here.) + + // Look for two consecutive small sub-diagonal elements + + int m = n-2; + while (m >= l) { + z = H[m][m]; + r = x - z; + s = y - z; + p = (r * s - w) / H[m+1][m] + H[m][m+1]; + q = H[m+1][m+1] - z - r - s; + r = H[m+2][m+1]; + s = abs(p) + abs(q) + abs(r); + p = p / s; + q = q / s; + r = r / s; + if (m == l) { + break; + } + if (abs(H[m][m-1]) * (abs(q) + abs(r)) < + eps * (abs(p) * (abs(H[m-1][m-1]) + abs(z) + + abs(H[m+1][m+1])))) { + break; + } + m--; + } + + for (int i = m+2; i <= n; i++) { + H[i][i-2] = 0.0; + if (i > m+2) { + H[i][i-3] = 0.0; + } + } + + // Double QR step involving rows l:n and columns m:n + + for (int k = m; k <= n-1; k++) { + int notlast = (k != n-1); + if (k != m) { + p = H[k][k-1]; + q = H[k+1][k-1]; + r = (notlast ? H[k+2][k-1] : 0.0); + x = abs(p) + abs(q) + abs(r); + if (x != 0.0) { + p = p / x; + q = q / x; + r = r / x; + } + } + if (x == 0.0) { + break; + } + s = sqrt(p * p + q * q + r * r); + if (p < 0) { + s = -s; + } + if (s != 0) { + if (k != m) { + H[k][k-1] = -s * x; + } else if (l != m) { + H[k][k-1] = -H[k][k-1]; + } + p = p + s; + x = p / s; + y = q / s; + z = r / s; + q = q / p; + r = r / p; + + // Row modification + + for (int j = k; j < nn; j++) { + p = H[k][j] + q * H[k+1][j]; + if (notlast) { + p = p + r * H[k+2][j]; + H[k+2][j] = H[k+2][j] - p * z; + } + H[k][j] = H[k][j] - p * x; + H[k+1][j] = H[k+1][j] - p * y; + } + + // Column modification + + for (int i = 0; i <= std::min(n,k+3); i++) { + p = x * H[i][k] + y * H[i][k+1]; + if (notlast) { + p = p + z * H[i][k+2]; + H[i][k+2] = H[i][k+2] - p * r; + } + H[i][k] = H[i][k] - p; + H[i][k+1] = H[i][k+1] - p * q; + } + + // Accumulate transformations + + for (int i = low; i <= high; i++) { + p = x * V[i][k] + y * V[i][k+1]; + if (notlast) { + p = p + z * V[i][k+2]; + V[i][k+2] = V[i][k+2] - p * r; + } + V[i][k] = V[i][k] - p; + V[i][k+1] = V[i][k+1] - p * q; + } + } // (s != 0) + } // k loop + } // check convergence + } // while (n >= low) + + // Backsubstitute to find vectors of upper triangular form + + if (norm == 0.0) { + return; + } + + for (n = nn-1; n >= 0; n--) { + p = d[n]; + q = e[n]; + + // Real vector + + if (q == 0) { + int l = n; + H[n][n] = 1.0; + for (int i = n-1; i >= 0; i--) { + w = H[i][i] - p; + r = 0.0; + for (int j = l; j <= n; j++) { + r = r + H[i][j] * H[j][n]; + } + if (e[i] < 0.0) { + z = w; + s = r; + } else { + l = i; + if (e[i] == 0.0) { + if (w != 0.0) { + H[i][n] = -r / w; + } else { + H[i][n] = -r / (eps * norm); + } + + // Solve real equations + + } else { + x = H[i][i+1]; + y = H[i+1][i]; + q = (d[i] - p) * (d[i] - p) + e[i] * e[i]; + t = (x * s - z * r) / q; + H[i][n] = t; + if (abs(x) > abs(z)) { + H[i+1][n] = (-r - w * t) / x; + } else { + H[i+1][n] = (-s - y * t) / z; + } + } + + // Overflow control + + t = abs(H[i][n]); + if ((eps * t) * t > 1) { + for (int j = i; j <= n; j++) { + H[j][n] = H[j][n] / t; + } + } + } + } + + // Complex vector + + } else if (q < 0) { + int l = n-1; + + // Last vector component imaginary so matrix is triangular + + if (abs(H[n][n-1]) > abs(H[n-1][n])) { + H[n-1][n-1] = q / H[n][n-1]; + H[n-1][n] = -(H[n][n] - p) / H[n][n-1]; + } else { + cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q); + H[n-1][n-1] = cdivr; + H[n-1][n] = cdivi; + } + H[n][n-1] = 0.0; + H[n][n] = 1.0; + for (int i = n-2; i >= 0; i--) { + Real ra,sa,vr,vi; + ra = 0.0; + sa = 0.0; + for (int j = l; j <= n; j++) { + ra = ra + H[i][j] * H[j][n-1]; + sa = sa + H[i][j] * H[j][n]; + } + w = H[i][i] - p; + + if (e[i] < 0.0) { + z = w; + r = ra; + s = sa; + } else { + l = i; + if (e[i] == 0) { + cdiv(-ra,-sa,w,q); + H[i][n-1] = cdivr; + H[i][n] = cdivi; + } else { + + // Solve complex equations + + x = H[i][i+1]; + y = H[i+1][i]; + vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q; + vi = (d[i] - p) * 2.0 * q; + if ((vr == 0.0) && (vi == 0.0)) { + vr = eps * norm * (abs(w) + abs(q) + + abs(x) + abs(y) + abs(z)); + } + cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi); + H[i][n-1] = cdivr; + H[i][n] = cdivi; + if (abs(x) > (abs(z) + abs(q))) { + H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x; + H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x; + } else { + cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q); + H[i+1][n-1] = cdivr; + H[i+1][n] = cdivi; + } + } + + // Overflow control + + t = std::max(abs(H[i][n-1]),abs(H[i][n])); + if ((eps * t) * t > 1) { + for (int j = i; j <= n; j++) { + H[j][n-1] = H[j][n-1] / t; + H[j][n] = H[j][n] / t; + } + } + } + } + } + } + + // Vectors of isolated roots + + for (int i = 0; i < nn; i++) { + if (i < low || i > high) { + for (int j = i; j < nn; j++) { + V[i][j] = H[i][j]; + } + } + } + + // Back transformation to get eigenvectors of original matrix + + for (int j = nn-1; j >= low; j--) { + for (int i = low; i <= high; i++) { + z = 0.0; + for (int k = low; k <= std::min(j,high); k++) { + z = z + V[i][k] * H[k][j]; + } + V[i][j] = z; + } + } + } + +public: + + + /** Check for symmetry, then construct the eigenvalue decomposition + @param A Square real (non-complex) matrix + */ + + Eigenvalue(const TNT::Array2D<Real> &A) { + n = A.dim2(); + V = Array2D<Real>(n,n); + d = Array1D<Real>(n); + e = Array1D<Real>(n); + + issymmetric = 1; + for (int j = 0; (j < n) && issymmetric; j++) { + for (int i = 0; (i < n) && issymmetric; i++) { + issymmetric = (A[i][j] == A[j][i]); + } + } + + if (issymmetric) { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + V[i][j] = A[i][j]; + } + } + + // Tridiagonalize. + tred2(); + + // Diagonalize. + tql2(); + + } else { + H = TNT::Array2D<Real>(n,n); + ort = TNT::Array1D<Real>(n); + + for (int j = 0; j < n; j++) { + for (int i = 0; i < n; i++) { + H[i][j] = A[i][j]; + } + } + + // Reduce to Hessenberg form. + orthes(); + + // Reduce Hessenberg to real Schur form. + hqr2(); + } + } + + + /** Return the eigenvector matrix + @return V + */ + + void getV (TNT::Array2D<Real> &V_) { + V_ = V; + return; + } + + /** Return the real parts of the eigenvalues + @return real(diag(D)) + */ + + void getRealEigenvalues (TNT::Array1D<Real> &d_) { + d_ = d; + return ; + } + + /** Return the imaginary parts of the eigenvalues + in parameter e_. + + @pararm e_: new matrix with imaginary parts of the eigenvalues. + */ + void getImagEigenvalues (TNT::Array1D<Real> &e_) { + e_ = e; + return; + } + + +/** + Computes the block diagonal eigenvalue matrix. + If the original matrix A is not symmetric, then the eigenvalue + matrix D is block diagonal with the real eigenvalues in 1-by-1 + blocks and any complex eigenvalues, + a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex + eigenvalues look like +<pre> + + u + iv . . . . . + . u - iv . . . . + . . a + ib . . . + . . . a - ib . . + . . . . x . + . . . . . y +</pre> + then D looks like +<pre> + + u v . . . . + -v u . . . . + . . a b . . + . . -b a . . + . . . . x . + . . . . . y +</pre> + This keeps V a real matrix in both symmetric and non-symmetric + cases, and A*V = V*D. + + @param D: upon return, the matrix is filled with the block diagonal + eigenvalue matrix. + +*/ + void getD (TNT::Array2D<Real> &D) { + D = Array2D<Real>(n,n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + D[i][j] = 0.0; + } + D[i][i] = d[i]; + if (e[i] > 0) { + D[i][i+1] = e[i]; + } else if (e[i] < 0) { + D[i][i-1] = e[i]; + } + } + } +}; + +} //namespace JAMA + + +#endif +// JAMA_EIG_H diff --git a/lib/include/tnt/jama_lu.h b/lib/include/tnt/jama_lu.h new file mode 100644 index 0000000..e95b433 --- /dev/null +++ b/lib/include/tnt/jama_lu.h @@ -0,0 +1,323 @@ +#ifndef JAMA_LU_H +#define JAMA_LU_H + +#include "tnt.h" +#include <algorithm> +//for min(), max() below + +using namespace TNT; +using namespace std; + + +// Modification by Willem Jan Palenstijn, 2010-03-11: +// Use std::min() instead of min() + +namespace JAMA +{ + + /** LU Decomposition. + <P> + For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n + unit lower triangular matrix L, an n-by-n upper triangular matrix U, + and a permutation vector piv of length m so that A(piv,:) = L*U. + If m < n, then L is m-by-m and U is m-by-n. + <P> + The LU decompostion with pivoting always exists, even if the matrix is + singular, so the constructor will never fail. The primary use of the + LU decomposition is in the solution of square systems of simultaneous + linear equations. This will fail if isNonsingular() returns false. + */ +template <class Real> +class LU +{ + + + + /* Array for internal storage of decomposition. */ + Array2D<Real> LU_; + int m, n, pivsign; + Array1D<int> piv; + + + Array2D<Real> permute_copy(const Array2D<Real> &A, + const Array1D<int> &piv, int j0, int j1) + { + int piv_length = piv.dim(); + + Array2D<Real> X(piv_length, j1-j0+1); + + + for (int i = 0; i < piv_length; i++) + for (int j = j0; j <= j1; j++) + X[i][j-j0] = A[piv[i]][j]; + + return X; + } + + Array1D<Real> permute_copy(const Array1D<Real> &A, + const Array1D<int> &piv) + { + int piv_length = piv.dim(); + if (piv_length != A.dim()) + return Array1D<Real>(); + + Array1D<Real> x(piv_length); + + + for (int i = 0; i < piv_length; i++) + x[i] = A[piv[i]]; + + return x; + } + + + public : + + /** LU Decomposition + @param A Rectangular matrix + @return LU Decomposition object to access L, U and piv. + */ + + LU (const Array2D<Real> &A) : LU_(A.copy()), m(A.dim1()), n(A.dim2()), + piv(A.dim1()) + + { + + // Use a "left-looking", dot-product, Crout/Doolittle algorithm. + + + for (int i = 0; i < m; i++) { + piv[i] = i; + } + pivsign = 1; + Real *LUrowi = 0;; + Array1D<Real> LUcolj(m); + + // Outer loop. + + for (int j = 0; j < n; j++) { + + // Make a copy of the j-th column to localize references. + + for (int i = 0; i < m; i++) { + LUcolj[i] = LU_[i][j]; + } + + // Apply previous transformations. + + for (int i = 0; i < m; i++) { + LUrowi = LU_[i]; + + // Most of the time is spent in the following dot product. + + int kmax = std::min(i,j); + double s = 0.0; + for (int k = 0; k < kmax; k++) { + s += LUrowi[k]*LUcolj[k]; + } + + LUrowi[j] = LUcolj[i] -= s; + } + + // Find pivot and exchange if necessary. + + int p = j; + for (int i = j+1; i < m; i++) { + if (abs(LUcolj[i]) > abs(LUcolj[p])) { + p = i; + } + } + if (p != j) { + int k=0; + for (k = 0; k < n; k++) { + double t = LU_[p][k]; + LU_[p][k] = LU_[j][k]; + LU_[j][k] = t; + } + k = piv[p]; + piv[p] = piv[j]; + piv[j] = k; + pivsign = -pivsign; + } + + // Compute multipliers. + + if ((j < m) && (LU_[j][j] != 0.0)) { + for (int i = j+1; i < m; i++) { + LU_[i][j] /= LU_[j][j]; + } + } + } + } + + + /** Is the matrix nonsingular? + @return 1 (true) if upper triangular factor U (and hence A) + is nonsingular, 0 otherwise. + */ + + int isNonsingular () { + for (int j = 0; j < n; j++) { + if (LU_[j][j] == 0) + return 0; + } + return 1; + } + + /** Return lower triangular factor + @return L + */ + + Array2D<Real> getL () { + Array2D<Real> L_(m,n); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i > j) { + L_[i][j] = LU_[i][j]; + } else if (i == j) { + L_[i][j] = 1.0; + } else { + L_[i][j] = 0.0; + } + } + } + return L_; + } + + /** Return upper triangular factor + @return U portion of LU factorization. + */ + + Array2D<Real> getU () { + Array2D<Real> U_(n,n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i <= j) { + U_[i][j] = LU_[i][j]; + } else { + U_[i][j] = 0.0; + } + } + } + return U_; + } + + /** Return pivot permutation vector + @return piv + */ + + Array1D<int> getPivot () { + return piv; + } + + + /** Compute determinant using LU factors. + @return determinant of A, or 0 if A is not square. + */ + + Real det () { + if (m != n) { + return Real(0); + } + Real d = Real(pivsign); + for (int j = 0; j < n; j++) { + d *= LU_[j][j]; + } + return d; + } + + /** Solve A*X = B + @param B A Matrix with as many rows as A and any number of columns. + @return X so that L*U*X = B(piv,:), if B is nonconformant, returns + 0x0 (null) array. + */ + + Array2D<Real> solve (const Array2D<Real> &B) + { + + /* Dimensions: A is mxn, X is nxk, B is mxk */ + + if (B.dim1() != m) { + return Array2D<Real>(0,0); + } + if (!isNonsingular()) { + return Array2D<Real>(0,0); + } + + // Copy right hand side with pivoting + int nx = B.dim2(); + + + Array2D<Real> X = permute_copy(B, piv, 0, nx-1); + + // Solve L*Y = B(piv,:) + for (int k = 0; k < n; k++) { + for (int i = k+1; i < n; i++) { + for (int j = 0; j < nx; j++) { + X[i][j] -= X[k][j]*LU_[i][k]; + } + } + } + // Solve U*X = Y; + for (int k = n-1; k >= 0; k--) { + for (int j = 0; j < nx; j++) { + X[k][j] /= LU_[k][k]; + } + for (int i = 0; i < k; i++) { + for (int j = 0; j < nx; j++) { + X[i][j] -= X[k][j]*LU_[i][k]; + } + } + } + return X; + } + + + /** Solve A*x = b, where x and b are vectors of length equal + to the number of rows in A. + + @param b a vector (Array1D> of length equal to the first dimension + of A. + @return x a vector (Array1D> so that L*U*x = b(piv), if B is nonconformant, + returns 0x0 (null) array. + */ + + Array1D<Real> solve (const Array1D<Real> &b) + { + + /* Dimensions: A is mxn, X is nxk, B is mxk */ + + if (b.dim1() != m) { + return Array1D<Real>(); + } + if (!isNonsingular()) { + return Array1D<Real>(); + } + + + Array1D<Real> x = permute_copy(b, piv); + + // Solve L*Y = B(piv) + for (int k = 0; k < n; k++) { + for (int i = k+1; i < n; i++) { + x[i] -= x[k]*LU_[i][k]; + } + } + + // Solve U*X = Y; + for (int k = n-1; k >= 0; k--) { + x[k] /= LU_[k][k]; + for (int i = 0; i < k; i++) + x[i] -= x[k]*LU_[i][k]; + } + + + return x; + } + +}; /* class LU */ + +} /* namespace JAMA */ + +#endif +/* JAMA_LU_H */ diff --git a/lib/include/tnt/jama_qr.h b/lib/include/tnt/jama_qr.h new file mode 100644 index 0000000..98d37f5 --- /dev/null +++ b/lib/include/tnt/jama_qr.h @@ -0,0 +1,326 @@ +#ifndef JAMA_QR_H +#define JAMA_QR_H + +#include "tnt_array1d.h" +#include "tnt_array2d.h" +#include "tnt_math_utils.h" + +namespace JAMA +{ + +/** +<p> + Classical QR Decompisition: + for an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n + orthogonal matrix Q and an n-by-n upper triangular matrix R so that + A = Q*R. +<P> + The QR decompostion always exists, even if the matrix does not have + full rank, so the constructor will never fail. The primary use of the + QR decomposition is in the least squares solution of nonsquare systems + of simultaneous linear equations. This will fail if isFullRank() + returns 0 (false). + +<p> + The Q and R factors can be retrived via the getQ() and getR() + methods. Furthermore, a solve() method is provided to find the + least squares solution of Ax=b using the QR factors. + + <p> + (Adapted from JAMA, a Java Matrix Library, developed by jointly + by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama). +*/ + +template <class Real> +class QR { + + + /** Array for internal storage of decomposition. + @serial internal array storage. + */ + + TNT::Array2D<Real> QR_; + + /** Row and column dimensions. + @serial column dimension. + @serial row dimension. + */ + int m, n; + + /** Array for internal storage of diagonal of R. + @serial diagonal of R. + */ + TNT::Array1D<Real> Rdiag; + + +public: + +/** + Create a QR factorization object for A. + + @param A rectangular (m>=n) matrix. +*/ + QR(const TNT::Array2D<Real> &A) /* constructor */ + { + QR_ = A.copy(); + m = A.dim1(); + n = A.dim2(); + Rdiag = TNT::Array1D<Real>(n); + int i=0, j=0, k=0; + + // Main loop. + for (k = 0; k < n; k++) { + // Compute 2-norm of k-th column without under/overflow. + Real nrm = 0; + for (i = k; i < m; i++) { + nrm = TNT::hypot(nrm,QR_[i][k]); + } + + if (nrm != 0.0) { + // Form k-th Householder vector. + if (QR_[k][k] < 0) { + nrm = -nrm; + } + for (i = k; i < m; i++) { + QR_[i][k] /= nrm; + } + QR_[k][k] += 1.0; + + // Apply transformation to remaining columns. + for (j = k+1; j < n; j++) { + Real s = 0.0; + for (i = k; i < m; i++) { + s += QR_[i][k]*QR_[i][j]; + } + s = -s/QR_[k][k]; + for (i = k; i < m; i++) { + QR_[i][j] += s*QR_[i][k]; + } + } + } + Rdiag[k] = -nrm; + } + } + + +/** + Flag to denote the matrix is of full rank. + + @return 1 if matrix is full rank, 0 otherwise. +*/ + int isFullRank() const + { + for (int j = 0; j < n; j++) + { + if (Rdiag[j] == 0) + return 0; + } + return 1; + } + + + + + /** + + Retreive the Householder vectors from QR factorization + @returns lower trapezoidal matrix whose columns define the reflections + */ + + TNT::Array2D<Real> getHouseholder (void) const + { + TNT::Array2D<Real> H(m,n); + + /* note: H is completely filled in by algorithm, so + initializaiton of H is not necessary. + */ + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + { + if (i >= j) { + H[i][j] = QR_[i][j]; + } else { + H[i][j] = 0.0; + } + } + } + return H; + } + + + + /** Return the upper triangular factor, R, of the QR factorization + @return R + */ + + TNT::Array2D<Real> getR() const + { + TNT::Array2D<Real> R(n,n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i < j) { + R[i][j] = QR_[i][j]; + } else if (i == j) { + R[i][j] = Rdiag[i]; + } else { + R[i][j] = 0.0; + } + } + } + return R; + } + + + + + + /** + Generate and return the (economy-sized) orthogonal factor + @param Q the (ecnomy-sized) orthogonal factor (Q*R=A). + */ + + TNT::Array2D<Real> getQ() const + { + int i=0, j=0, k=0; + + TNT::Array2D<Real> Q(m,n); + for (k = n-1; k >= 0; k--) { + for (i = 0; i < m; i++) { + Q[i][k] = 0.0; + } + Q[k][k] = 1.0; + for (j = k; j < n; j++) { + if (QR_[k][k] != 0) { + Real s = 0.0; + for (i = k; i < m; i++) { + s += QR_[i][k]*Q[i][j]; + } + s = -s/QR_[k][k]; + for (i = k; i < m; i++) { + Q[i][j] += s*QR_[i][k]; + } + } + } + } + return Q; + } + + + /** Least squares solution of A*x = b + @param B m-length array (vector). + @return x n-length array (vector) that minimizes the two norm of Q*R*X-B. + If B is non-conformant, or if QR.isFullRank() is false, + the routine returns a null (0-length) vector. + */ + + TNT::Array1D<Real> solve(const TNT::Array1D<Real> &b) const + { + if (b.dim1() != m) /* arrays must be conformant */ + return TNT::Array1D<Real>(); + + if ( !isFullRank() ) /* matrix is rank deficient */ + { + return TNT::Array1D<Real>(); + } + + TNT::Array1D<Real> x = b.copy(); + + // Compute Y = transpose(Q)*b + for (int k = 0; k < n; k++) + { + Real s = 0.0; + for (int i = k; i < m; i++) + { + s += QR_[i][k]*x[i]; + } + s = -s/QR_[k][k]; + for (int i = k; i < m; i++) + { + x[i] += s*QR_[i][k]; + } + } + // Solve R*X = Y; + for (int k = n-1; k >= 0; k--) + { + x[k] /= Rdiag[k]; + for (int i = 0; i < k; i++) { + x[i] -= x[k]*QR_[i][k]; + } + } + + + /* return n x nx portion of X */ + TNT::Array1D<Real> x_(n); + for (int i=0; i<n; i++) + x_[i] = x[i]; + + return x_; + } + + /** Least squares solution of A*X = B + @param B m x k Array (must conform). + @return X n x k Array that minimizes the two norm of Q*R*X-B. If + B is non-conformant, or if QR.isFullRank() is false, + the routine returns a null (0x0) array. + */ + + TNT::Array2D<Real> solve(const TNT::Array2D<Real> &B) const + { + if (B.dim1() != m) /* arrays must be conformant */ + return TNT::Array2D<Real>(0,0); + + if ( !isFullRank() ) /* matrix is rank deficient */ + { + return TNT::Array2D<Real>(0,0); + } + + int nx = B.dim2(); + TNT::Array2D<Real> X = B.copy(); + int i=0, j=0, k=0; + + // Compute Y = transpose(Q)*B + for (k = 0; k < n; k++) { + for (j = 0; j < nx; j++) { + Real s = 0.0; + for (i = k; i < m; i++) { + s += QR_[i][k]*X[i][j]; + } + s = -s/QR_[k][k]; + for (i = k; i < m; i++) { + X[i][j] += s*QR_[i][k]; + } + } + } + // Solve R*X = Y; + for (k = n-1; k >= 0; k--) { + for (j = 0; j < nx; j++) { + X[k][j] /= Rdiag[k]; + } + for (i = 0; i < k; i++) { + for (j = 0; j < nx; j++) { + X[i][j] -= X[k][j]*QR_[i][k]; + } + } + } + + + /* return n x nx portion of X */ + TNT::Array2D<Real> X_(n,nx); + for (i=0; i<n; i++) + for (j=0; j<nx; j++) + X_[i][j] = X[i][j]; + + return X_; + } + + +}; + + +} +// namespace JAMA + +#endif +// JAMA_QR__H + diff --git a/lib/include/tnt/jama_svd.h b/lib/include/tnt/jama_svd.h new file mode 100644 index 0000000..72ce3a7 --- /dev/null +++ b/lib/include/tnt/jama_svd.h @@ -0,0 +1,543 @@ +#ifndef JAMA_SVD_H +#define JAMA_SVD_H + + +#include "tnt_array1d.h" +#include "tnt_array1d_utils.h" +#include "tnt_array2d.h" +#include "tnt_array2d_utils.h" +#include "tnt_math_utils.h" + +#include <algorithm> +// for min(), max() below +#include <cmath> +// for abs() below + +using namespace TNT; +using namespace std; + + +// Modification by Willem Jan Palenstijn, 2010-03-11: +// Use std::min() instead of min(), std::max() instead of max() + + +namespace JAMA +{ + /** Singular Value Decomposition. + <P> + For an m-by-n matrix A with m >= n, the singular value decomposition is + an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and + an n-by-n orthogonal matrix V so that A = U*S*V'. + <P> + The singular values, sigma[k] = S[k][k], are ordered so that + sigma[0] >= sigma[1] >= ... >= sigma[n-1]. + <P> + The singular value decompostion always exists, so the constructor will + never fail. The matrix condition number and the effective numerical + rank can be computed from this decomposition. + + <p> + (Adapted from JAMA, a Java Matrix Library, developed by jointly + by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama). + */ +template <class Real> +class SVD +{ + + + Array2D<Real> U, V; + Array1D<Real> s; + int m, n; + + public: + + + SVD (const Array2D<Real> &Arg) { + + + m = Arg.dim1(); + n = Arg.dim2(); + int nu = std::min(m,n); + s = Array1D<Real>(std::min(m+1,n)); + U = Array2D<Real>(m, nu, Real(0)); + V = Array2D<Real>(n,n); + Array1D<Real> e(n); + Array1D<Real> work(m); + Array2D<Real> A(Arg.copy()); + int wantu = 1; /* boolean */ + int wantv = 1; /* boolean */ + int i=0, j=0, k=0; + + // Reduce A to bidiagonal form, storing the diagonal elements + // in s and the super-diagonal elements in e. + + int nct = std::min(m-1,n); + int nrt = std::max(0,std::min(n-2,m)); + for (k = 0; k < std::max(nct,nrt); k++) { + if (k < nct) { + + // Compute the transformation for the k-th column and + // place the k-th diagonal in s[k]. + // Compute 2-norm of k-th column without under/overflow. + s[k] = 0; + for (i = k; i < m; i++) { + s[k] = hypot(s[k],A[i][k]); + } + if (s[k] != 0.0) { + if (A[k][k] < 0.0) { + s[k] = -s[k]; + } + for (i = k; i < m; i++) { + A[i][k] /= s[k]; + } + A[k][k] += 1.0; + } + s[k] = -s[k]; + } + for (j = k+1; j < n; j++) { + if ((k < nct) && (s[k] != 0.0)) { + + // Apply the transformation. + + Real t(0.0); + for (i = k; i < m; i++) { + t += A[i][k]*A[i][j]; + } + t = -t/A[k][k]; + for (i = k; i < m; i++) { + A[i][j] += t*A[i][k]; + } + } + + // Place the k-th row of A into e for the + // subsequent calculation of the row transformation. + + e[j] = A[k][j]; + } + if (wantu & (k < nct)) { + + // Place the transformation in U for subsequent back + // multiplication. + + for (i = k; i < m; i++) { + U[i][k] = A[i][k]; + } + } + if (k < nrt) { + + // Compute the k-th row transformation and place the + // k-th super-diagonal in e[k]. + // Compute 2-norm without under/overflow. + e[k] = 0; + for (i = k+1; i < n; i++) { + e[k] = hypot(e[k],e[i]); + } + if (e[k] != 0.0) { + if (e[k+1] < 0.0) { + e[k] = -e[k]; + } + for (i = k+1; i < n; i++) { + e[i] /= e[k]; + } + e[k+1] += 1.0; + } + e[k] = -e[k]; + if ((k+1 < m) & (e[k] != 0.0)) { + + // Apply the transformation. + + for (i = k+1; i < m; i++) { + work[i] = 0.0; + } + for (j = k+1; j < n; j++) { + for (i = k+1; i < m; i++) { + work[i] += e[j]*A[i][j]; + } + } + for (j = k+1; j < n; j++) { + Real t(-e[j]/e[k+1]); + for (i = k+1; i < m; i++) { + A[i][j] += t*work[i]; + } + } + } + if (wantv) { + + // Place the transformation in V for subsequent + // back multiplication. + + for (i = k+1; i < n; i++) { + V[i][k] = e[i]; + } + } + } + } + + // Set up the final bidiagonal matrix or order p. + + int p = std::min(n,m+1); + if (nct < n) { + s[nct] = A[nct][nct]; + } + if (m < p) { + s[p-1] = 0.0; + } + if (nrt+1 < p) { + e[nrt] = A[nrt][p-1]; + } + e[p-1] = 0.0; + + // If required, generate U. + + if (wantu) { + for (j = nct; j < nu; j++) { + for (i = 0; i < m; i++) { + U[i][j] = 0.0; + } + U[j][j] = 1.0; + } + for (k = nct-1; k >= 0; k--) { + if (s[k] != 0.0) { + for (j = k+1; j < nu; j++) { + Real t(0.0); + for (i = k; i < m; i++) { + t += U[i][k]*U[i][j]; + } + t = -t/U[k][k]; + for (i = k; i < m; i++) { + U[i][j] += t*U[i][k]; + } + } + for (i = k; i < m; i++ ) { + U[i][k] = -U[i][k]; + } + U[k][k] = 1.0 + U[k][k]; + for (i = 0; i < k-1; i++) { + U[i][k] = 0.0; + } + } else { + for (i = 0; i < m; i++) { + U[i][k] = 0.0; + } + U[k][k] = 1.0; + } + } + } + + // If required, generate V. + + if (wantv) { + for (k = n-1; k >= 0; k--) { + if ((k < nrt) & (e[k] != 0.0)) { + for (j = k+1; j < nu; j++) { + Real t(0.0); + for (i = k+1; i < n; i++) { + t += V[i][k]*V[i][j]; + } + t = -t/V[k+1][k]; + for (i = k+1; i < n; i++) { + V[i][j] += t*V[i][k]; + } + } + } + for (i = 0; i < n; i++) { + V[i][k] = 0.0; + } + V[k][k] = 1.0; + } + } + + // Main iteration loop for the singular values. + + int pp = p-1; + int iter = 0; + Real eps(pow(2.0,-52.0)); + while (p > 0) { + int k=0; + int kase=0; + + // Here is where a test for too many iterations would go. + + // This section of the program inspects for + // negligible elements in the s and e arrays. On + // completion the variables kase and k are set as follows. + + // kase = 1 if s(p) and e[k-1] are negligible and k<p + // kase = 2 if s(k) is negligible and k<p + // kase = 3 if e[k-1] is negligible, k<p, and + // s(k), ..., s(p) are not negligible (qr step). + // kase = 4 if e(p-1) is negligible (convergence). + + for (k = p-2; k >= -1; k--) { + if (k == -1) { + break; + } + if (abs(e[k]) <= eps*(abs(s[k]) + abs(s[k+1]))) { + e[k] = 0.0; + break; + } + } + if (k == p-2) { + kase = 4; + } else { + int ks; + for (ks = p-1; ks >= k; ks--) { + if (ks == k) { + break; + } + Real t( (ks != p ? abs(e[ks]) : 0.) + + (ks != k+1 ? abs(e[ks-1]) : 0.)); + if (abs(s[ks]) <= eps*t) { + s[ks] = 0.0; + break; + } + } + if (ks == k) { + kase = 3; + } else if (ks == p-1) { + kase = 1; + } else { + kase = 2; + k = ks; + } + } + k++; + + // Perform the task indicated by kase. + + switch (kase) { + + // Deflate negligible s(p). + + case 1: { + Real f(e[p-2]); + e[p-2] = 0.0; + for (j = p-2; j >= k; j--) { + Real t( hypot(s[j],f)); + Real cs(s[j]/t); + Real sn(f/t); + s[j] = t; + if (j != k) { + f = -sn*e[j-1]; + e[j-1] = cs*e[j-1]; + } + if (wantv) { + for (i = 0; i < n; i++) { + t = cs*V[i][j] + sn*V[i][p-1]; + V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1]; + V[i][j] = t; + } + } + } + } + break; + + // Split at negligible s(k). + + case 2: { + Real f(e[k-1]); + e[k-1] = 0.0; + for (j = k; j < p; j++) { + Real t(hypot(s[j],f)); + Real cs( s[j]/t); + Real sn(f/t); + s[j] = t; + f = -sn*e[j]; + e[j] = cs*e[j]; + if (wantu) { + for (i = 0; i < m; i++) { + t = cs*U[i][j] + sn*U[i][k-1]; + U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1]; + U[i][j] = t; + } + } + } + } + break; + + // Perform one qr step. + + case 3: { + + // Calculate the shift. + + Real scale = std::max(std::max(std::max(std::max( + abs(s[p-1]),abs(s[p-2])),abs(e[p-2])), + abs(s[k])),abs(e[k])); + Real sp = s[p-1]/scale; + Real spm1 = s[p-2]/scale; + Real epm1 = e[p-2]/scale; + Real sk = s[k]/scale; + Real ek = e[k]/scale; + Real b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; + Real c = (sp*epm1)*(sp*epm1); + Real shift = 0.0; + if ((b != 0.0) || (c != 0.0)) { + shift = sqrt(b*b + c); + if (b < 0.0) { + shift = -shift; + } + shift = c/(b + shift); + } + Real f = (sk + sp)*(sk - sp) + shift; + Real g = sk*ek; + + // Chase zeros. + + for (j = k; j < p-1; j++) { + Real t = hypot(f,g); + Real cs = f/t; + Real sn = g/t; + if (j != k) { + e[j-1] = t; + } + f = cs*s[j] + sn*e[j]; + e[j] = cs*e[j] - sn*s[j]; + g = sn*s[j+1]; + s[j+1] = cs*s[j+1]; + if (wantv) { + for (i = 0; i < n; i++) { + t = cs*V[i][j] + sn*V[i][j+1]; + V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1]; + V[i][j] = t; + } + } + t = hypot(f,g); + cs = f/t; + sn = g/t; + s[j] = t; + f = cs*e[j] + sn*s[j+1]; + s[j+1] = -sn*e[j] + cs*s[j+1]; + g = sn*e[j+1]; + e[j+1] = cs*e[j+1]; + if (wantu && (j < m-1)) { + for (i = 0; i < m; i++) { + t = cs*U[i][j] + sn*U[i][j+1]; + U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1]; + U[i][j] = t; + } + } + } + e[p-2] = f; + iter = iter + 1; + } + break; + + // Convergence. + + case 4: { + + // Make the singular values positive. + + if (s[k] <= 0.0) { + s[k] = (s[k] < 0.0 ? -s[k] : 0.0); + if (wantv) { + for (i = 0; i <= pp; i++) { + V[i][k] = -V[i][k]; + } + } + } + + // Order the singular values. + + while (k < pp) { + if (s[k] >= s[k+1]) { + break; + } + Real t = s[k]; + s[k] = s[k+1]; + s[k+1] = t; + if (wantv && (k < n-1)) { + for (i = 0; i < n; i++) { + t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t; + } + } + if (wantu && (k < m-1)) { + for (i = 0; i < m; i++) { + t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t; + } + } + k++; + } + iter = 0; + p--; + } + break; + } + } + } + + + void getU (Array2D<Real> &A) + { + int minm = std::min(m+1,n); + + A = Array2D<Real>(m, minm); + + for (int i=0; i<m; i++) + for (int j=0; j<minm; j++) + A[i][j] = U[i][j]; + + } + + /* Return the right singular vectors */ + + void getV (Array2D<Real> &A) + { + A = V; + } + + /** Return the one-dimensional array of singular values */ + + void getSingularValues (Array1D<Real> &x) + { + x = s; + } + + /** Return the diagonal matrix of singular values + @return S + */ + + void getS (Array2D<Real> &A) { + A = Array2D<Real>(n,n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + A[i][j] = 0.0; + } + A[i][i] = s[i]; + } + } + + /** Two norm (max(S)) */ + + Real norm2 () { + return s[0]; + } + + /** Two norm of condition number (max(S)/min(S)) */ + + Real cond () { + return s[0]/s[std::min(m,n)-1]; + } + + /** Effective numerical matrix rank + @return Number of nonnegligible singular values. + */ + + int rank () + { + Real eps = pow(2.0,-52.0); + Real tol = std::max(m,n)*s[0]*eps; + int r = 0; + for (int i = 0; i < s.dim(); i++) { + if (s[i] > tol) { + r++; + } + } + return r; + } +}; + +} +#endif +// JAMA_SVD_H diff --git a/lib/include/tnt/tnt.h b/lib/include/tnt/tnt.h new file mode 100644 index 0000000..92463e0 --- /dev/null +++ b/lib/include/tnt/tnt.h @@ -0,0 +1,64 @@ +/* +* +* Template Numerical Toolkit (TNT): Linear Algebra Module +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +#ifndef TNT_H +#define TNT_H + + + +//--------------------------------------------------------------------- +// Define this macro if you want TNT to track some of the out-of-bounds +// indexing. This can encur a small run-time overhead, but is recommended +// while developing code. It can be turned off for production runs. +// +// #define TNT_BOUNDS_CHECK +//--------------------------------------------------------------------- +// + +//#define TNT_BOUNDS_CHECK + + + +#include "tnt_version.h" +#include "tnt_math_utils.h" +#include "tnt_array1d.h" +#include "tnt_array2d.h" +#include "tnt_array3d.h" +#include "tnt_array1d_utils.h" +#include "tnt_array2d_utils.h" +#include "tnt_array3d_utils.h" + +#include "tnt_fortran_array1d.h" +#include "tnt_fortran_array2d.h" +#include "tnt_fortran_array3d.h" +#include "tnt_fortran_array1d_utils.h" +#include "tnt_fortran_array2d_utils.h" +#include "tnt_fortran_array3d_utils.h" + +#include "tnt_sparse_matrix_csr.h" + +#include "tnt_stopwatch.h" +#include "tnt_subscript.h" +#include "tnt_vec.h" +#include "tnt_cmat.h" + + +#endif +// TNT_H diff --git a/lib/include/tnt/tnt_array1d.h b/lib/include/tnt/tnt_array1d.h new file mode 100644 index 0000000..858df57 --- /dev/null +++ b/lib/include/tnt/tnt_array1d.h @@ -0,0 +1,278 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_ARRAY1D_H +#define TNT_ARRAY1D_H + +//#include <cstdlib> +#include <iostream> + +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif + + +#include "tnt_i_refvec.h" + +namespace TNT +{ + +template <class T> +class Array1D +{ + + private: + + /* ... */ + i_refvec<T> v_; + int n_; + T* data_; /* this normally points to v_.begin(), but + * could also point to a portion (subvector) + * of v_. + */ + + void copy_(T* p, const T* q, int len) const; + void set_(T* begin, T* end, const T& val); + + + public: + + typedef T value_type; + + + Array1D(); + explicit Array1D(int n); + Array1D(int n, const T &a); + Array1D(int n, T *a); + inline Array1D(const Array1D &A); + inline operator T*(); + inline operator const T*(); + inline Array1D & operator=(const T &a); + inline Array1D & operator=(const Array1D &A); + inline Array1D & ref(const Array1D &A); + Array1D copy() const; + Array1D & inject(const Array1D & A); + inline T& operator[](int i); + inline const T& operator[](int i) const; + inline int dim1() const; + inline int dim() const; + ~Array1D(); + + + /* ... extended interface ... */ + + inline int ref_count() const; + inline Array1D<T> subarray(int i0, int i1); + +}; + + + + +template <class T> +Array1D<T>::Array1D() : v_(), n_(0), data_(0) {} + +template <class T> +Array1D<T>::Array1D(const Array1D<T> &A) : v_(A.v_), n_(A.n_), + data_(A.data_) +{ +#ifdef TNT_DEBUG + std::cout << "Created Array1D(const Array1D<T> &A) \n"; +#endif + +} + + +template <class T> +Array1D<T>::Array1D(int n) : v_(n), n_(n), data_(v_.begin()) +{ +#ifdef TNT_DEBUG + std::cout << "Created Array1D(int n) \n"; +#endif +} + +template <class T> +Array1D<T>::Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin()) +{ +#ifdef TNT_DEBUG + std::cout << "Created Array1D(int n, const T& val) \n"; +#endif + set_(data_, data_+ n, val); + +} + +template <class T> +Array1D<T>::Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin()) +{ +#ifdef TNT_DEBUG + std::cout << "Created Array1D(int n, T* a) \n"; +#endif +} + +template <class T> +inline Array1D<T>::operator T*() +{ + return &(v_[0]); +} + + +template <class T> +inline Array1D<T>::operator const T*() +{ + return &(v_[0]); +} + + + +template <class T> +inline T& Array1D<T>::operator[](int i) +{ +#ifdef TNT_BOUNDS_CHECK + assert(i>= 0); + assert(i < n_); +#endif + return data_[i]; +} + +template <class T> +inline const T& Array1D<T>::operator[](int i) const +{ +#ifdef TNT_BOUNDS_CHECK + assert(i>= 0); + assert(i < n_); +#endif + return data_[i]; +} + + + + +template <class T> +Array1D<T> & Array1D<T>::operator=(const T &a) +{ + set_(data_, data_+n_, a); + return *this; +} + +template <class T> +Array1D<T> Array1D<T>::copy() const +{ + Array1D A( n_); + copy_(A.data_, data_, n_); + + return A; +} + + +template <class T> +Array1D<T> & Array1D<T>::inject(const Array1D &A) +{ + if (A.n_ == n_) + copy_(data_, A.data_, n_); + + return *this; +} + + + + + +template <class T> +Array1D<T> & Array1D<T>::ref(const Array1D<T> &A) +{ + if (this != &A) + { + v_ = A.v_; /* operator= handles the reference counting. */ + n_ = A.n_; + data_ = A.data_; + + } + return *this; +} + +template <class T> +Array1D<T> & Array1D<T>::operator=(const Array1D<T> &A) +{ + return ref(A); +} + +template <class T> +inline int Array1D<T>::dim1() const { return n_; } + +template <class T> +inline int Array1D<T>::dim() const { return n_; } + +template <class T> +Array1D<T>::~Array1D() {} + + +/* ............................ exented interface ......................*/ + +template <class T> +inline int Array1D<T>::ref_count() const +{ + return v_.ref_count(); +} + +template <class T> +inline Array1D<T> Array1D<T>::subarray(int i0, int i1) +{ + if ((i0 > 0) && (i1 < n_) || (i0 <= i1)) + { + Array1D<T> X(*this); /* create a new instance of this array. */ + X.n_ = i1-i0+1; + X.data_ += i0; + + return X; + } + else + { + return Array1D<T>(); + } +} + + +/* private internal functions */ + + +template <class T> +void Array1D<T>::set_(T* begin, T* end, const T& a) +{ + for (T* p=begin; p<end; p++) + *p = a; + +} + +template <class T> +void Array1D<T>::copy_(T* p, const T* q, int len) const +{ + T *end = p + len; + while (p<end ) + *p++ = *q++; + +} + + +} /* namespace TNT */ + +#endif +/* TNT_ARRAY1D_H */ + diff --git a/lib/include/tnt/tnt_array1d_utils.h b/lib/include/tnt/tnt_array1d_utils.h new file mode 100644 index 0000000..683e0e2 --- /dev/null +++ b/lib/include/tnt/tnt_array1d_utils.h @@ -0,0 +1,230 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + +#ifndef TNT_ARRAY1D_UTILS_H +#define TNT_ARRAY1D_UTILS_H + +#include <cstdlib> +#include <cassert> + +namespace TNT +{ + + +template <class T> +std::ostream& operator<<(std::ostream &s, const Array1D<T> &A) +{ + int N=A.dim1(); + +#ifdef TNT_DEBUG + s << "addr: " << (void *) &A[0] << "\n"; +#endif + s << N << "\n"; + for (int j=0; j<N; j++) + { + s << A[j] << "\n"; + } + s << "\n"; + + return s; +} + +template <class T> +std::istream& operator>>(std::istream &s, Array1D<T> &A) +{ + int N; + s >> N; + + Array1D<T> B(N); + for (int i=0; i<N; i++) + s >> B[i]; + A = B; + return s; +} + + + +template <class T> +Array1D<T> operator+(const Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Array1D<T>(); + + else + { + Array1D<T> C(n); + + for (int i=0; i<n; i++) + { + C[i] = A[i] + B[i]; + } + return C; + } +} + + + +template <class T> +Array1D<T> operator-(const Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Array1D<T>(); + + else + { + Array1D<T> C(n); + + for (int i=0; i<n; i++) + { + C[i] = A[i] - B[i]; + } + return C; + } +} + + +template <class T> +Array1D<T> operator*(const Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Array1D<T>(); + + else + { + Array1D<T> C(n); + + for (int i=0; i<n; i++) + { + C[i] = A[i] * B[i]; + } + return C; + } +} + + +template <class T> +Array1D<T> operator/(const Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Array1D<T>(); + + else + { + Array1D<T> C(n); + + for (int i=0; i<n; i++) + { + C[i] = A[i] / B[i]; + } + return C; + } +} + + + + + + + + + +template <class T> +Array1D<T>& operator+=(Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=0; i<n; i++) + { + A[i] += B[i]; + } + } + return A; +} + + + + +template <class T> +Array1D<T>& operator-=(Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=0; i<n; i++) + { + A[i] -= B[i]; + } + } + return A; +} + + + +template <class T> +Array1D<T>& operator*=(Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=0; i<n; i++) + { + A[i] *= B[i]; + } + } + return A; +} + + + + +template <class T> +Array1D<T>& operator/=(Array1D<T> &A, const Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=0; i<n; i++) + { + A[i] /= B[i]; + } + } + return A; +} + + + + + + +} // namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_array2d.h b/lib/include/tnt/tnt_array2d.h new file mode 100644 index 0000000..c791575 --- /dev/null +++ b/lib/include/tnt/tnt_array2d.h @@ -0,0 +1,315 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_ARRAY2D_H +#define TNT_ARRAY2D_H + +#include <cstdlib> +#include <iostream> +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif + +#include "tnt_array1d.h" + +namespace TNT +{ + +template <class T> +class Array2D +{ + + + private: + + + + Array1D<T> data_; + Array1D<T*> v_; + int m_; + int n_; + + public: + + typedef T value_type; + Array2D(); + Array2D(int m, int n); + Array2D(int m, int n, T *a); + Array2D(int m, int n, const T &a); + inline Array2D(const Array2D &A); + inline operator T**(); + inline operator const T**(); + inline Array2D & operator=(const T &a); + inline Array2D & operator=(const Array2D &A); + inline Array2D & ref(const Array2D &A); + Array2D copy() const; + Array2D & inject(const Array2D & A); + inline T* operator[](int i); + inline const T* operator[](int i) const; + inline int dim1() const; + inline int dim2() const; + ~Array2D(); + + /* extended interface (not part of the standard) */ + + + inline int ref_count(); + inline int ref_count_data(); + inline int ref_count_dim1(); + Array2D subarray(int i0, int i1, int j0, int j1); + +}; + + +template <class T> +Array2D<T>::Array2D() : data_(), v_(), m_(0), n_(0) {} + +template <class T> +Array2D<T>::Array2D(const Array2D<T> &A) : data_(A.data_), v_(A.v_), + m_(A.m_), n_(A.n_) {} + + + + +template <class T> +Array2D<T>::Array2D(int m, int n) : data_(m*n), v_(m), m_(m), n_(n) +{ + if (m>0 && n>0) + { + T* p = &(data_[0]); + for (int i=0; i<m; i++) + { + v_[i] = p; + p += n; + } + } +} + + + +template <class T> +Array2D<T>::Array2D(int m, int n, const T &val) : data_(m*n), v_(m), + m_(m), n_(n) +{ + if (m>0 && n>0) + { + data_ = val; + T* p = &(data_[0]); + for (int i=0; i<m; i++) + { + v_[i] = p; + p += n; + } + } +} + +template <class T> +Array2D<T>::Array2D(int m, int n, T *a) : data_(m*n, a), v_(m), m_(m), n_(n) +{ + if (m>0 && n>0) + { + T* p = &(data_[0]); + + for (int i=0; i<m; i++) + { + v_[i] = p; + p += n; + } + } +} + + +template <class T> +inline T* Array2D<T>::operator[](int i) +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 0); + assert(i < m_); +#endif + +return v_[i]; + +} + + +template <class T> +inline const T* Array2D<T>::operator[](int i) const +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 0); + assert(i < m_); +#endif + +return v_[i]; + +} + +template <class T> +Array2D<T> & Array2D<T>::operator=(const T &a) +{ + /* non-optimzied, but will work with subarrays in future verions */ + + for (int i=0; i<m_; i++) + for (int j=0; j<n_; j++) + v_[i][j] = a; + return *this; +} + + + + +template <class T> +Array2D<T> Array2D<T>::copy() const +{ + Array2D A(m_, n_); + + for (int i=0; i<m_; i++) + for (int j=0; j<n_; j++) + A[i][j] = v_[i][j]; + + + return A; +} + + +template <class T> +Array2D<T> & Array2D<T>::inject(const Array2D &A) +{ + if (A.m_ == m_ && A.n_ == n_) + { + for (int i=0; i<m_; i++) + for (int j=0; j<n_; j++) + v_[i][j] = A[i][j]; + } + return *this; +} + + + + +template <class T> +Array2D<T> & Array2D<T>::ref(const Array2D<T> &A) +{ + if (this != &A) + { + v_ = A.v_; + data_ = A.data_; + m_ = A.m_; + n_ = A.n_; + + } + return *this; +} + + + +template <class T> +Array2D<T> & Array2D<T>::operator=(const Array2D<T> &A) +{ + return ref(A); +} + +template <class T> +inline int Array2D<T>::dim1() const { return m_; } + +template <class T> +inline int Array2D<T>::dim2() const { return n_; } + + +template <class T> +Array2D<T>::~Array2D() {} + + + + +template <class T> +inline Array2D<T>::operator T**() +{ + return &(v_[0]); +} +template <class T> +inline Array2D<T>::operator const T**() +{ + return &(v_[0]); +} + +/* ............... extended interface ............... */ +/** + Create a new view to a subarray defined by the boundaries + [i0][i0] and [i1][j1]. The size of the subarray is + (i1-i0) by (j1-j0). If either of these lengths are zero + or negative, the subarray view is null. + +*/ +template <class T> +Array2D<T> Array2D<T>::subarray(int i0, int i1, int j0, int j1) +{ + Array2D<T> A; + int m = i1-i0+1; + int n = j1-j0+1; + + /* if either length is zero or negative, this is an invalide + subarray. return a null view. + */ + if (m<1 || n<1) + return A; + + A.data_ = data_; + A.m_ = m; + A.n_ = n; + A.v_ = Array1D<T*>(m); + T* p = &(data_[0]) + i0 * n_ + j0; + for (int i=0; i<m; i++) + { + A.v_[i] = p + i*n_; + + } + return A; +} + +template <class T> +inline int Array2D<T>::ref_count() +{ + return ref_count_data(); +} + + + +template <class T> +inline int Array2D<T>::ref_count_data() +{ + return data_.ref_count(); +} + +template <class T> +inline int Array2D<T>::ref_count_dim1() +{ + return v_.ref_count(); +} + + + + +} /* namespace TNT */ + +#endif +/* TNT_ARRAY2D_H */ + diff --git a/lib/include/tnt/tnt_array2d_utils.h b/lib/include/tnt/tnt_array2d_utils.h new file mode 100644 index 0000000..7041ed3 --- /dev/null +++ b/lib/include/tnt/tnt_array2d_utils.h @@ -0,0 +1,287 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +#ifndef TNT_ARRAY2D_UTILS_H +#define TNT_ARRAY2D_UTILS_H + +#include <cstdlib> +#include <cassert> + +namespace TNT +{ + + +template <class T> +std::ostream& operator<<(std::ostream &s, const Array2D<T> &A) +{ + int M=A.dim1(); + int N=A.dim2(); + + s << M << " " << N << "\n"; + + for (int i=0; i<M; i++) + { + for (int j=0; j<N; j++) + { + s << A[i][j] << " "; + } + s << "\n"; + } + + + return s; +} + +template <class T> +std::istream& operator>>(std::istream &s, Array2D<T> &A) +{ + + int M, N; + + s >> M >> N; + + Array2D<T> B(M,N); + + for (int i=0; i<M; i++) + for (int j=0; j<N; j++) + { + s >> B[i][j]; + } + + A = B; + return s; +} + + +template <class T> +Array2D<T> operator+(const Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Array2D<T>(); + + else + { + Array2D<T> C(m,n); + + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + C[i][j] = A[i][j] + B[i][j]; + } + return C; + } +} + +template <class T> +Array2D<T> operator-(const Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Array2D<T>(); + + else + { + Array2D<T> C(m,n); + + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + C[i][j] = A[i][j] - B[i][j]; + } + return C; + } +} + + +template <class T> +Array2D<T> operator*(const Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Array2D<T>(); + + else + { + Array2D<T> C(m,n); + + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + C[i][j] = A[i][j] * B[i][j]; + } + return C; + } +} + + + + +template <class T> +Array2D<T> operator/(const Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Array2D<T>(); + + else + { + Array2D<T> C(m,n); + + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + C[i][j] = A[i][j] / B[i][j]; + } + return C; + } +} + + + + + +template <class T> +Array2D<T>& operator+=(Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + A[i][j] += B[i][j]; + } + } + return A; +} + + + +template <class T> +Array2D<T>& operator-=(Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + A[i][j] -= B[i][j]; + } + } + return A; +} + + + +template <class T> +Array2D<T>& operator*=(Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + A[i][j] *= B[i][j]; + } + } + return A; +} + + + + + +template <class T> +Array2D<T>& operator/=(Array2D<T> &A, const Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=0; i<m; i++) + { + for (int j=0; j<n; j++) + A[i][j] /= B[i][j]; + } + } + return A; +} + +/** + Matrix Multiply: compute C = A*B, where C[i][j] + is the dot-product of row i of A and column j of B. + + + @param A an (m x n) array + @param B an (n x k) array + @return the (m x k) array A*B, or a null array (0x0) + if the matrices are non-conformant (i.e. the number + of columns of A are different than the number of rows of B.) + + +*/ +template <class T> +Array2D<T> matmult(const Array2D<T> &A, const Array2D<T> &B) +{ + if (A.dim2() != B.dim1()) + return Array2D<T>(); + + int M = A.dim1(); + int N = A.dim2(); + int K = B.dim2(); + + Array2D<T> C(M,K); + + for (int i=0; i<M; i++) + for (int j=0; j<K; j++) + { + T sum = 0; + + for (int k=0; k<N; k++) + sum += A[i][k] * B [k][j]; + + C[i][j] = sum; + } + + return C; + +} + +} // namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_array3d.h b/lib/include/tnt/tnt_array3d.h new file mode 100644 index 0000000..c210d2e --- /dev/null +++ b/lib/include/tnt/tnt_array3d.h @@ -0,0 +1,296 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_ARRAY3D_H +#define TNT_ARRAY3D_H + +#include <cstdlib> +#include <iostream> +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif + +#include "tnt_array1d.h" +#include "tnt_array2d.h" + +namespace TNT +{ + +template <class T> +class Array3D +{ + + + private: + Array1D<T> data_; + Array2D<T*> v_; + int m_; + int n_; + int g_; + + + public: + + typedef T value_type; + + Array3D(); + Array3D(int m, int n, int g); + Array3D(int m, int n, int g, T val); + Array3D(int m, int n, int g, T *a); + + inline operator T***(); + inline operator const T***(); + inline Array3D(const Array3D &A); + inline Array3D & operator=(const T &a); + inline Array3D & operator=(const Array3D &A); + inline Array3D & ref(const Array3D &A); + Array3D copy() const; + Array3D & inject(const Array3D & A); + + inline T** operator[](int i); + inline const T* const * operator[](int i) const; + inline int dim1() const; + inline int dim2() const; + inline int dim3() const; + ~Array3D(); + + /* extended interface */ + + inline int ref_count(){ return data_.ref_count(); } + Array3D subarray(int i0, int i1, int j0, int j1, + int k0, int k1); +}; + +template <class T> +Array3D<T>::Array3D() : data_(), v_(), m_(0), n_(0) {} + +template <class T> +Array3D<T>::Array3D(const Array3D<T> &A) : data_(A.data_), + v_(A.v_), m_(A.m_), n_(A.n_), g_(A.g_) +{ +} + + + +template <class T> +Array3D<T>::Array3D(int m, int n, int g) : data_(m*n*g), v_(m,n), + m_(m), n_(n), g_(g) +{ + + if (m>0 && n>0 && g>0) + { + T* p = & (data_[0]); + int ng = n_*g_; + + for (int i=0; i<m_; i++) + { + T* ping = p+ i*ng; + for (int j=0; j<n; j++) + v_[i][j] = ping + j*g_; + } + } +} + + + +template <class T> +Array3D<T>::Array3D(int m, int n, int g, T val) : data_(m*n*g, val), + v_(m,n), m_(m), n_(n), g_(g) +{ + if (m>0 && n>0 && g>0) + { + + T* p = & (data_[0]); + int ng = n_*g_; + + for (int i=0; i<m_; i++) + { + T* ping = p+ i*ng; + for (int j=0; j<n; j++) + v_[i][j] = ping + j*g_; + } + } +} + + + +template <class T> +Array3D<T>::Array3D(int m, int n, int g, T* a) : + data_(m*n*g, a), v_(m,n), m_(m), n_(n), g_(g) +{ + + if (m>0 && n>0 && g>0) + { + T* p = & (data_[0]); + int ng = n_*g_; + + for (int i=0; i<m_; i++) + { + T* ping = p+ i*ng; + for (int j=0; j<n; j++) + v_[i][j] = ping + j*g_; + } + } +} + + + +template <class T> +inline T** Array3D<T>::operator[](int i) +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 0); + assert(i < m_); +#endif + +return v_[i]; + +} + +template <class T> +inline const T* const * Array3D<T>::operator[](int i) const +{ return v_[i]; } + +template <class T> +Array3D<T> & Array3D<T>::operator=(const T &a) +{ + for (int i=0; i<m_; i++) + for (int j=0; j<n_; j++) + for (int k=0; k<g_; k++) + v_[i][j][k] = a; + + return *this; +} + +template <class T> +Array3D<T> Array3D<T>::copy() const +{ + Array3D A(m_, n_, g_); + for (int i=0; i<m_; i++) + for (int j=0; j<n_; j++) + for (int k=0; k<g_; k++) + A.v_[i][j][k] = v_[i][j][k]; + + return A; +} + + +template <class T> +Array3D<T> & Array3D<T>::inject(const Array3D &A) +{ + if (A.m_ == m_ && A.n_ == n_ && A.g_ == g_) + + for (int i=0; i<m_; i++) + for (int j=0; j<n_; j++) + for (int k=0; k<g_; k++) + v_[i][j][k] = A.v_[i][j][k]; + + return *this; +} + + + +template <class T> +Array3D<T> & Array3D<T>::ref(const Array3D<T> &A) +{ + if (this != &A) + { + m_ = A.m_; + n_ = A.n_; + g_ = A.g_; + v_ = A.v_; + data_ = A.data_; + } + return *this; +} + +template <class T> +Array3D<T> & Array3D<T>::operator=(const Array3D<T> &A) +{ + return ref(A); +} + + +template <class T> +inline int Array3D<T>::dim1() const { return m_; } + +template <class T> +inline int Array3D<T>::dim2() const { return n_; } + +template <class T> +inline int Array3D<T>::dim3() const { return g_; } + + + +template <class T> +Array3D<T>::~Array3D() {} + +template <class T> +inline Array3D<T>::operator T***() +{ + return v_; +} + + +template <class T> +inline Array3D<T>::operator const T***() +{ + return v_; +} + +/* extended interface */ +template <class T> +Array3D<T> Array3D<T>::subarray(int i0, int i1, int j0, + int j1, int k0, int k1) +{ + + /* check that ranges are valid. */ + if (!( 0 <= i0 && i0 <= i1 && i1 < m_ && + 0 <= j0 && j0 <= j1 && j1 < n_ && + 0 <= k0 && k0 <= k1 && k1 < g_)) + return Array3D<T>(); /* null array */ + + + Array3D<T> A; + A.data_ = data_; + A.m_ = i1-i0+1; + A.n_ = j1-j0+1; + A.g_ = k1-k0+1; + A.v_ = Array2D<T*>(A.m_,A.n_); + T* p = &(data_[0]) + i0*n_*g_ + j0*g_ + k0; + + for (int i=0; i<A.m_; i++) + { + T* ping = p + i*n_*g_; + for (int j=0; j<A.n_; j++) + A.v_[i][j] = ping + j*g_ ; + } + + return A; +} + + + +} /* namespace TNT */ + +#endif +/* TNT_ARRAY3D_H */ + diff --git a/lib/include/tnt/tnt_array3d_utils.h b/lib/include/tnt/tnt_array3d_utils.h new file mode 100644 index 0000000..5acdc1d --- /dev/null +++ b/lib/include/tnt/tnt_array3d_utils.h @@ -0,0 +1,236 @@ + + +#ifndef TNT_ARRAY3D_UTILS_H +#define TNT_ARRAY3D_UTILS_H + +#include <cstdlib> +#include <cassert> + +namespace TNT +{ + + +template <class T> +std::ostream& operator<<(std::ostream &s, const Array3D<T> &A) +{ + int M=A.dim1(); + int N=A.dim2(); + int K=A.dim3(); + + s << M << " " << N << " " << K << "\n"; + + for (int i=0; i<M; i++) + { + for (int j=0; j<N; j++) + { + for (int k=0; k<K; k++) + s << A[i][j][k] << " "; + s << "\n"; + } + s << "\n"; + } + + + return s; +} + +template <class T> +std::istream& operator>>(std::istream &s, Array3D<T> &A) +{ + + int M, N, K; + + s >> M >> N >> K; + + Array3D<T> B(M,N,K); + + for (int i=0; i<M; i++) + for (int j=0; j<N; j++) + for (int k=0; k<K; k++) + s >> B[i][j][k]; + + A = B; + return s; +} + + + +template <class T> +Array3D<T> operator+(const Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Array3D<T>(); + + else + { + Array3D<T> C(m,n,p); + + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + C[i][j][k] = A[i][j][k] + B[i][j][k]; + + return C; + } +} + + +template <class T> +Array3D<T> operator-(const Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Array3D<T>(); + + else + { + Array3D<T> C(m,n,p); + + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + C[i][j][k] = A[i][j][k] - B[i][j][k]; + + return C; + } +} + + + + +template <class T> +Array3D<T> operator*(const Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Array3D<T>(); + + else + { + Array3D<T> C(m,n,p); + + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + C[i][j][k] = A[i][j][k] * B[i][j][k]; + + return C; + } +} + + +template <class T> +Array3D<T> operator/(const Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Array3D<T>(); + + else + { + Array3D<T> C(m,n,p); + + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + C[i][j][k] = A[i][j][k] / B[i][j][k]; + + return C; + } +} + + + +template <class T> +Array3D<T>& operator+=(Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + A[i][j][k] += B[i][j][k]; + } + + return A; +} + +template <class T> +Array3D<T>& operator-=(Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + A[i][j][k] -= B[i][j][k]; + } + + return A; +} + +template <class T> +Array3D<T>& operator*=(Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + A[i][j][k] *= B[i][j][k]; + } + + return A; +} + + +template <class T> +Array3D<T>& operator/=(Array3D<T> &A, const Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=0; i<m; i++) + for (int j=0; j<n; j++) + for (int k=0; k<p; k++) + A[i][j][k] /= B[i][j][k]; + } + + return A; +} + + + + + +} // namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_cmat.h b/lib/include/tnt/tnt_cmat.h new file mode 100644 index 0000000..5ff4c48 --- /dev/null +++ b/lib/include/tnt/tnt_cmat.h @@ -0,0 +1,580 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing +// + +#ifndef TNT_CMAT_H +#define TNT_CMAT_H + +#include "tnt_subscript.h" +#include "tnt_vec.h" +#include <cstdlib> +#include <cassert> +#include <iostream> +#include <sstream> + +namespace TNT +{ + + +template <class T> +class Matrix +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + Subscript m_; + Subscript n_; + Subscript mn_; // total size + T* v_; + T** row_; + T* vm1_ ; // these point to the same data, but are 1-based + T** rowm1_; + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript M, Subscript N) + { + mn_ = M*N; + m_ = M; + n_ = N; + + v_ = new T[mn_]; + row_ = new T*[M]; + rowm1_ = new T*[M]; + + assert(v_ != NULL); + assert(row_ != NULL); + assert(rowm1_ != NULL); + + T* p = v_; + vm1_ = v_ - 1; + for (Subscript i=0; i<M; i++) + { + row_[i] = p; + rowm1_[i] = p-1; + p += N ; + + } + + rowm1_ -- ; // compensate for 1-based offset + } + + void copy(const T* v) + { + Subscript N = m_ * n_; + Subscript i; + +#ifdef TNT_UNROLL_LOOPS + Subscript Nmod4 = N & 3; + Subscript N4 = N - Nmod4; + + for (i=0; i<N4; i+=4) + { + v_[i] = v[i]; + v_[i+1] = v[i+1]; + v_[i+2] = v[i+2]; + v_[i+3] = v[i+3]; + } + + for (i=N4; i< N; i++) + v_[i] = v[i]; +#else + + for (i=0; i< N; i++) + v_[i] = v[i]; +#endif + } + + void set(const T& val) + { + Subscript N = m_ * n_; + Subscript i; + +#ifdef TNT_UNROLL_LOOPS + Subscript Nmod4 = N & 3; + Subscript N4 = N - Nmod4; + + for (i=0; i<N4; i+=4) + { + v_[i] = val; + v_[i+1] = val; + v_[i+2] = val; + v_[i+3] = val; + } + + for (i=N4; i< N; i++) + v_[i] = val; +#else + + for (i=0; i< N; i++) + v_[i] = val; + +#endif + } + + + + void destroy() + { + /* do nothing, if no memory has been previously allocated */ + if (v_ == NULL) return ; + + /* if we are here, then matrix was previously allocated */ + if (v_ != NULL) delete [] (v_); + if (row_ != NULL) delete [] (row_); + + /* return rowm1_ back to original value */ + rowm1_ ++; + if (rowm1_ != NULL ) delete [] (rowm1_); + } + + + public: + + operator T**(){ return row_; } + operator T**() const { return row_; } + + + Subscript size() const { return mn_; } + + // constructors + + Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {}; + + Matrix(const Matrix<T> &A) + { + initialize(A.m_, A.n_); + copy(A.v_); + } + + Matrix(Subscript M, Subscript N, const T& value = T()) + { + initialize(M,N); + set(value); + } + + Matrix(Subscript M, Subscript N, const T* v) + { + initialize(M,N); + copy(v); + } + + Matrix(Subscript M, Subscript N, const char *s) + { + initialize(M,N); + //std::istrstream ins(s); + std::istringstream ins(s); + + Subscript i, j; + + for (i=0; i<M; i++) + for (j=0; j<N; j++) + ins >> row_[i][j]; + } + + // destructor + // + ~Matrix() + { + destroy(); + } + + + // reallocating + // + Matrix<T>& newsize(Subscript M, Subscript N) + { + if (num_rows() == M && num_cols() == N) + return *this; + + destroy(); + initialize(M,N); + + return *this; + } + + + + + // assignments + // + Matrix<T>& operator=(const Matrix<T> &A) + { + if (v_ == A.v_) + return *this; + + if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.m_, A.n_); + copy(A.v_); + } + + return *this; + } + + Matrix<T>& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + + Subscript dim(Subscript d) const + { +#ifdef TNT_BOUNDS_CHECK + assert( d >= 1); + assert( d <= 2); +#endif + return (d==1) ? m_ : ((d==2) ? n_ : 0); + } + + Subscript num_rows() const { return m_; } + Subscript num_cols() const { return n_; } + + + + + inline T* operator[](Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < m_) ; +#endif + return row_[i]; + } + + inline const T* operator[](Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < m_) ; +#endif + return row_[i]; + } + + inline reference operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= mn_) ; +#endif + return vm1_[i]; + } + + inline const_reference operator()(Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= mn_) ; +#endif + return vm1_[i]; + } + + + + inline reference operator()(Subscript i, Subscript j) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return rowm1_[i][j]; + } + + + + inline const_reference operator() (Subscript i, Subscript j) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= m_) ; + assert(1<=j); + assert(j <= n_); +#endif + return rowm1_[i][j]; + } + + + + +}; + + +/* *************************** I/O ********************************/ + +template <class T> +std::ostream& operator<<(std::ostream &s, const Matrix<T> &A) +{ + Subscript M=A.num_rows(); + Subscript N=A.num_cols(); + + s << M << " " << N << "\n"; + + for (Subscript i=0; i<M; i++) + { + for (Subscript j=0; j<N; j++) + { + s << A[i][j] << " "; + } + s << "\n"; + } + + + return s; +} + +template <class T> +std::istream& operator>>(std::istream &s, Matrix<T> &A) +{ + + Subscript M, N; + + s >> M >> N; + + if ( !(M == A.num_rows() && N == A.num_cols() )) + { + A.newsize(M,N); + } + + + for (Subscript i=0; i<M; i++) + for (Subscript j=0; j<N; j++) + { + s >> A[i][j]; + } + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + + +template <class T> +Matrix<T> operator+(const Matrix<T> &A, + const Matrix<T> &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix<T> tmp(M,N); + Subscript i,j; + + for (i=0; i<M; i++) + for (j=0; j<N; j++) + tmp[i][j] = A[i][j] + B[i][j]; + + return tmp; +} + +template <class T> +Matrix<T> operator-(const Matrix<T> &A, + const Matrix<T> &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix<T> tmp(M,N); + Subscript i,j; + + for (i=0; i<M; i++) + for (j=0; j<N; j++) + tmp[i][j] = A[i][j] - B[i][j]; + + return tmp; +} + +template <class T> +Matrix<T> mult_element(const Matrix<T> &A, + const Matrix<T> &B) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + assert(M==B.num_rows()); + assert(N==B.num_cols()); + + Matrix<T> tmp(M,N); + Subscript i,j; + + for (i=0; i<M; i++) + for (j=0; j<N; j++) + tmp[i][j] = A[i][j] * B[i][j]; + + return tmp; +} + + +template <class T> +Matrix<T> transpose(const Matrix<T> &A) +{ + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Matrix<T> S(N,M); + Subscript i, j; + + for (i=0; i<M; i++) + for (j=0; j<N; j++) + S[j][i] = A[i][j]; + + return S; +} + + + +template <class T> +inline Matrix<T> matmult(const Matrix<T> &A, + const Matrix<T> &B) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == B.num_rows()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + Matrix<T> tmp(M,K); + T sum; + + for (Subscript i=0; i<M; i++) + for (Subscript k=0; k<K; k++) + { + sum = 0; + for (Subscript j=0; j<N; j++) + sum = sum + A[i][j] * B[j][k]; + + tmp[i][k] = sum; + } + + return tmp; +} + +template <class T> +inline Matrix<T> operator*(const Matrix<T> &A, + const Matrix<T> &B) +{ + return matmult(A,B); +} + +template <class T> +inline int matmult(Matrix<T>& C, const Matrix<T> &A, + const Matrix<T> &B) +{ + + assert(A.num_cols() == B.num_rows()); + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + Subscript K = B.num_cols(); + + C.newsize(M,K); + + T sum; + + const T* row_i; + const T* col_k; + + for (Subscript i=0; i<M; i++) + for (Subscript k=0; k<K; k++) + { + row_i = &(A[i][0]); + col_k = &(B[0][k]); + sum = 0; + for (Subscript j=0; j<N; j++) + { + sum += *row_i * *col_k; + row_i++; + col_k += K; + } + C[i][k] = sum; + } + + return 0; +} + + +template <class T> +Vector<T> matmult(const Matrix<T> &A, const Vector<T> &x) +{ + +#ifdef TNT_BOUNDS_CHECK + assert(A.num_cols() == x.dim()); +#endif + + Subscript M = A.num_rows(); + Subscript N = A.num_cols(); + + Vector<T> tmp(M); + T sum; + + for (Subscript i=0; i<M; i++) + { + sum = 0; + const T* rowi = A[i]; + for (Subscript j=0; j<N; j++) + sum = sum + rowi[j] * x[j]; + + tmp[i] = sum; + } + + return tmp; +} + +template <class T> +inline Vector<T> operator*(const Matrix<T> &A, const Vector<T> &x) +{ + return matmult(A,x); +} + +} // namespace TNT + +#endif +// CMAT_H diff --git a/lib/include/tnt/tnt_fortran_array1d.h b/lib/include/tnt/tnt_fortran_array1d.h new file mode 100644 index 0000000..ad3bba0 --- /dev/null +++ b/lib/include/tnt/tnt_fortran_array1d.h @@ -0,0 +1,267 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_FORTRAN_ARRAY1D_H +#define TNT_FORTRAN_ARRAY1D_H + +#include <cstdlib> +#include <iostream> + +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif + + +#include "tnt_i_refvec.h" + +namespace TNT +{ + +template <class T> +class Fortran_Array1D +{ + + private: + + i_refvec<T> v_; + int n_; + T* data_; /* this normally points to v_.begin(), but + * could also point to a portion (subvector) + * of v_. + */ + + void initialize_(int n); + void copy_(T* p, const T* q, int len) const; + void set_(T* begin, T* end, const T& val); + + + public: + + typedef T value_type; + + + Fortran_Array1D(); + explicit Fortran_Array1D(int n); + Fortran_Array1D(int n, const T &a); + Fortran_Array1D(int n, T *a); + inline Fortran_Array1D(const Fortran_Array1D &A); + inline Fortran_Array1D & operator=(const T &a); + inline Fortran_Array1D & operator=(const Fortran_Array1D &A); + inline Fortran_Array1D & ref(const Fortran_Array1D &A); + Fortran_Array1D copy() const; + Fortran_Array1D & inject(const Fortran_Array1D & A); + inline T& operator()(int i); + inline const T& operator()(int i) const; + inline int dim1() const; + inline int dim() const; + ~Fortran_Array1D(); + + + /* ... extended interface ... */ + + inline int ref_count() const; + inline Fortran_Array1D<T> subarray(int i0, int i1); + +}; + + + + +template <class T> +Fortran_Array1D<T>::Fortran_Array1D() : v_(), n_(0), data_(0) {} + +template <class T> +Fortran_Array1D<T>::Fortran_Array1D(const Fortran_Array1D<T> &A) : v_(A.v_), n_(A.n_), + data_(A.data_) +{ +#ifdef TNT_DEBUG + std::cout << "Created Fortran_Array1D(const Fortran_Array1D<T> &A) \n"; +#endif + +} + + +template <class T> +Fortran_Array1D<T>::Fortran_Array1D(int n) : v_(n), n_(n), data_(v_.begin()) +{ +#ifdef TNT_DEBUG + std::cout << "Created Fortran_Array1D(int n) \n"; +#endif +} + +template <class T> +Fortran_Array1D<T>::Fortran_Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin()) +{ +#ifdef TNT_DEBUG + std::cout << "Created Fortran_Array1D(int n, const T& val) \n"; +#endif + set_(data_, data_+ n, val); + +} + +template <class T> +Fortran_Array1D<T>::Fortran_Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin()) +{ +#ifdef TNT_DEBUG + std::cout << "Created Fortran_Array1D(int n, T* a) \n"; +#endif +} + +template <class T> +inline T& Fortran_Array1D<T>::operator()(int i) +{ +#ifdef TNT_BOUNDS_CHECK + assert(i>= 1); + assert(i <= n_); +#endif + return data_[i-1]; +} + +template <class T> +inline const T& Fortran_Array1D<T>::operator()(int i) const +{ +#ifdef TNT_BOUNDS_CHECK + assert(i>= 1); + assert(i <= n_); +#endif + return data_[i-1]; +} + + + + +template <class T> +Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const T &a) +{ + set_(data_, data_+n_, a); + return *this; +} + +template <class T> +Fortran_Array1D<T> Fortran_Array1D<T>::copy() const +{ + Fortran_Array1D A( n_); + copy_(A.data_, data_, n_); + + return A; +} + + +template <class T> +Fortran_Array1D<T> & Fortran_Array1D<T>::inject(const Fortran_Array1D &A) +{ + if (A.n_ == n_) + copy_(data_, A.data_, n_); + + return *this; +} + + + + + +template <class T> +Fortran_Array1D<T> & Fortran_Array1D<T>::ref(const Fortran_Array1D<T> &A) +{ + if (this != &A) + { + v_ = A.v_; /* operator= handles the reference counting. */ + n_ = A.n_; + data_ = A.data_; + + } + return *this; +} + +template <class T> +Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const Fortran_Array1D<T> &A) +{ + return ref(A); +} + +template <class T> +inline int Fortran_Array1D<T>::dim1() const { return n_; } + +template <class T> +inline int Fortran_Array1D<T>::dim() const { return n_; } + +template <class T> +Fortran_Array1D<T>::~Fortran_Array1D() {} + + +/* ............................ exented interface ......................*/ + +template <class T> +inline int Fortran_Array1D<T>::ref_count() const +{ + return v_.ref_count(); +} + +template <class T> +inline Fortran_Array1D<T> Fortran_Array1D<T>::subarray(int i0, int i1) +{ +#ifdef TNT_DEBUG + std::cout << "entered subarray. \n"; +#endif + if ((i0 > 0) && (i1 < n_) || (i0 <= i1)) + { + Fortran_Array1D<T> X(*this); /* create a new instance of this array. */ + X.n_ = i1-i0+1; + X.data_ += i0; + + return X; + } + else + { +#ifdef TNT_DEBUG + std::cout << "subarray: null return.\n"; +#endif + return Fortran_Array1D<T>(); + } +} + + +/* private internal functions */ + + +template <class T> +void Fortran_Array1D<T>::set_(T* begin, T* end, const T& a) +{ + for (T* p=begin; p<end; p++) + *p = a; + +} + +template <class T> +void Fortran_Array1D<T>::copy_(T* p, const T* q, int len) const +{ + T *end = p + len; + while (p<end ) + *p++ = *q++; + +} + + +} /* namespace TNT */ + +#endif +/* TNT_FORTRAN_ARRAY1D_H */ + diff --git a/lib/include/tnt/tnt_fortran_array1d_utils.h b/lib/include/tnt/tnt_fortran_array1d_utils.h new file mode 100644 index 0000000..b037b17 --- /dev/null +++ b/lib/include/tnt/tnt_fortran_array1d_utils.h @@ -0,0 +1,242 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + +#ifndef TNT_FORTRAN_ARRAY1D_UTILS_H +#define TNT_FORTRAN_ARRAY1D_UTILS_H + +#include <iostream> + +namespace TNT +{ + + +/** + Write an array to a character outstream. Output format is one that can + be read back in via the in-stream operator: one integer + denoting the array dimension (n), followed by n elements, + one per line. + +*/ +template <class T> +std::ostream& operator<<(std::ostream &s, const Fortran_Array1D<T> &A) +{ + int N=A.dim1(); + + s << N << "\n"; + for (int j=1; j<=N; j++) + { + s << A(j) << "\n"; + } + s << "\n"; + + return s; +} + +/** + Read an array from a character stream. Input format + is one integer, denoting the dimension (n), followed + by n whitespace-separated elments. Newlines are ignored + + <p> + Note: the array being read into references new memory + storage. If the intent is to fill an existing conformant + array, use <code> cin >> B; A.inject(B) ); </code> + instead or read the elements in one-a-time by hand. + + @param s the charater to read from (typically <code>std::in</code>) + @param A the array to read into. +*/ +template <class T> +std::istream& operator>>(std::istream &s, Fortran_Array1D<T> &A) +{ + int N; + s >> N; + + Fortran_Array1D<T> B(N); + for (int i=1; i<=N; i++) + s >> B(i); + A = B; + return s; +} + + +template <class T> +Fortran_Array1D<T> operator+(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Fortran_Array1D<T>(); + + else + { + Fortran_Array1D<T> C(n); + + for (int i=1; i<=n; i++) + { + C(i) = A(i) + B(i); + } + return C; + } +} + + + +template <class T> +Fortran_Array1D<T> operator-(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Fortran_Array1D<T>(); + + else + { + Fortran_Array1D<T> C(n); + + for (int i=1; i<=n; i++) + { + C(i) = A(i) - B(i); + } + return C; + } +} + + +template <class T> +Fortran_Array1D<T> operator*(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Fortran_Array1D<T>(); + + else + { + Fortran_Array1D<T> C(n); + + for (int i=1; i<=n; i++) + { + C(i) = A(i) * B(i); + } + return C; + } +} + + +template <class T> +Fortran_Array1D<T> operator/(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() != n ) + return Fortran_Array1D<T>(); + + else + { + Fortran_Array1D<T> C(n); + + for (int i=1; i<=n; i++) + { + C(i) = A(i) / B(i); + } + return C; + } +} + + + + + + + + + +template <class T> +Fortran_Array1D<T>& operator+=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=1; i<=n; i++) + { + A(i) += B(i); + } + } + return A; +} + + + + +template <class T> +Fortran_Array1D<T>& operator-=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=1; i<=n; i++) + { + A(i) -= B(i); + } + } + return A; +} + + + +template <class T> +Fortran_Array1D<T>& operator*=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=1; i<=n; i++) + { + A(i) *= B(i); + } + } + return A; +} + + + + +template <class T> +Fortran_Array1D<T>& operator/=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B) +{ + int n = A.dim1(); + + if (B.dim1() == n) + { + for (int i=1; i<=n; i++) + { + A(i) /= B(i); + } + } + return A; +} + + +} // namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_fortran_array2d.h b/lib/include/tnt/tnt_fortran_array2d.h new file mode 100644 index 0000000..f307536 --- /dev/null +++ b/lib/include/tnt/tnt_fortran_array2d.h @@ -0,0 +1,225 @@ +/* +* +* Template Numerical Toolkit (TNT): Two-dimensional Fortran numerical array +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_FORTRAN_ARRAY2D_H +#define TNT_FORTRAN_ARRAY2D_H + +#include <cstdlib> +#include <iostream> + +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif + +#include "tnt_i_refvec.h" + +namespace TNT +{ + +template <class T> +class Fortran_Array2D +{ + + + private: + i_refvec<T> v_; + int m_; + int n_; + T* data_; + + + void initialize_(int n); + void copy_(T* p, const T* q, int len); + void set_(T* begin, T* end, const T& val); + + public: + + typedef T value_type; + + Fortran_Array2D(); + Fortran_Array2D(int m, int n); + Fortran_Array2D(int m, int n, T *a); + Fortran_Array2D(int m, int n, const T &a); + inline Fortran_Array2D(const Fortran_Array2D &A); + inline Fortran_Array2D & operator=(const T &a); + inline Fortran_Array2D & operator=(const Fortran_Array2D &A); + inline Fortran_Array2D & ref(const Fortran_Array2D &A); + Fortran_Array2D copy() const; + Fortran_Array2D & inject(const Fortran_Array2D & A); + inline T& operator()(int i, int j); + inline const T& operator()(int i, int j) const ; + inline int dim1() const; + inline int dim2() const; + ~Fortran_Array2D(); + + /* extended interface */ + + inline int ref_count() const; + +}; + +template <class T> +Fortran_Array2D<T>::Fortran_Array2D() : v_(), m_(0), n_(0), data_(0) {} + + +template <class T> +Fortran_Array2D<T>::Fortran_Array2D(const Fortran_Array2D<T> &A) : v_(A.v_), + m_(A.m_), n_(A.n_), data_(A.data_) {} + + + +template <class T> +Fortran_Array2D<T>::Fortran_Array2D(int m, int n) : v_(m*n), m_(m), n_(n), + data_(v_.begin()) {} + +template <class T> +Fortran_Array2D<T>::Fortran_Array2D(int m, int n, const T &val) : + v_(m*n), m_(m), n_(n), data_(v_.begin()) +{ + set_(data_, data_+m*n, val); +} + + +template <class T> +Fortran_Array2D<T>::Fortran_Array2D(int m, int n, T *a) : v_(a), + m_(m), n_(n), data_(v_.begin()) {} + + + + +template <class T> +inline T& Fortran_Array2D<T>::operator()(int i, int j) +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 1); + assert(i <= m_); + assert(j >= 1); + assert(j <= n_); +#endif + + return v_[ (j-1)*m_ + (i-1) ]; + +} + +template <class T> +inline const T& Fortran_Array2D<T>::operator()(int i, int j) const +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 1); + assert(i <= m_); + assert(j >= 1); + assert(j <= n_); +#endif + + return v_[ (j-1)*m_ + (i-1) ]; + +} + + +template <class T> +Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const T &a) +{ + set_(data_, data_+m_*n_, a); + return *this; +} + +template <class T> +Fortran_Array2D<T> Fortran_Array2D<T>::copy() const +{ + + Fortran_Array2D B(m_,n_); + + B.inject(*this); + return B; +} + + +template <class T> +Fortran_Array2D<T> & Fortran_Array2D<T>::inject(const Fortran_Array2D &A) +{ + if (m_ == A.m_ && n_ == A.n_) + copy_(data_, A.data_, m_*n_); + + return *this; +} + + + +template <class T> +Fortran_Array2D<T> & Fortran_Array2D<T>::ref(const Fortran_Array2D<T> &A) +{ + if (this != &A) + { + v_ = A.v_; + m_ = A.m_; + n_ = A.n_; + data_ = A.data_; + } + return *this; +} + +template <class T> +Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const Fortran_Array2D<T> &A) +{ + return ref(A); +} + +template <class T> +inline int Fortran_Array2D<T>::dim1() const { return m_; } + +template <class T> +inline int Fortran_Array2D<T>::dim2() const { return n_; } + + +template <class T> +Fortran_Array2D<T>::~Fortran_Array2D() +{ +} + +template <class T> +inline int Fortran_Array2D<T>::ref_count() const { return v_.ref_count(); } + + + + +template <class T> +void Fortran_Array2D<T>::set_(T* begin, T* end, const T& a) +{ + for (T* p=begin; p<end; p++) + *p = a; + +} + +template <class T> +void Fortran_Array2D<T>::copy_(T* p, const T* q, int len) +{ + T *end = p + len; + while (p<end ) + *p++ = *q++; + +} + + +} /* namespace TNT */ + +#endif +/* TNT_FORTRAN_ARRAY2D_H */ + diff --git a/lib/include/tnt/tnt_fortran_array2d_utils.h b/lib/include/tnt/tnt_fortran_array2d_utils.h new file mode 100644 index 0000000..bb68673 --- /dev/null +++ b/lib/include/tnt/tnt_fortran_array2d_utils.h @@ -0,0 +1,236 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +#ifndef TNT_FORTRAN_ARRAY2D_UTILS_H +#define TNT_FORTRAN_ARRAY2D_UTILS_H + +#include <iostream> + +namespace TNT +{ + + +template <class T> +std::ostream& operator<<(std::ostream &s, const Fortran_Array2D<T> &A) +{ + int M=A.dim1(); + int N=A.dim2(); + + s << M << " " << N << "\n"; + + for (int i=1; i<=M; i++) + { + for (int j=1; j<=N; j++) + { + s << A(i,j) << " "; + } + s << "\n"; + } + + + return s; +} + +template <class T> +std::istream& operator>>(std::istream &s, Fortran_Array2D<T> &A) +{ + + int M, N; + + s >> M >> N; + + Fortran_Array2D<T> B(M,N); + + for (int i=1; i<=M; i++) + for (int j=1; j<=N; j++) + { + s >> B(i,j); + } + + A = B; + return s; +} + + + + +template <class T> +Fortran_Array2D<T> operator+(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Fortran_Array2D<T>(); + + else + { + Fortran_Array2D<T> C(m,n); + + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + C(i,j) = A(i,j) + B(i,j); + } + return C; + } +} + +template <class T> +Fortran_Array2D<T> operator-(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Fortran_Array2D<T>(); + + else + { + Fortran_Array2D<T> C(m,n); + + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + C(i,j) = A(i,j) - B(i,j); + } + return C; + } +} + + +template <class T> +Fortran_Array2D<T> operator*(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Fortran_Array2D<T>(); + + else + { + Fortran_Array2D<T> C(m,n); + + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + C(i,j) = A(i,j) * B(i,j); + } + return C; + } +} + + +template <class T> +Fortran_Array2D<T> operator/(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() != m || B.dim2() != n ) + return Fortran_Array2D<T>(); + + else + { + Fortran_Array2D<T> C(m,n); + + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + C(i,j) = A(i,j) / B(i,j); + } + return C; + } +} + + + +template <class T> +Fortran_Array2D<T>& operator+=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + A(i,j) += B(i,j); + } + } + return A; +} + +template <class T> +Fortran_Array2D<T>& operator-=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + A(i,j) -= B(i,j); + } + } + return A; +} + +template <class T> +Fortran_Array2D<T>& operator*=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + A(i,j) *= B(i,j); + } + } + return A; +} + +template <class T> +Fortran_Array2D<T>& operator/=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + + if (B.dim1() == m || B.dim2() == n ) + { + for (int i=1; i<=m; i++) + { + for (int j=1; j<=n; j++) + A(i,j) /= B(i,j); + } + } + return A; +} + +} // namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_fortran_array3d.h b/lib/include/tnt/tnt_fortran_array3d.h new file mode 100644 index 0000000..e51affb --- /dev/null +++ b/lib/include/tnt/tnt_fortran_array3d.h @@ -0,0 +1,223 @@ +/* +* +* Template Numerical Toolkit (TNT): Three-dimensional Fortran numerical array +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_FORTRAN_ARRAY3D_H +#define TNT_FORTRAN_ARRAY3D_H + +#include <cstdlib> +#include <iostream> +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif +#include "tnt_i_refvec.h" + +namespace TNT +{ + +template <class T> +class Fortran_Array3D +{ + + + private: + + + i_refvec<T> v_; + int m_; + int n_; + int k_; + T* data_; + + public: + + typedef T value_type; + + Fortran_Array3D(); + Fortran_Array3D(int m, int n, int k); + Fortran_Array3D(int m, int n, int k, T *a); + Fortran_Array3D(int m, int n, int k, const T &a); + inline Fortran_Array3D(const Fortran_Array3D &A); + inline Fortran_Array3D & operator=(const T &a); + inline Fortran_Array3D & operator=(const Fortran_Array3D &A); + inline Fortran_Array3D & ref(const Fortran_Array3D &A); + Fortran_Array3D copy() const; + Fortran_Array3D & inject(const Fortran_Array3D & A); + inline T& operator()(int i, int j, int k); + inline const T& operator()(int i, int j, int k) const ; + inline int dim1() const; + inline int dim2() const; + inline int dim3() const; + inline int ref_count() const; + ~Fortran_Array3D(); + + +}; + +template <class T> +Fortran_Array3D<T>::Fortran_Array3D() : v_(), m_(0), n_(0), k_(0), data_(0) {} + + +template <class T> +Fortran_Array3D<T>::Fortran_Array3D(const Fortran_Array3D<T> &A) : + v_(A.v_), m_(A.m_), n_(A.n_), k_(A.k_), data_(A.data_) {} + + + +template <class T> +Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k) : + v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin()) {} + + + +template <class T> +Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, const T &val) : + v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin()) +{ + for (T* p = data_; p < data_ + m*n*k; p++) + *p = val; +} + +template <class T> +Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, T *a) : + v_(a), m_(m), n_(n), k_(k), data_(v_.begin()) {} + + + + +template <class T> +inline T& Fortran_Array3D<T>::operator()(int i, int j, int k) +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 1); + assert(i <= m_); + assert(j >= 1); + assert(j <= n_); + assert(k >= 1); + assert(k <= k_); +#endif + + return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1]; + +} + +template <class T> +inline const T& Fortran_Array3D<T>::operator()(int i, int j, int k) const +{ +#ifdef TNT_BOUNDS_CHECK + assert(i >= 1); + assert(i <= m_); + assert(j >= 1); + assert(j <= n_); + assert(k >= 1); + assert(k <= k_); +#endif + + return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1]; +} + + +template <class T> +Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const T &a) +{ + + T *end = data_ + m_*n_*k_; + + for (T *p=data_; p != end; *p++ = a); + + return *this; +} + +template <class T> +Fortran_Array3D<T> Fortran_Array3D<T>::copy() const +{ + + Fortran_Array3D B(m_, n_, k_); + B.inject(*this); + return B; + +} + + +template <class T> +Fortran_Array3D<T> & Fortran_Array3D<T>::inject(const Fortran_Array3D &A) +{ + + if (m_ == A.m_ && n_ == A.n_ && k_ == A.k_) + { + T *p = data_; + T *end = data_ + m_*n_*k_; + const T* q = A.data_; + for (; p < end; *p++ = *q++); + } + return *this; +} + + + + +template <class T> +Fortran_Array3D<T> & Fortran_Array3D<T>::ref(const Fortran_Array3D<T> &A) +{ + + if (this != &A) + { + v_ = A.v_; + m_ = A.m_; + n_ = A.n_; + k_ = A.k_; + data_ = A.data_; + } + return *this; +} + +template <class T> +Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const Fortran_Array3D<T> &A) +{ + return ref(A); +} + +template <class T> +inline int Fortran_Array3D<T>::dim1() const { return m_; } + +template <class T> +inline int Fortran_Array3D<T>::dim2() const { return n_; } + +template <class T> +inline int Fortran_Array3D<T>::dim3() const { return k_; } + + +template <class T> +inline int Fortran_Array3D<T>::ref_count() const +{ + return v_.ref_count(); +} + +template <class T> +Fortran_Array3D<T>::~Fortran_Array3D() +{ +} + + +} /* namespace TNT */ + +#endif +/* TNT_FORTRAN_ARRAY3D_H */ + diff --git a/lib/include/tnt/tnt_fortran_array3d_utils.h b/lib/include/tnt/tnt_fortran_array3d_utils.h new file mode 100644 index 0000000..a13a275 --- /dev/null +++ b/lib/include/tnt/tnt_fortran_array3d_utils.h @@ -0,0 +1,249 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +#ifndef TNT_FORTRAN_ARRAY3D_UTILS_H +#define TNT_FORTRAN_ARRAY3D_UTILS_H + +#include <cstdlib> +#include <cassert> + +namespace TNT +{ + + +template <class T> +std::ostream& operator<<(std::ostream &s, const Fortran_Array3D<T> &A) +{ + int M=A.dim1(); + int N=A.dim2(); + int K=A.dim3(); + + s << M << " " << N << " " << K << "\n"; + + for (int i=1; i<=M; i++) + { + for (int j=1; j<=N; j++) + { + for (int k=1; k<=K; k++) + s << A(i,j,k) << " "; + s << "\n"; + } + s << "\n"; + } + + + return s; +} + +template <class T> +std::istream& operator>>(std::istream &s, Fortran_Array3D<T> &A) +{ + + int M, N, K; + + s >> M >> N >> K; + + Fortran_Array3D<T> B(M,N,K); + + for (int i=1; i<=M; i++) + for (int j=1; j<=N; j++) + for (int k=1; k<=K; k++) + s >> B(i,j,k); + + A = B; + return s; +} + + +template <class T> +Fortran_Array3D<T> operator+(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Fortran_Array3D<T>(); + + else + { + Fortran_Array3D<T> C(m,n,p); + + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + C(i,j,k) = A(i,j,k)+ B(i,j,k); + + return C; + } +} + + +template <class T> +Fortran_Array3D<T> operator-(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Fortran_Array3D<T>(); + + else + { + Fortran_Array3D<T> C(m,n,p); + + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + C(i,j,k) = A(i,j,k)- B(i,j,k); + + return C; + } +} + + +template <class T> +Fortran_Array3D<T> operator*(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Fortran_Array3D<T>(); + + else + { + Fortran_Array3D<T> C(m,n,p); + + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + C(i,j,k) = A(i,j,k)* B(i,j,k); + + return C; + } +} + + +template <class T> +Fortran_Array3D<T> operator/(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() != m || B.dim2() != n || B.dim3() != p ) + return Fortran_Array3D<T>(); + + else + { + Fortran_Array3D<T> C(m,n,p); + + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + C(i,j,k) = A(i,j,k)/ B(i,j,k); + + return C; + } +} + + +template <class T> +Fortran_Array3D<T>& operator+=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + A(i,j,k) += B(i,j,k); + } + + return A; +} + + +template <class T> +Fortran_Array3D<T>& operator-=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + A(i,j,k) -= B(i,j,k); + } + + return A; +} + + +template <class T> +Fortran_Array3D<T>& operator*=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + A(i,j,k) *= B(i,j,k); + } + + return A; +} + + +template <class T> +Fortran_Array3D<T>& operator/=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B) +{ + int m = A.dim1(); + int n = A.dim2(); + int p = A.dim3(); + + if (B.dim1() == m && B.dim2() == n && B.dim3() == p ) + { + for (int i=1; i<=m; i++) + for (int j=1; j<=n; j++) + for (int k=1; k<=p; k++) + A(i,j,k) /= B(i,j,k); + } + + return A; +} + + +} // namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_i_refvec.h b/lib/include/tnt/tnt_i_refvec.h new file mode 100644 index 0000000..5a67eb5 --- /dev/null +++ b/lib/include/tnt/tnt_i_refvec.h @@ -0,0 +1,243 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_I_REFVEC_H +#define TNT_I_REFVEC_H + +#include <cstdlib> +#include <iostream> + +#ifdef TNT_BOUNDS_CHECK +#include <assert.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +namespace TNT +{ +/* + Internal representation of ref-counted array. The TNT + arrays all use this building block. + + <p> + If an array block is created by TNT, then every time + an assignment is made, the left-hand-side reference + is decreased by one, and the right-hand-side refernce + count is increased by one. If the array block was + external to TNT, the refernce count is a NULL pointer + regardless of how many references are made, since the + memory is not freed by TNT. + + + +*/ +template <class T> +class i_refvec +{ + + + private: + T* data_; + int *ref_count_; + + + public: + + i_refvec(); + explicit i_refvec(int n); + inline i_refvec(T* data); + inline i_refvec(const i_refvec &v); + inline T* begin(); + inline const T* begin() const; + inline T& operator[](int i); + inline const T& operator[](int i) const; + inline i_refvec<T> & operator=(const i_refvec<T> &V); + void copy_(T* p, const T* q, const T* e); + void set_(T* p, const T* b, const T* e); + inline int ref_count() const; + inline int is_null() const; + inline void destroy(); + ~i_refvec(); + +}; + +template <class T> +void i_refvec<T>::copy_(T* p, const T* q, const T* e) +{ + for (T* t=p; q<e; t++, q++) + *t= *q; +} + +template <class T> +i_refvec<T>::i_refvec() : data_(NULL), ref_count_(NULL) {} + +/** + In case n is 0 or negative, it does NOT call new. +*/ +template <class T> +i_refvec<T>::i_refvec(int n) : data_(NULL), ref_count_(NULL) +{ + if (n >= 1) + { +#ifdef TNT_DEBUG + std::cout << "new data storage.\n"; +#endif + data_ = new T[n]; + ref_count_ = new int; + *ref_count_ = 1; + } +} + +template <class T> +inline i_refvec<T>::i_refvec(const i_refvec<T> &V): data_(V.data_), + ref_count_(V.ref_count_) +{ + if (V.ref_count_ != NULL) + (*(V.ref_count_))++; +} + + +template <class T> +i_refvec<T>::i_refvec(T* data) : data_(data), ref_count_(NULL) {} + +template <class T> +inline T* i_refvec<T>::begin() +{ + return data_; +} + +template <class T> +inline const T& i_refvec<T>::operator[](int i) const +{ + return data_[i]; +} + +template <class T> +inline T& i_refvec<T>::operator[](int i) +{ + return data_[i]; +} + + +template <class T> +inline const T* i_refvec<T>::begin() const +{ + return data_; +} + + + +template <class T> +i_refvec<T> & i_refvec<T>::operator=(const i_refvec<T> &V) +{ + if (this == &V) + return *this; + + + if (ref_count_ != NULL) + { + (*ref_count_) --; + if ((*ref_count_) == 0) + destroy(); + } + + data_ = V.data_; + ref_count_ = V.ref_count_; + + if (V.ref_count_ != NULL) + (*(V.ref_count_))++; + + return *this; +} + +template <class T> +void i_refvec<T>::destroy() +{ + if (ref_count_ != NULL) + { +#ifdef TNT_DEBUG + std::cout << "destorying data... \n"; +#endif + delete ref_count_; + +#ifdef TNT_DEBUG + std::cout << "deleted ref_count_ ...\n"; +#endif + if (data_ != NULL) + delete []data_; +#ifdef TNT_DEBUG + std::cout << "deleted data_[] ...\n"; +#endif + data_ = NULL; + } +} + +/* +* return 1 is vector is empty, 0 otherwise +* +* if is_null() is false and ref_count() is 0, then +* +*/ +template<class T> +int i_refvec<T>::is_null() const +{ + return (data_ == NULL ? 1 : 0); +} + +/* +* returns -1 if data is external, +* returns 0 if a is NULL array, +* otherwise returns the positive number of vectors sharing +* this data space. +*/ +template <class T> +int i_refvec<T>::ref_count() const +{ + if (data_ == NULL) + return 0; + else + return (ref_count_ != NULL ? *ref_count_ : -1) ; +} + +template <class T> +i_refvec<T>::~i_refvec() +{ + if (ref_count_ != NULL) + { + (*ref_count_)--; + + if (*ref_count_ == 0) + destroy(); + } +} + + +} /* namespace TNT */ + + + + + +#endif +/* TNT_I_REFVEC_H */ + diff --git a/lib/include/tnt/tnt_math_utils.h b/lib/include/tnt/tnt_math_utils.h new file mode 100644 index 0000000..f9c1c91 --- /dev/null +++ b/lib/include/tnt/tnt_math_utils.h @@ -0,0 +1,34 @@ +#ifndef MATH_UTILS_H +#define MATH_UTILS_H + +/* needed for fabs, sqrt() below */ +#include <cmath> + + + +namespace TNT +{ +/** + @returns hypotenuse of real (non-complex) scalars a and b by + avoiding underflow/overflow + using (a * sqrt( 1 + (b/a) * (b/a))), rather than + sqrt(a*a + b*b). +*/ +template <class Real> +Real hypot(const Real &a, const Real &b) +{ + + if (a== 0) + return abs(b); + else + { + Real c = b/a; + return fabs(a) * sqrt(1 + c*c); + } +} +} /* TNT namespace */ + + + +#endif +/* MATH_UTILS_H */ diff --git a/lib/include/tnt/tnt_sparse_matrix_csr.h b/lib/include/tnt/tnt_sparse_matrix_csr.h new file mode 100644 index 0000000..0d4fde1 --- /dev/null +++ b/lib/include/tnt/tnt_sparse_matrix_csr.h @@ -0,0 +1,103 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +#ifndef TNT_SPARSE_MATRIX_CSR_H +#define TNT_SPARSE_MATRIX_CSR_H + +#include "tnt_array1d.h" + +namespace TNT +{ + + +/** + Read-only view of a sparse matrix in compressed-row storage + format. Neither array elements (nonzeros) nor sparsity + structure can be modified. If modifications are required, + create a new view. + + <p> + Index values begin at 0. + + <p> + <b>Storage requirements:</b> An (m x n) matrix with + nz nonzeros requires no more than ((T+I)*nz + M*I) + bytes, where T is the size of data elements and + I is the size of integers. + + +*/ +template <class T> +class Sparse_Matrix_CompRow { + +private: + Array1D<T> val_; // data values (nz_ elements) + Array1D<int> rowptr_; // row_ptr (dim_[0]+1 elements) + Array1D<int> colind_; // col_ind (nz_ elements) + + int dim1_; // number of rows + int dim2_; // number of cols + +public: + + Sparse_Matrix_CompRow(const Sparse_Matrix_CompRow &S); + Sparse_Matrix_CompRow(int M, int N, int nz, const T *val, + const int *r, const int *c); + + + + inline const T& val(int i) const { return val_[i]; } + inline const int& row_ptr(int i) const { return rowptr_[i]; } + inline const int& col_ind(int i) const { return colind_[i];} + + inline int dim1() const {return dim1_;} + inline int dim2() const {return dim2_;} + int NumNonzeros() const {return val_.dim1();} + + + Sparse_Matrix_CompRow& operator=( + const Sparse_Matrix_CompRow &R); + + + +}; + +/** + Construct a read-only view of existing sparse matrix in + compressed-row storage format. + + @param M the number of rows of sparse matrix + @param N the number of columns of sparse matrix + @param nz the number of nonzeros + @param val a contiguous list of nonzero values + @param r row-pointers: r[i] denotes the begining position of row i + (i.e. the ith row begins at val[row[i]]). + @param c column-indices: c[i] denotes the column location of val[i] +*/ +template <class T> +Sparse_Matrix_CompRow<T>::Sparse_Matrix_CompRow(int M, int N, int nz, + const T *val, const int *r, const int *c) : val_(nz,val), + rowptr_(M, r), colind_(nz, c), dim1_(M), dim2_(N) {} + + +} +// namespace TNT + +#endif diff --git a/lib/include/tnt/tnt_stopwatch.h b/lib/include/tnt/tnt_stopwatch.h new file mode 100644 index 0000000..8dc5d23 --- /dev/null +++ b/lib/include/tnt/tnt_stopwatch.h @@ -0,0 +1,95 @@ +/* +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef STOPWATCH_H +#define STOPWATCH_H + +// for clock() and CLOCKS_PER_SEC +#include <time.h> + + +namespace TNT +{ + +inline static double seconds(void) +{ + const double secs_per_tick = 1.0 / CLOCKS_PER_SEC; + return ( (double) clock() ) * secs_per_tick; +} + +class Stopwatch { + private: + int running_; + double start_time_; + double total_; + + public: + inline Stopwatch(); + inline void start(); + inline double stop(); + inline double read(); + inline void resume(); + inline int running(); +}; + +inline Stopwatch::Stopwatch() : running_(0), start_time_(0.0), total_(0.0) {} + +void Stopwatch::start() +{ + running_ = 1; + total_ = 0.0; + start_time_ = seconds(); +} + +double Stopwatch::stop() +{ + if (running_) + { + total_ += (seconds() - start_time_); + running_ = 0; + } + return total_; +} + +inline void Stopwatch::resume() +{ + if (!running_) + { + start_time_ = seconds(); + running_ = 1; + } +} + + +inline double Stopwatch::read() +{ + if (running_) + { + stop(); + resume(); + } + return total_; +} + + +} /* TNT namespace */ +#endif + + + diff --git a/lib/include/tnt/tnt_subscript.h b/lib/include/tnt/tnt_subscript.h new file mode 100644 index 0000000..d8fe120 --- /dev/null +++ b/lib/include/tnt/tnt_subscript.h @@ -0,0 +1,54 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + +#ifndef TNT_SUBSCRPT_H +#define TNT_SUBSCRPT_H + + +//--------------------------------------------------------------------- +// This definition describes the default TNT data type used for +// indexing into TNT matrices and vectors. The data type should +// be wide enough to index into large arrays. It defaults to an +// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE, +// e.g. +// +// c++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ... +// +//--------------------------------------------------------------------- +// + +#ifndef TNT_SUBSCRIPT_TYPE +#define TNT_SUBSCRIPT_TYPE int +#endif + +namespace TNT +{ + typedef TNT_SUBSCRIPT_TYPE Subscript; +} /* namespace TNT */ + + +// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the +// first elements. This offset is left as a macro for future +// purposes, but should not be changed in the current release. +// +// +#define TNT_BASE_OFFSET (1) + +#endif diff --git a/lib/include/tnt/tnt_vec.h b/lib/include/tnt/tnt_vec.h new file mode 100644 index 0000000..3455d79 --- /dev/null +++ b/lib/include/tnt/tnt_vec.h @@ -0,0 +1,404 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + + + +#ifndef TNT_VEC_H +#define TNT_VEC_H + +#include "tnt_subscript.h" +#include <cstdlib> +#include <cassert> +#include <iostream> +#include <sstream> + +namespace TNT +{ + +/** + <b>[Deprecatred]</b> Value-based vector class from pre-1.0 + TNT version. Kept here for backward compatiblity, but should + use the newer TNT::Array1D classes instead. + +*/ + +template <class T> +class Vector +{ + + + public: + + typedef Subscript size_type; + typedef T value_type; + typedef T element_type; + typedef T* pointer; + typedef T* iterator; + typedef T& reference; + typedef const T* const_iterator; + typedef const T& const_reference; + + Subscript lbound() const { return 1;} + + protected: + T* v_; + T* vm1_; // pointer adjustment for optimzied 1-offset indexing + Subscript n_; + + // internal helper function to create the array + // of row pointers + + void initialize(Subscript N) + { + // adjust pointers so that they are 1-offset: + // v_[] is the internal contiguous array, it is still 0-offset + // + assert(v_ == NULL); + v_ = new T[N]; + assert(v_ != NULL); + vm1_ = v_-1; + n_ = N; + } + + void copy(const T* v) + { + Subscript N = n_; + Subscript i; + +#ifdef TNT_UNROLL_LOOPS + Subscript Nmod4 = N & 3; + Subscript N4 = N - Nmod4; + + for (i=0; i<N4; i+=4) + { + v_[i] = v[i]; + v_[i+1] = v[i+1]; + v_[i+2] = v[i+2]; + v_[i+3] = v[i+3]; + } + + for (i=N4; i< N; i++) + v_[i] = v[i]; +#else + + for (i=0; i< N; i++) + v_[i] = v[i]; +#endif + } + + void set(const T& val) + { + Subscript N = n_; + Subscript i; + +#ifdef TNT_UNROLL_LOOPS + Subscript Nmod4 = N & 3; + Subscript N4 = N - Nmod4; + + for (i=0; i<N4; i+=4) + { + v_[i] = val; + v_[i+1] = val; + v_[i+2] = val; + v_[i+3] = val; + } + + for (i=N4; i< N; i++) + v_[i] = val; +#else + + for (i=0; i< N; i++) + v_[i] = val; + +#endif + } + + + + void destroy() + { + /* do nothing, if no memory has been previously allocated */ + if (v_ == NULL) return ; + + /* if we are here, then matrix was previously allocated */ + delete [] (v_); + + v_ = NULL; + vm1_ = NULL; + } + + + public: + + // access + + iterator begin() { return v_;} + iterator end() { return v_ + n_; } + const iterator begin() const { return v_;} + const iterator end() const { return v_ + n_; } + + // destructor + + ~Vector() + { + destroy(); + } + + // constructors + + Vector() : v_(0), vm1_(0), n_(0) {}; + + Vector(const Vector<T> &A) : v_(0), vm1_(0), n_(0) + { + initialize(A.n_); + copy(A.v_); + } + + Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0) + { + initialize(N); + set(value); + } + + Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0) + { + initialize(N); + copy(v); + } + + Vector(Subscript N, char *s) : v_(0), vm1_(0), n_(0) + { + initialize(N); + std::istringstream ins(s); + + Subscript i; + + for (i=0; i<N; i++) + ins >> v_[i]; + } + + + // methods + // + Vector<T>& newsize(Subscript N) + { + if (n_ == N) return *this; + + destroy(); + initialize(N); + + return *this; + } + + + // assignments + // + Vector<T>& operator=(const Vector<T> &A) + { + if (v_ == A.v_) + return *this; + + if (n_ == A.n_) // no need to re-alloc + copy(A.v_); + + else + { + destroy(); + initialize(A.n_); + copy(A.v_); + } + + return *this; + } + + Vector<T>& operator=(const T& scalar) + { + set(scalar); + return *this; + } + + inline Subscript dim() const + { + return n_; + } + + inline Subscript size() const + { + return n_; + } + + + inline reference operator()(Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= n_) ; +#endif + return vm1_[i]; + } + + inline const_reference operator() (Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(1<=i); + assert(i <= n_) ; +#endif + return vm1_[i]; + } + + inline reference operator[](Subscript i) + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + assert(i < n_) ; +#endif + return v_[i]; + } + + inline const_reference operator[](Subscript i) const + { +#ifdef TNT_BOUNDS_CHECK + assert(0<=i); + + + + + + + assert(i < n_) ; +#endif + return v_[i]; + } + + + +}; + + +/* *************************** I/O ********************************/ + +template <class T> +std::ostream& operator<<(std::ostream &s, const Vector<T> &A) +{ + Subscript N=A.dim(); + + s << N << "\n"; + + for (Subscript i=0; i<N; i++) + s << A[i] << " " << "\n"; + s << "\n"; + + return s; +} + +template <class T> +std::istream & operator>>(std::istream &s, Vector<T> &A) +{ + + Subscript N; + + s >> N; + + if ( !(N == A.size() )) + { + A.newsize(N); + } + + + for (Subscript i=0; i<N; i++) + s >> A[i]; + + + return s; +} + +// *******************[ basic matrix algorithms ]*************************** + + +template <class T> +Vector<T> operator+(const Vector<T> &A, + const Vector<T> &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector<T> tmp(N); + Subscript i; + + for (i=0; i<N; i++) + tmp[i] = A[i] + B[i]; + + return tmp; +} + +template <class T> +Vector<T> operator-(const Vector<T> &A, + const Vector<T> &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector<T> tmp(N); + Subscript i; + + for (i=0; i<N; i++) + tmp[i] = A[i] - B[i]; + + return tmp; +} + +template <class T> +Vector<T> operator*(const Vector<T> &A, + const Vector<T> &B) +{ + Subscript N = A.dim(); + + assert(N==B.dim()); + + Vector<T> tmp(N); + Subscript i; + + for (i=0; i<N; i++) + tmp[i] = A[i] * B[i]; + + return tmp; +} + + +template <class T> +T dot_prod(const Vector<T> &A, const Vector<T> &B) +{ + Subscript N = A.dim(); + assert(N == B.dim()); + + Subscript i; + T sum = 0; + + for (i=0; i<N; i++) + sum += A[i] * B[i]; + + return sum; +} + +} /* namespace TNT */ + +#endif +// TNT_VEC_H diff --git a/lib/include/tnt/tnt_version.h b/lib/include/tnt/tnt_version.h new file mode 100644 index 0000000..047e7d3 --- /dev/null +++ b/lib/include/tnt/tnt_version.h @@ -0,0 +1,39 @@ +/* +* +* Template Numerical Toolkit (TNT) +* +* Mathematical and Computational Sciences Division +* National Institute of Technology, +* Gaithersburg, MD USA +* +* +* This software was developed at the National Institute of Standards and +* Technology (NIST) by employees of the Federal Government in the course +* of their official duties. Pursuant to title 17 Section 105 of the +* United States Code, this software is not subject to copyright protection +* and is in the public domain. NIST assumes no responsibility whatsoever for +* its use by other parties, and makes no guarantees, expressed or implied, +* about its quality, reliability, or any other characteristic. +* +*/ + +#ifndef TNT_VERSION_H +#define TNT_VERSION_H + + +//--------------------------------------------------------------------- +// current version +//--------------------------------------------------------------------- + + +#define TNT_MAJOR_VERSION '1' +#define TNT_MINOR_VERSION '2' +#define TNT_SUBMINOR_VERSION '6' +#define TNT_VERSION_STRING "1.2.6" + + + + + +#endif +// TNT_VERSION_H diff --git a/lib/licenses/rapidxml.txt b/lib/licenses/rapidxml.txt new file mode 100644 index 0000000..1409831 --- /dev/null +++ b/lib/licenses/rapidxml.txt @@ -0,0 +1,52 @@ +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/lib/licenses/tnt.txt b/lib/licenses/tnt.txt new file mode 100644 index 0000000..3dafbe0 --- /dev/null +++ b/lib/licenses/tnt.txt @@ -0,0 +1,14 @@ +Template Numerical Toolkit (TNT): Linear Algebra Module + +Mathematical and Computational Sciences Division +National Institute of Technology, +Gaithersburg, MD USA + + +This software was developed at the National Institute of Standards and +Technology (NIST) by employees of the Federal Government in the course +of their official duties. Pursuant to title 17 Section 105 of the +United States Code, this software is not subject to copyright protection +and is in the public domain. NIST assumes no responsibility whatsoever for +its use by other parties, and makes no guarantees, expressed or implied, +about its quality, reliability, or any other characteristic. diff --git a/matlab/algorithms/DART/DARTalgorithm.m b/matlab/algorithms/DART/DARTalgorithm.m new file mode 100644 index 0000000..b7e63b5 --- /dev/null +++ b/matlab/algorithms/DART/DARTalgorithm.m @@ -0,0 +1,229 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef DARTalgorithm < matlab.mixin.Copyable + + % Algorithm class for Discrete Algebraic Reconstruction Technique (DART). + + % todo: reset() + % todo: fixed random seed + % todo: initialize from settings (?) + + %---------------------------------------------------------------------- + properties (GetAccess=public, SetAccess=public) + + tomography = TomographyDefault(); % POLICY: Tomography object. + segmentation = SegmentationDefault(); % POLICY: Segmentation object. + smoothing = SmoothingDefault(); % POLICY: Smoothing object. + masking = MaskingDefault(); % POLICY: Masking object. + output = OutputDefault(); % POLICY: Output object. + statistics = StatisticsDefault(); % POLICY: Statistics object. + + base = struct(); % DATA(set): base structure, should contain: 'sinogram', 'proj_geom', 'phantom' (optional). + + memory = 'yes'; % SETTING: reduce memory usage? (disables some features) + + testdata = struct(); + + end + %---------------------------------------------------------------------- + properties (GetAccess=public, SetAccess=private) + V0 = []; % DATA(get): Initial reconstruction. + V = []; % DATA(get): Reconstruction. + S = []; % DATA(get): Segmentation. + R = []; % DATA(get): Residual projection data. + Mask = []; % DATA(get): Reconstruction Mask. + stats = struct(); % Structure containing various statistics. + iterationcount = 0; % Number of performed iterations. + start_tic = 0; + initialized = 0; % Is initialized? + end + %---------------------------------------------------------------------- + properties (Access=private) + adaptparam_name = {}; + adaptparam_values = {}; + adaptparam_iters = {}; + end + + %---------------------------------------------------------------------- + methods + + %------------------------------------------------------------------ + function this = DARTalgorithm(base) + % Constructor + % >> D = DARTalgorithm(base); base is a matlab struct (or the path towards one) + % that should contain 'sinogram', 'proj_geom'. + + if ischar(base) + this.base = load(base); + else + this.base = base; + end + end + + + %------------------------------------------------------------------ + function D = deepcopy(this) + % Create a deep copy of this object. + % >> D2 = D.deepcopy(); + + D = copy(this); + props = properties(this); + for i = 1:length(props) + if isa(this.(props{i}), 'handle') + D.(props{i}) = copy(this.(props{i})); + end + end + + end + + %------------------------------------------------------------------ + function this = initialize(this) + % Initializes this object. + % >> D.initialize(); + + % Initialize tomography part + this.tomography.initialize(this); + + % Create an Initial Reconstruction + if isfield(this.base, 'V0') + this.V0 = this.base.V0; + else + this.output.pre_initial_iteration(this); + this.V0 = this.tomography.createInitialReconstruction(this, this.base.sinogram); + this.output.post_initial_iteration(this); + end + this.V = this.V0; + if strcmp(this.memory,'yes') + this.base.V0 = []; + this.V0 = []; + end + this.initialized = 1; + end + + %------------------------------------------------------------------ + % iterate + function this = iterate(this, iters) + % Perform several iterations of the DART algorithm. + % >> D.iterate(iterations); + + this.start_tic = tic; + + for iteration = 1:iters + + this.iterationcount = this.iterationcount + 1; + + %---------------------------------------------------------- + % Initial Output + this.output.pre_iteration(this); + + %---------------------------------------------------------- + % Update Adaptive Parameters + for i = 1:numel(this.adaptparam_name) + + for j = 1:numel(this.adaptparam_iters{i}) + if this.iterationcount == this.adaptparam_iters{i}(j) + new_value = this.adaptparam_values{i}(j); + eval(['this.' this.adaptparam_name{i} ' = ' num2str(new_value) ';']); + disp(['value ' this.adaptparam_name{i} ' changed to ' num2str(new_value) ]); + end + end + + end + + %---------------------------------------------------------- + % Segmentation + this.segmentation.estimate_grey_levels(this, this.V); + this.S = this.segmentation.apply(this, this.V); + + %---------------------------------------------------------- + % Select Update and Fixed Pixels + this.Mask = this.masking.apply(this, this.S); + + this.V = (this.V .* this.Mask) + (this.S .* (1 - this.Mask)); + %this.V(this.Mask == 0) = this.S(this.Mask == 0); + + F = this.V; + F(this.Mask == 1) = 0; + + %---------------------------------------------------------- + % Create Residual Projection Difference + %this.testdata.F{iteration} = F; + this.R = this.base.sinogram - this.tomography.createForwardProjection(this, F); + %this.testdata.R{iteration} = this.R; + + %---------------------------------------------------------- + % ART Loose Part + %this.testdata.V1{iteration} = this.V; + %this.testdata.Mask{iteration} = this.Mask; + + %X = zeros(size(this.V)); + %Y = this.tomography.createReconstruction(this, this.R, X, this.Mask); + %this.V(this.Mask) = Y(this.Mask); + this.V = this.tomography.createReconstruction(this, this.R, this.V, this.Mask); + + %this.testdata.V2{iteration} = this.V; + + %---------------------------------------------------------- + % Blur + this.V = this.smoothing.apply(this, this.V); + %this.testdata.V3{iteration} = this.V; + + %---------------------------------------------------------- + % Calculate Statistics + this.stats = this.statistics.apply(this); + + %---------------------------------------------------------- + % Output + this.output.post_iteration(this); + + end % end iteration loop + + %test = this.testdata; + %save('testdata.mat','test'); + + end + + %------------------------------------------------------------------ + % get data + function data = getdata(this, string) + if numel(this.(string)) == 1 + data = astra_mex_data2d('get',this.(string)); + else + data = this.(string); + end + end + + %------------------------------------------------------------------ + % add adaptive parameter + function this = adaptiveparameter(this, name, values, iterations) + this.adaptparam_name{end+1} = name; + this.adaptparam_values{end+1} = values; + this.adaptparam_iters{end+1} = iterations; + end + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = tomography.getsettings(); + + settings.tomography = this.tomography.getsettings(); + settings.smoothing = this.smoothing.getsettings(); + settings.masking = this.masking.getsettings(); + settings.segmentation = this.segmentation.getsettings(); + end + %------------------------------------------------------------------ + + end % methods + +end % class + + diff --git a/matlab/algorithms/DART/IterativeTomography.m b/matlab/algorithms/DART/IterativeTomography.m new file mode 100644 index 0000000..b30640e --- /dev/null +++ b/matlab/algorithms/DART/IterativeTomography.m @@ -0,0 +1,455 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef IterativeTomography < matlab.mixin.Copyable + + % Algorithm class for 2D Iterative Tomography. + + %---------------------------------------------------------------------- + properties (SetAccess=public, GetAccess=public) + superresolution = 1; % SETTING: Volume upsampling factor. + proj_type = 'linear'; % SETTING: Projector type, only when gpu='no'. + method = 'SIRT_CUDA'; % SETTING: Iterative method (see ASTRA toolbox documentation). + gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'} + gpu_core = 0; % SETTING: Which gpu core to use? Only when gpu='yes'. + inner_circle = 'yes'; % SETTING: Do roi only? {'yes', 'no'} + image_size = []; % SETTING: Overwrite default reconstruction size. Only if no vol_geom is specified. + use_minc = 'no'; % SETTING: Use minimum constraint. {'no', 'yes'} + end + %---------------------------------------------------------------------- + properties (SetAccess=public, GetAccess=public) + sinogram = []; % DATA: Projection data. + proj_geom = []; % DATA: Projection geometry. + V = []; % DATA: Volume data. Also used to set initial estimate (optional). + vol_geom = []; % DATA: Volume geometry. + end + %---------------------------------------------------------------------- + properties (SetAccess=private, GetAccess=public) + initialized = 0; % Is this object initialized? + end + %---------------------------------------------------------------------- + properties (SetAccess=protected, GetAccess=protected) + proj_geom_sr = []; % PROTECTED: geometry of sinogram (with super-resolution) + proj_id = []; % PROTECTED: astra id of projector (when gpu='no') + proj_id_sr = []; % PROTECTED: astra id of super-resolution projector (when gpu='no') + cfg_base = struct(); % PROTECTED: base configuration structure for the reconstruction algorithm. + end + %---------------------------------------------------------------------- + + methods (Access=public) + + %------------------------------------------------------------------ + function this = IterativeTomography(varargin) + % Constructor + % >> tomography = IterativeTomography(); + % >> tomography = IterativeTomography(base); base struct should contain fields 'sinogram' and 'proj_geom'. + % >> tomography = IterativeTomography(base_filename); mat-file should contain 'sinogram' and 'proj_geom'. + % >> tomography = IterativeTomography(proj_geom, vol_geom); + % >> tomography = IterativeTomography(sinogram, proj_geom); + + % Input: IterativeTomography(base) + if nargin == 1 + if ischar(varargin{1}) + this.sinogram = load(varargin{1},'sinogram'); + this.proj_geom = load(varargin{1},'proj_geom'); + else + this.sinogram = varargin{1}.sinogram; + this.proj_geom = varargin{1}.proj_geom; + end + end + % Input: IterativeTomography(proj_geom, vol_geom) + if nargin == 2 && isstruct(varargin{1}) && isstruct(varargin{2}) + this.proj_geom = varargin{1}; + this.vol_geom = varargin{2}; + % Input: IterativeTomography(sinogram, proj_geom) + elseif nargin == 2 + this.sinogram = varargin{1}; + this.proj_geom = varargin{2}; + end + + end + + %------------------------------------------------------------------ + function delete(this) + % Destructor + % >> clear tomography; + if strcmp(this.gpu,'no') && numel(this.proj_id) > 0 + astra_mex_projector('delete', this.proj_id, this.proj_id_sr); + end + end + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = tomography.getsettings(); + settings.superresolution = this.superresolution; + settings.proj_type = this.proj_type; + settings.method = this.method; + settings.gpu = this.gpu; + settings.gpu_core = this.gpu_core; + settings.inner_circle = this.inner_circle; + settings.image_size = this.image_size; + settings.use_minc = this.use_minc; + end + + %------------------------------------------------------------------ + function ok = initialize(this) + % Initialize this object. Returns 1 if succesful. + % >> tomography.initialize(); + + % create projection geometry with super-resolution + this.proj_geom_sr = astra_geom_superresolution(this.proj_geom, this.superresolution); + + % if no volume geometry is specified by the user: create volume geometry + if numel(this.vol_geom) == 0 + if numel(this.image_size) < 2 + this.image_size(1) = this.proj_geom.DetectorCount; + this.image_size(2) = this.proj_geom.DetectorCount; + end + this.vol_geom = astra_create_vol_geom(this.image_size(1) * this.superresolution, this.image_size(2) * this.superresolution, ... + -this.image_size(1)/2, this.image_size(1)/2, -this.image_size(2)/2, this.image_size(2)/2); + else + this.image_size(1) = this.vol_geom.GridRowCount; + this.image_size(2) = this.vol_geom.GridColCount; + end + + % create projector + if strcmp(this.gpu, 'no') + this.proj_id = astra_create_projector(this.proj_type, this.proj_geom, this.vol_geom); + this.proj_id_sr = astra_create_projector(this.proj_type, this.proj_geom_sr, this.vol_geom); + end + + % create reconstruction configuration + this.cfg_base = astra_struct(upper(this.method)); + if strcmp(this.gpu,'no') + this.cfg_base.ProjectorId = this.proj_id; + this.cfg_base.ProjectionGeometry = this.proj_geom; + this.cfg_base.ReconstructionGeometry = this.vol_geom; + this.cfg_base.option.ProjectionOrder = 'random'; + end + this.cfg_base.option.DetectorSuperSampling = this.superresolution; + %this.cfg_base.option.DetectorSuperSampling = 8; + if strcmp(this.gpu,'yes') + this.cfg_base.option.GPUindex = this.gpu_core; + end + this.cfg_base.option.UseMinConstraint = this.use_minc; + + this.initialized = 1; + ok = this.initialized; + end + + %------------------------------------------------------------------ + function P = project(this, volume) + % Compute forward projection. + % Stores sinogram in tomography.sinogram if it is still empty. + % >> P = tomography.project(); projects 'tomography.V'. + % >> P = tomography.project(volume); projects 'volume'. + + if ~this.initialized + this.initialize(); + end + + if nargin == 1 % tomography.project(); + P = this.project_c(this.V); + + elseif nargin == 2 % tomography.project(volume); + P = this.project_c(volume); + end + + % store + if numel(this.sinogram) == 0 + this.sinogram = P; + end + end + + %------------------------------------------------------------------ + function V = reconstruct(this, iterations) + % Compute reconstruction. + % Uses tomography.sinogram + % Initial solution (if available) should be stored in tomography.V + % >> V = tomography.reconstruct(iterations); + + if ~this.initialized + this.initialize(); + end + + this.V = this.reconstruct_c(this.sinogram, this.V, [], iterations); + if strcmp(this.inner_circle,'yes') + this.V = this.selectROI(this.V); + end + V = this.V; + end + + %------------------------------------------------------------------ + function I = reconstructMask(this, mask, iterations) + % Compute reconstruction with mask. + % Uses tomography.sinogram + % Initial solution (if available) should be stored in tomography.V + % >> V = tomography.reconstructMask(mask, iterations); + + if ~this.initialized + this.initialize(); + end + + if strcmp(this.inner_circle,'yes') + mask = this.selectROI(mask); + end + I = this.reconstruct_c(this.sinogram, this.V, mask, iterations); + end + %------------------------------------------------------------------ + + end + + %---------------------------------------------------------------------- + methods (Access = protected) + + %------------------------------------------------------------------ + % Protected function: create FP + function sinogram = project_c(this, volume) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + % data is stored in astra memory + if numel(volume) == 1 + + if strcmp(this.gpu, 'yes') + sinogram_tmp = astra_create_sino_cuda(volume, this.proj_geom_sr, this.vol_geom, this.gpu_core); + else + sinogram_tmp = astra_create_sino(volume, this.proj_id); + end + + % sinogram downsampling + if this.superresolution > 1 + sinogram_data = astra_mex_data2d('get', sinogram_tmp); + astra_mex_data2d('delete', sinogram_tmp); + sinogram_data = downsample_sinogram(sinogram_data, this.superresolution); + %if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + % sinogram = sinogram / this.superresolution; + %end + sinogram = astra_mex_data2d('create','sino', this.proj_geom, sinogram_data); + else + sinogram = sinogram_tmp; + end + + % data is stored in matlab memory + else + + % 2D and 3D slice by slice + sinogram_tmp = zeros([astra_geom_size(this.proj_geom_sr), size(volume,3)]); + sinogram_tmp2 = zeros([astra_geom_size(this.proj_geom), size(volume,3)]); + for slice = 1:size(volume,3) + + if strcmp(this.gpu, 'yes') + [tmp_id, sinogram_tmp2(:,:,slice)] = astra_create_sino_sampling(volume(:,:,slice), this.proj_geom, this.vol_geom, this.gpu_core, this.superresolution); + astra_mex_data2d('delete', tmp_id); + else + [tmp_id, tmp] = astra_create_sino(volume(:,:,slice), this.proj_id_sr); + sinogram_tmp2(:,:,slice) = downsample_sinogram(tmp, this.superresolution) * (this.superresolution^2); + astra_mex_data2d('delete', tmp_id); + end + + end + + % sinogram downsampling + if strcmp(this.gpu, 'yes') + %sinogram = downsample_sinogram(sinogram_tmp, this.superresolution); + sinogram2 = sinogram_tmp2; + if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + sinogram2 = sinogram2 / this.superresolution; + elseif strcmp(this.proj_geom.type,'parallel') + sinogram2 = sinogram2 / (this.superresolution * this.superresolution); + end + sinogram = sinogram2; + else + sinogram = sinogram_tmp2; + end + + end + + end + + %------------------------------------------------------------------ + % Protected function: reconstruct + function V = reconstruct_c(this, sinogram, V0, mask, iterations) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + % data is stored in astra memory + if numel(sinogram) == 1 + V = this.reconstruct_c_astra(sinogram, V0, mask, iterations); + + % data is stored in matlab memory + else + V = this.reconstruct_c_matlab(sinogram, V0, mask, iterations); + end + + end + + %------------------------------------------------------------------ + % Protected function: reconstruct (data in matlab) + function V = reconstruct_c_matlab(this, sinogram, V0, mask, iterations) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + % parse method + method2 = upper(this.method); + if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA') + iterations = iterations * size(sinogram,1); + elseif strcmp(method2, 'ART') + iterations = iterations * numel(sinogram); + end + + % create data objects + V = zeros(this.vol_geom.GridRowCount, this.vol_geom.GridColCount, size(sinogram,3)); + reconstruction_id = astra_mex_data2d('create', '-vol', this.vol_geom); + sinogram_id = astra_mex_data2d('create', '-sino', this.proj_geom); + if numel(mask) > 0 + mask_id = astra_mex_data2d('create', '-vol', this.vol_geom); + end + + % algorithm configuration + cfg = this.cfg_base; + cfg.ProjectionDataId = sinogram_id; + cfg.ReconstructionDataId = reconstruction_id; + if numel(mask) > 0 + cfg.option.ReconstructionMaskId = mask_id; + end + alg_id = astra_mex_algorithm('create', cfg); + + % loop slices + for slice = 1:size(sinogram,3) + + % fetch slice of initial reconstruction + if numel(V0) > 0 + astra_mex_data2d('store', reconstruction_id, V0(:,:,slice)); + else + astra_mex_data2d('store', reconstruction_id, 0); + end + + % fetch slice of sinogram + astra_mex_data2d('store', sinogram_id, sinogram(:,:,slice)); + + % fecth slice of mask + if numel(mask) > 0 + astra_mex_data2d('store', mask_id, mask(:,:,slice)); + end + + % iterate + astra_mex_algorithm('iterate', alg_id, iterations); + + % fetch data + V(:,:,slice) = astra_mex_data2d('get', reconstruction_id); + + end + + % correct attenuation factors for super-resolution + if this.superresolution > 1 && strcmp(this.gpu,'yes') + if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + if numel(mask) > 0 + V(mask > 0) = V(mask > 0) ./ this.superresolution; + else + V = V ./ this.superresolution; + end + end + end + + % garbage collection + astra_mex_algorithm('delete', alg_id); + astra_mex_data2d('delete', sinogram_id, reconstruction_id); + if numel(mask) > 0 + astra_mex_data2d('delete', mask_id); + end + + end + + %------------------------------------------------------------------ + % Protected function: reconstruct (data in astra) + function V = reconstruct_c_astra(this, sinogram, V0, mask, iterations) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + if numel(V0) > 1 || numel(mask) > 1 || numel(sinogram) > 1 + error('Not all required data is stored in the astra memory'); + end + + if numel(V0) == 0 + V0 = astra_mex_data2d('create', '-vol', this.vol_geom, 0); + end + + % parse method + method2 = upper(this.method); + if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA') + iterations = iterations * astra_geom_size(this.proj_geom, 1); + elseif strcmp(method2, 'ART') + s = astra_geom_size(this.proj_geom); + iterations = iterations * s(1) * s(2); + end + + % algorithm configuration + cfg = this.cfg_base; + cfg.ProjectionDataId = sinogram; + cfg.ReconstructionDataId = V0; + if numel(mask) > 0 + cfg.option.ReconstructionMaskId = mask; + end + alg_id = astra_mex_algorithm('create', cfg); + + % iterate + astra_mex_algorithm('iterate', alg_id, iterations); + + % fetch data + V = V0; + + % correct attenuation factors for super-resolution + if this.superresolution > 1 + if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + if numel(mask) > 0 + astra_data_op_masked('$1./s1', [V V], [this.superresolution this.superresolution], mask, this.gpu_core); + else + astra_data_op('$1./s1', [V V], [this.superresolution this.superresolution], this.gpu_core); + end + end + end + + % garbage collection + astra_mex_algorithm('delete', alg_id); + + end + + %------------------------------------------------------------------ + function V_out = selectROI(~, V_in) + + if numel(V_in) == 1 + cfg = astra_struct('RoiSelect_CUDA'); + cfg.DataId = V_in; + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('run', alg_id); + astra_mex_algorithm('delete', alg_id); + V_out = V_in; + else + V_out = ROIselectfull(V_in, min([size(V_in,1), size(V_in,2)])); + end + + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/IterativeTomography3D.m b/matlab/algorithms/DART/IterativeTomography3D.m new file mode 100644 index 0000000..3f89457 --- /dev/null +++ b/matlab/algorithms/DART/IterativeTomography3D.m @@ -0,0 +1,433 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef IterativeTomography3D < matlab.mixin.Copyable + + % Algorithm class for 3D Iterative Tomography. + + %---------------------------------------------------------------------- + properties (SetAccess=public, GetAccess=public) + superresolution = 1; % SETTING: Volume upsampling factor. + proj_type = 'linear'; % SETTING: Projector type, only when gpu='no'. + method = 'SIRT3D_CUDA'; % SETTING: Iterative method (see ASTRA toolbox documentation). + gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'} + gpu_core = 0; % SETTING: Which gpu core to use? Only when gpu='yes'. + inner_circle = 'yes'; % SETTING: Do roi only? {'yes', 'no'} + image_size = []; % SETTING: Overwrite default reconstruction size. Only if no vol_geom is specified. + use_minc = 'no'; % SETTING: Use minimum constraint. {'no', 'yes'} + maxc = +Inf; % SETTING: Maximum constraint. +Inf means off. + end + %---------------------------------------------------------------------- + properties (SetAccess=public, GetAccess=public) + sinogram = []; % DATA: Projection data. + proj_geom = []; % DATA: Projection geometry. + V = []; % DATA: Volume data. Also used to set initial estimate (optional). + vol_geom = []; % DATA: Volume geometry. + end + %---------------------------------------------------------------------- + properties (SetAccess=private, GetAccess=public) + initialized = 0; % Is this object initialized? + end + %---------------------------------------------------------------------- + properties (SetAccess=protected, GetAccess=protected) + proj_geom_sr = []; % PROTECTED: geometry of sinogram (with super-resolution) + proj_id = []; % PROTECTED: astra id of projector (when gpu='no') + proj_id_sr = []; % PROTECTED: astra id of super-resolution projector (when gpu='no') + cfg_base = struct(); % PROTECTED: base configuration structure for the reconstruction algorithm. + end + %---------------------------------------------------------------------- + + methods (Access=public) + + %------------------------------------------------------------------ + function this = IterativeTomography(varargin) + % Constructor + % >> tomography = IterativeTomography(); + % >> tomography = IterativeTomography(base); base struct should contain fields 'sinogram' and 'proj_geom'. + % >> tomography = IterativeTomography(base_filename); mat-file should contain 'sinogram' and 'proj_geom'. + % >> tomography = IterativeTomography(proj_geom, vol_geom); + % >> tomography = IterativeTomography(sinogram, proj_geom); + + % Input: IterativeTomography(base) + if nargin == 1 + if ischar(varargin{1}) + this.sinogram = load(varargin{1},'sinogram'); + this.proj_geom = load(varargin{1},'proj_geom'); + else + this.sinogram = varargin{1}.sinogram; + this.proj_geom = varargin{1}.proj_geom; + end + end + % Input: IterativeTomography(proj_geom, vol_geom) + if nargin == 2 && isstruct(varargin{1}) && isstruct(varargin{2}) + this.proj_geom = varargin{1}; + this.vol_geom = varargin{2}; + % Input: IterativeTomography(sinogram, proj_geom) + elseif nargin == 2 + this.sinogram = varargin{1}; + this.proj_geom = varargin{2}; + end + + end + + %------------------------------------------------------------------ + function delete(this) + % Destructor + % >> clear tomography; + if strcmp(this.gpu,'no') && numel(this.proj_id) > 0 + astra_mex_projector('delete', this.proj_id, this.proj_id_sr); + end + end + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = tomography.getsettings(); + settings.superresolution = this.superresolution; + settings.proj_type = this.proj_type; + settings.method = this.method; + settings.gpu = this.gpu; + settings.gpu_core = this.gpu_core; + settings.inner_circle = this.inner_circle; + settings.image_size = this.image_size; + settings.use_minc = this.use_minc; + settings.maxc = this.maxc; + end + + %------------------------------------------------------------------ + function ok = initialize(this) + % Initialize this object. Returns 1 if succesful. + % >> tomography.initialize(); + +% % create projection geometry with super-resolution +% this.proj_geom_sr = astra_geom_superresolution(this.proj_geom, this.superresolution); + + % if no volume geometry is specified by the user: create volume geometry + if numel(this.vol_geom) == 0 + if numel(this.image_size) < 2 + this.image_size(1) = this.proj_geom.DetectorRowCount; + this.image_size(2) = this.proj_geom.DetectorColCount; + end + this.vol_geom = astra_create_vol_geom(this.proj_geom.DetectorColCount, this.proj_geom.DetectorColCount, this.proj_geom.DetectorRowCount); + else + this.image_size(1) = this.vol_geom.GridRowCount; + this.image_size(2) = this.vol_geom.GridColCount; + end + + % create projector + if strcmp(this.gpu, 'no') + this.proj_id = astra_create_projector(this.proj_type, this.proj_geom, this.vol_geom); + this.proj_id_sr = astra_create_projector(this.proj_type, this.proj_geom_sr, this.vol_geom); + end + + % create reconstruction configuration + this.cfg_base = astra_struct(upper(this.method)); + if strcmp(this.gpu,'no') + this.cfg_base.ProjectorId = this.proj_id; + this.cfg_base.ProjectionGeometry = this.proj_geom; + this.cfg_base.ReconstructionGeometry = this.vol_geom; + this.cfg_base.option.ProjectionOrder = 'random'; + end + this.cfg_base.option.DetectorSuperSampling = this.superresolution; + %this.cfg_base.option.DetectorSuperSampling = 8; + if strcmp(this.gpu,'yes') + this.cfg_base.option.GPUindex = this.gpu_core; + end + this.cfg_base.option.UseMinConstraint = this.use_minc; + if ~isinf(this.maxc) + this.cfg_base.option.UseMaxConstraint = 'yes'; + this.cfg_base.option.MaxConstraintValue = this.maxc; + end + + this.initialized = 1; + ok = this.initialized; + end + + %------------------------------------------------------------------ + function P = project(this, volume) + % Compute forward projection. + % Stores sinogram in tomography.sinogram if it is still empty. + % >> P = tomography.project(); projects 'tomography.V'. + % >> P = tomography.project(volume); projects 'volume'. + + if ~this.initialized + this.initialize(); + end + + if nargin == 1 % tomography.project(); + P = this.project_c(this.V); + + elseif nargin == 2 % tomography.project(volume); + P = this.project_c(volume); + end + + % store + if numel(this.sinogram) == 0 + this.sinogram = P; + end + end + + %------------------------------------------------------------------ + function V = reconstruct(this, iterations) + % Compute reconstruction. + % Uses tomography.sinogram + % Initial solution (if available) should be stored in tomography.V + % >> V = tomography.reconstruct(iterations); + + if ~this.initialized + this.initialize(); + end + + this.V = this.reconstruct_c(this.sinogram, this.V, [], iterations); + if strcmp(this.inner_circle,'yes') + this.V = this.selectROI(this.V); + end + V = this.V; + end + + %------------------------------------------------------------------ + function I = reconstructMask(this, mask, iterations) + % Compute reconstruction with mask. + % Uses tomography.sinogram + % Initial solution (if available) should be stored in tomography.V + % >> V = tomography.reconstructMask(mask, iterations); + + if ~this.initialized + this.initialize(); + end + + if strcmp(this.inner_circle,'yes') + mask = this.selectROI(mask); + end + I = this.reconstruct_c(this.sinogram, this.V, mask, iterations); + end + %------------------------------------------------------------------ + + end + + %---------------------------------------------------------------------- + methods (Access = protected) + + %------------------------------------------------------------------ + % Protected function: create FP + function sinogram = project_c(this, volume) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + % data is stored in astra memory + if numel(volume) == 1 + + if strcmp(this.gpu, 'yes') + sinogram_tmp = astra_create_sino_cuda(volume, this.proj_geom_sr, this.vol_geom, this.gpu_core); + else + sinogram_tmp = astra_create_sino(volume, this.proj_id); + end + + % sinogram downsampling + if this.superresolution > 1 + sinogram_data = astra_mex_data2d('get', sinogram_tmp); + astra_mex_data2d('delete', sinogram_tmp); + sinogram_data = downsample_sinogram(sinogram_data, this.superresolution); + %if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + % sinogram = sinogram / this.superresolution; + %end + sinogram = astra_mex_data2d('create','sino', this.proj_geom, sinogram_data); + else + sinogram = sinogram_tmp; + end + + % data is stored in matlab memory + else + + [tmp_id, sinogram] = astra_create_sino3d_cuda(volume, this.proj_geom, this.vol_geom); + astra_mex_data3d('delete', tmp_id); + + end + + end + + %------------------------------------------------------------------ + % Protected function: reconstruct + function V = reconstruct_c(this, sinogram, V0, mask, iterations) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + % data is stored in astra memory + if numel(sinogram) == 1 + V = this.reconstruct_c_astra(sinogram, V0, mask, iterations); + + % data is stored in matlab memory + else + V = this.reconstruct_c_matlab(sinogram, V0, mask, iterations); + end + + end + + %------------------------------------------------------------------ + % Protected function: reconstruct (data in matlab) + function V = reconstruct_c_matlab(this, sinogram, V0, mask, iterations) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + % parse method + method2 = upper(this.method); + if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA') + iterations = iterations * size(sinogram,1); + elseif strcmp(method2, 'ART') + iterations = iterations * numel(sinogram); + end + + % create data objects +% V = zeros(this.vol_geom.GridRowCount, this.vol_geom.GridColCount, size(sinogram,3)); + reconstruction_id = astra_mex_data3d('create', '-vol', this.vol_geom); + sinogram_id = astra_mex_data3d('create', '-proj3d', this.proj_geom); + if numel(mask) > 0 + mask_id = astra_mex_data3d('create', '-vol', this.vol_geom); + end + + % algorithm configuration + cfg = this.cfg_base; + cfg.ProjectionDataId = sinogram_id; + cfg.ReconstructionDataId = reconstruction_id; + if numel(mask) > 0 + cfg.option.ReconstructionMaskId = mask_id; + end + alg_id = astra_mex_algorithm('create', cfg); + +% % loop slices +% for slice = 1:size(sinogram,3) + + % fetch slice of initial reconstruction + if numel(V0) > 0 + astra_mex_data3d('store', reconstruction_id, V0); + else + astra_mex_data3d('store', reconstruction_id, 0); + end + + % fetch slice of sinogram + astra_mex_data3d('store', sinogram_id, sinogram); + + % fecth slice of mask + if numel(mask) > 0 + astra_mex_data3d('store', mask_id, mask); + end + + % iterate + astra_mex_algorithm('iterate', alg_id, iterations); + + % fetch data + V = astra_mex_data3d('get', reconstruction_id); + +% end + + % correct attenuation factors for super-resolution + if this.superresolution > 1 && strcmp(this.gpu,'yes') + if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + if numel(mask) > 0 + V(mask > 0) = V(mask > 0) ./ this.superresolution; + else + V = V ./ this.superresolution; + end + end + end + + % garbage collection + astra_mex_algorithm('delete', alg_id); + astra_mex_data3d('delete', sinogram_id, reconstruction_id); + if numel(mask) > 0 + astra_mex_data3d('delete', mask_id); + end + + end + + %------------------------------------------------------------------ + % Protected function: reconstruct (data in astra) + function V = reconstruct_c_astra(this, sinogram, V0, mask, iterations) + + if this.initialized == 0 + error('IterativeTomography not initialized'); + end + + if numel(V0) > 1 || numel(mask) > 1 || numel(sinogram) > 1 + error('Not all required data is stored in the astra memory'); + end + + if numel(V0) == 0 + V0 = astra_mex_data2d('create', '-vol', this.vol_geom, 0); + end + + % parse method + method2 = upper(this.method); + if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA') + iterations = iterations * astra_geom_size(this.proj_geom, 1); + elseif strcmp(method2, 'ART') + s = astra_geom_size(this.proj_geom); + iterations = iterations * s(1) * s(2); + end + + % algorithm configuration + cfg = this.cfg_base; + cfg.ProjectionDataId = sinogram; + cfg.ReconstructionDataId = V0; + if numel(mask) > 0 + cfg.option.ReconstructionMaskId = mask; + end + alg_id = astra_mex_algorithm('create', cfg); + + % iterate + astra_mex_algorithm('iterate', alg_id, iterations); + + % fetch data + V = V0; + + % correct attenuation factors for super-resolution + if this.superresolution > 1 + if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat') + if numel(mask) > 0 + astra_data_op_masked('$1./s1', [V V], [this.superresolution this.superresolution], mask, this.gpu_core); + else + astra_data_op('$1./s1', [V V], [this.superresolution this.superresolution], this.gpu_core); + end + end + end + + % garbage collection + astra_mex_algorithm('delete', alg_id); + + end + + %------------------------------------------------------------------ + function V_out = selectROI(~, V_in) + + if numel(V_in) == 1 + cfg = astra_struct('RoiSelect_CUDA'); + cfg.DataId = V_in; + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('run', alg_id); + astra_mex_algorithm('delete', alg_id); + V_out = V_in; + else + V_out = ROIselectfull(V_in, min([size(V_in,1), size(V_in,2)])); + end + + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/Kernels.m b/matlab/algorithms/DART/Kernels.m new file mode 100644 index 0000000..b5e3134 --- /dev/null +++ b/matlab/algorithms/DART/Kernels.m @@ -0,0 +1,68 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef Kernels + %KERNELS Summary of this class goes here + % Detailed explanation goes here + + properties + + end + + methods(Static) + + function K = BinaryPixelKernel(radius, conn) + + if nargin < 2 + conn = 8; + end + + % 2D, 4conn + if conn == 4 + K = [0 1 0; 1 1 1; 0 1 0]; + for i = 2:radius + K = conv2(K,K); + end + K = double(K >= 1); + + % 2D, 8conn + elseif conn == 8 + K = ones(2*radius+1, 2*radius+1); + + % 3D, 6conn + elseif conn == 6 + K = zeros(3,3,3); + K(:,:,1) = [0 0 0; 0 1 0; 0 0 0]; + K(:,:,2) = [0 1 0; 1 1 1; 0 1 0]; + K(:,:,3) = [0 0 0; 0 1 0; 0 0 0]; + for i = 2:radius + K = convn(K,K); + end + K = double(K >= 1); + + % 2D, 27conn + elseif conn == 26 + K = ones(2*radius+1, 2*radius+1, 2*radius+1); + + else + disp('Invalid conn') + end + end + + + + + + + end + +end + diff --git a/matlab/algorithms/DART/MaskingDefault.m b/matlab/algorithms/DART/MaskingDefault.m new file mode 100644 index 0000000..6bd25a5 --- /dev/null +++ b/matlab/algorithms/DART/MaskingDefault.m @@ -0,0 +1,212 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef MaskingDefault < matlab.mixin.Copyable + + % Default policy class for masking for DART. + + %---------------------------------------------------------------------- + properties (Access=public) + + radius = 1; % SETTING: Radius of masking kernel. + conn = 8; % SETTING: Connectivity window. For 2D: 4 or 8. For 3D: 6 or 26. + edge_threshold = 1; % SETTING: Number of pixels in the window that should be different. + random = 0.1; % SETTING: Percentage of random points. Between 0 and 1. + gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'} + gpu_core = 0; % SETTING: Which gpu core to use, only when gpu='yes'. + + end + + %---------------------------------------------------------------------- + methods (Access=public) + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.masking.getsettings(); + settings.radius = this.radius; + settings.conn = this.conn; + settings.edge_threshold = this.edge_threshold; + settings.random = this.random; + end + + %------------------------------------------------------------------ + function Mask = apply(this, ~, S) + % Applies masking. + % >> Mask = DART.segmentation.apply(DART, S); + + % 2D, one slice + if size(S,3) == 1 + if strcmp(this.gpu,'yes') + Mask = this.apply_2D_gpu(S); + else + Mask = this.apply_2D(S); + end + + % 3D, slice by slice + elseif this.conn == 4 || this.conn == 8 + Mask = zeros(size(S)); + for slice = 1:size(S,3) + if strcmp(this.gpu,'yes') + Mask(:,:,slice) = this.apply_2D_gpu(S(:,:,slice)); + else + Mask(:,:,slice) = this.apply_2D(S(:,:,slice)); + end + end + + % 3D, full + else + if strcmp(this.gpu,'yes') + Mask = this.apply_3D_gpu(S); + else + Mask = this.apply_3D(S); + end + end + + end + + end + + %---------------------------------------------------------------------- + methods (Access=protected) + + %------------------------------------------------------------------ + function Mask = apply_2D_gpu(this, S) + + vol_geom = astra_create_vol_geom(size(S)); + data_id = astra_mex_data2d('create', '-vol', vol_geom, S); + mask_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + + cfg = astra_struct('DARTMASK_CUDA'); + cfg.SegmentationDataId = data_id; + cfg.MaskDataId = mask_id; + cfg.option.GPUindex = this.gpu_core; + cfg.option.Connectivity = this.conn; + cfg.option.Threshold = this.edge_threshold; + cfg.option.Radius = this.radius; + + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('iterate',alg_id,1); + Mask = astra_mex_data2d('get', mask_id); + + astra_mex_algorithm('delete', alg_id); + astra_mex_data2d('delete', data_id, mask_id); + + % random + RandomField = double(rand(size(S)) < this.random); + + % combine + Mask = or(Mask, RandomField); + + end + + %------------------------------------------------------------------ + function Mask = apply_2D(this, S) + + r = this.radius; + w = 2 * r + 1; + + kernel = Kernels.BinaryPixelKernel(r, this.conn); + + % edges + Xlarge = zeros(size(S,1)+w-1, size(S,2)+w-1); + Xlarge(1+r:end-r, 1+r:end-r) = S; + + Edges = zeros(size(S)); + for s = -r:r + for t = -r:r + if kernel(s+r+1, t+r+1) == 0 + continue + end + Temp = abs(Xlarge(1+r:end-r, 1+r:end-r) - Xlarge(1+r+s:end-r+s, 1+r+t:end-r+t)); + Edges(Temp > eps) = Edges(Temp > eps) + 1; + end + end + + Edges = Edges > this.edge_threshold; + + % random + RandomField = double(rand(size(S)) < this.random); + + % combine + Mask = or(Edges, RandomField); + + end + + %------------------------------------------------------------------ + function Mask = apply_3D(this, S) + + r = this.radius; + w = 2 * r + 1; + + kernel = Kernels.BinaryPixelKernel(r, this.conn); + + % edges + Xlarge = zeros(size(S,1)+w-1, size(S,2)+w-1, size(S,3)+w-1); + Xlarge(1+r:end-r, 1+r:end-r, 1+r:end-r) = S; + + Edges = zeros(size(S)); + for s = -r:r + for t = -r:r + for u = -r:r + if kernel(s+r+1, t+r+1, u+r+1) == 0 + continue + end + Temp = abs(Xlarge(1+r:end-r, 1+r:end-r, 1+r:end-r) - Xlarge(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u)); + Edges(Temp > eps) = 1; + end + end + end + + clear Xlarge; + + % random + RandomField = double(rand(size(S)) < this.random); + + % combine + Mask = or(Edges, RandomField); + + end + + %------------------------------------------------------------------ + function Mask = apply_3D_gpu(this, S) + + vol_geom = astra_create_vol_geom(size(S)); + data_id = astra_mex_data3d('create', '-vol', vol_geom, S); + + cfg = astra_struct('DARTMASK3D_CUDA'); + cfg.SegmentationDataId = data_id; + cfg.MaskDataId = data_id; + cfg.option.GPUindex = this.gpu_core; + cfg.option.Connectivity = this.conn; + cfg.option.Threshold = this.edge_threshold; + cfg.option.Radius = this.radius; + + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('iterate',alg_id,1); + Mask = astra_mex_data3d('get', data_id); + + astra_mex_algorithm('delete', alg_id); + astra_mex_data3d('delete', data_id); + + % random + RandomField = double(rand(size(S)) < this.random); + + % combine + Mask = or(Mask, RandomField); + + end + + %------------------------------------------------------------------ + end + +end + diff --git a/matlab/algorithms/DART/MaskingGPU.m b/matlab/algorithms/DART/MaskingGPU.m new file mode 100644 index 0000000..c4ef2b7 --- /dev/null +++ b/matlab/algorithms/DART/MaskingGPU.m @@ -0,0 +1,94 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef MaskingGPU < matlab.mixin.Copyable + + % Policy class for masking for DART with GPU accelerated code (deprecated). + + %---------------------------------------------------------------------- + properties (Access=public) + + radius = 1; % SETTING: Radius of masking kernel. + conn = 8; % SETTING: Connectivity window. For 2D: 4 or 8. For 3D: 6 or 26. + edge_threshold = 1; % SETTING: Number of pixels in the window that should be different. + gpu_core = 0; % SETTING: + random = 0.1; % SETTING: Percentage of random points. Between 0 and 1. + + end + + %---------------------------------------------------------------------- + methods (Access=public) + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.masking.getsettings(); + settings.radius = this.radius; + settings.conn = this.conn; + settings.edge_threshold = this.edge_threshold; + settings.random = this.random; + end + + %------------------------------------------------------------------ + function Mask = apply(this, ~, V_in) + % Applies masking. + % >> Mask = DART.segmentation.apply(DART, V_in); + + % 2D, one slice + if size(V_in,3) == 1 + Mask = this.apply_2D(V_in); + + % 3D, slice by slice + elseif this.conn == 4 || this.conn == 8 + Mask = zeros(size(V_in)); + for slice = 1:size(V_in,3) + Mask(:,:,slice) = this.apply_2D(V_in(:,:,slice)); + end + + % 3D, full + else + error('Full 3D masking on GPU not implemented.') + end + + end + + end + + %---------------------------------------------------------------------- + methods (Access=protected) + + %------------------------------------------------------------------ + function Mask = apply_2D(this, S) + + vol_geom = astra_create_vol_geom(size(S)); + data_id = astra_mex_data2d('create', '-vol', vol_geom, S); + mask_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + + cfg = astra_struct('DARTMASK_CUDA'); + cfg.SegmentationDataId = data_id; + cfg.MaskDataId = mask_id; + cfg.option.GPUindex = this.gpu_core; + %cfg.option.Connectivity = this.conn; + + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('iterate',alg_id,1); + Mask = astra_mex_data2d('get', mask_id); + + astra_mex_algorithm('delete', alg_id); + astra_mex_data2d('delete', data_id, mask_id); + + end + end + + + +end + diff --git a/matlab/algorithms/DART/OutputDefault.m b/matlab/algorithms/DART/OutputDefault.m new file mode 100644 index 0000000..a34a430 --- /dev/null +++ b/matlab/algorithms/DART/OutputDefault.m @@ -0,0 +1,173 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef OutputDefault < matlab.mixin.Copyable + + % Default policy class for output for DART. + + properties (Access=public) + + directory = ''; % SETTING: Directory to save output. + pre = ''; % SETTING: Prefix of output. + + save_images = 'no'; % SETTING: Save the images. 'no', 'yes' (='S') OR {'S', 'I', 'Mask', 'P'} + save_results = 'no'; % SETTING: Save the results. 'yes', 'no' OR {'base', 'stats', 'settings', 'S', 'V', 'V0'} + save_object = 'no'; % SETTING: Save the DART object. {'no','yes'} + + save_interval = 1; % SETTING: # DART iteration between saves. + save_images_interval = []; % SETTING: Overwrite interval for save_images. + save_results_interval = []; % SETTING: Overwrite interval for save_results. + save_object_interval = []; % SETTING: Overwrite interval for save_object. + + slices = 1; % SETTING: In case of 3D, which slices to save? + + verbose = 'no'; % SETTING: Verbose? {'no','yes'} + + end + + methods (Access=public) + + %------------------------------------------------------------------ + function pre_initial_iteration(this, ~) + if strcmp(this.verbose,'yes') + tic + fprintf(1, 'initial iteration...'); + end + end + + %------------------------------------------------------------------ + function post_initial_iteration(this, ~) + if strcmp(this.verbose,'yes') + t = toc; + fprintf(1, 'done in %f s.\n', t); + end + end + + %------------------------------------------------------------------ + function pre_iteration(this, DART) + if strcmp(this.verbose,'yes') + tic; + fprintf(1, '%s dart iteration %d...', this.pre, DART.iterationcount); + end + end + + %------------------------------------------------------------------ + function post_iteration(this, DART) + + % print output + if strcmp(this.verbose,'yes') + t = toc; + s = DART.statistics.tostring(DART.stats); + fprintf(1, 'done in %0.2fs %s.\n', t, s); + end + + % save DART object + if do_object(this, DART) + save(sprintf('%s%sobject_%i.mat', this.directory, this.pre, DART.iterationcount), '-v7.3', 'DART'); + end + + % save .mat + if do_results(this, DART) + base = DART.base; + stats = DART.stats; + S = DART.S; + V = DART.V; + V0 = DART.V0; + settings = DART.getsettings(); + if ~iscell(this.save_results) + save(sprintf('%s%sresults_%i.mat', this.directory, this.pre, DART.iterationcount), '-v7.3', 'base', 'stats', 'S', 'V', 'V0', 'settings'); + else + string = []; + for i = 1:numel(this.save_results) + string = [string this.save_results{i} '|']; + end + save(sprintf('%s%sresults_%i.mat', this.directory, this.pre, DART.iterationcount), '-v7.3', '-regexp', string(1:end-1)); + end + end + + % save images + if do_images(this, DART) + + if ~iscell(this.save_images) && strcmp(this.save_images, 'yes') + output_image(this, DART, 'S') + elseif iscell(this.save_images) + for i = 1:numel(this.save_images) + output_image(this, DART, this.save_images{i}); + end + end + + end + + end + %------------------------------------------------------------------ + + end + + %---------------------------------------------------------------------- + methods (Access=private) + + function output_image(this, DART, data) + % 2D + if numel(size(DART.S)) == 2 + eval(['imwritesc(DART.' data ', sprintf(''%s%s' data '_%i.png'', this.directory, this.pre, DART.iterationcount))']); + % 3D + elseif numel(size(DART.S)) == 3 + for slice = this.slices + eval(['imwritesc(DART.' data '(:,:,slice), sprintf(''%s%s' data '_%i_slice%i.png'', this.directory, this.pre, DART.iterationcount, slice))']); + end + end + end + + %------------------------------------------------------------------ + function out = do_object(this, DART) + if strcmp(this.save_object,'no') + out = 0; + return + end + if numel(this.save_object_interval) == 0 && mod(DART.iterationcount, this.save_interval) == 0 + out = 1; + elseif mod(DART.iterationcount, this.save_object_interval) == 0 + out = 1; + else + out = 0; + end + end + %------------------------------------------------------------------ + function out = do_results(this, DART) + if strcmp(this.save_results,'no') + out = 0; + return + end + if numel(this.save_results_interval) == 0 && mod(DART.iterationcount, this.save_interval) == 0 + out = 1; + elseif mod(DART.iterationcount, this.save_results_interval) == 0 + out = 1; + else + out = 0; + end + end + + %------------------------------------------------------------------ + function out = do_images(this, DART) + if numel(this.save_images_interval) == 0 && mod(DART.iterationcount, this.save_interval) == 0 + out = 1; + elseif mod(DART.iterationcount, this.save_images_interval) == 0 + out = 1; + else + out = 0; + end + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/SegmentationDefault.m b/matlab/algorithms/DART/SegmentationDefault.m new file mode 100644 index 0000000..c1d7d99 --- /dev/null +++ b/matlab/algorithms/DART/SegmentationDefault.m @@ -0,0 +1,55 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef SegmentationDefault < matlab.mixin.Copyable + + % Default policy class for segmentation for DART. + + %---------------------------------------------------------------------- + properties (Access=public) + rho = []; % SETTING: Grey levels. + tau = []; % SETTING: Threshold values. + end + + %---------------------------------------------------------------------- + methods (Access=public) + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.segmentation.getsettings(); + settings.rho = this.rho; + settings.tau = this.tau; + end + + %------------------------------------------------------------------ + function this = estimate_grey_levels(this, ~, ~) + % Estimates grey levels + % >> DART.segmentation.estimate_grey_levels(); + end + + %------------------------------------------------------------------ + function V_out = apply(this, ~, V_in) + % Applies segmentation. + % >> V_out = DART.segmentation.apply(DART, V_in); + + V_out = ones(size(V_in)) * this.rho(1); + for n = 2:length(this.rho) + V_out(this.tau(n-1) < V_in) = this.rho(n); + end + + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/SmoothingDefault.m b/matlab/algorithms/DART/SmoothingDefault.m new file mode 100644 index 0000000..58a8baa --- /dev/null +++ b/matlab/algorithms/DART/SmoothingDefault.m @@ -0,0 +1,179 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef SmoothingDefault < matlab.mixin.Copyable + + % Default policy class for smoothing for DART. + + %---------------------------------------------------------------------- + properties (Access=public) + radius = 1; % SETTING: Radius of smoothing kernel. + b = 0.1; % SETTING: Intensity of smoothing. Between 0 and 1. + full3d = 'yes'; % SETTING: smooth in 3D? {'yes','no'} + gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'} + gpu_core = 0; % SETTING: Which gpu core to use, only when gpu='yes'. + end + + + %---------------------------------------------------------------------- + methods (Access=public) + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.smoothing.getsettings(); + settings.radius = this.radius; + settings.b = this.b; + settings.full3d = this.full3d; + end + + %------------------------------------------------------------------ + function V_out = apply(this, ~, V_in) + % Applies smoothing. + % >> V_out = DART.smoothing.apply(DART, V_in); + + % 2D, one slice + if size(V_in,3) == 1 + if strcmp(this.gpu,'yes') + V_out = this.apply_2D_gpu(V_in); + else + V_out = this.apply_2D(V_in); + end + + % 3D, slice by slice + elseif ~strcmp(this.full3d,'yes') + V_out = zeros(size(V_in)); + for slice = 1:size(V_in,3) + if strcmp(this.gpu,'yes') + V_out(:,:,slice) = this.apply_2D_gpu(V_in(:,:,slice)); + else + V_out(:,:,slice) = this.apply_2D(V_in(:,:,slice)); + end + end + + % 3D, full + else + if strcmp(this.gpu,'yes') + V_out = this.apply_3D_gpu(V_in); + else + V_out = this.apply_3D(V_in); + end + end + + end + + end + + %---------------------------------------------------------------------- + methods (Access=protected) + + %------------------------------------------------------------------ + function V_out = apply_2D(this, V_in) + + r = this.radius; + w = 2 * r + 1; + + % Set Kernel + K = ones(w) * this.b / (w.^2-1); % edges + K(r+1,r+1) = 1 - this.b; % center + + % output window + V_out = zeros(size(V_in,1) + w-1, size(V_in,2) + w - 1); + + % blur convolution + for s = -r:r + for t = -r:r + V_out(1+r+s:end-r+s, 1+r+t:end-r+t) = V_out(1+r+s:end-r+s, 1+r+t:end-r+t) + K(r+1+s, r+1+t) * V_in; + end + end + + % shrink output window + V_out = V_out(1+r:end-r, 1+r:end-r); + + end + + %------------------------------------------------------------------ + function V_out = apply_2D_gpu(this, V_in) + + vol_geom = astra_create_vol_geom(size(V_in)); + in_id = astra_mex_data2d('create', '-vol', vol_geom, V_in); + out_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + + cfg = astra_struct('DARTSMOOTHING_CUDA'); + cfg.InDataId = in_id; + cfg.OutDataId = out_id; + cfg.option.Intensity = this.b; + cfg.option.Radius = this.radius; + cfg.option.GPUindex = this.gpu_core; + + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('iterate',alg_id,1); + V_out = astra_mex_data2d('get', out_id); + + astra_mex_algorithm('delete', alg_id); + astra_mex_data2d('delete', in_id, out_id); + + end + + %------------------------------------------------------------------ + function I_out = apply_3D(this, I_in) + + r = this.radius; + w = 2 * r + 1; + + % Set Kernel + K = ones(w,w,w) * this.b / (w.^3-1); % edges + K(r+1,r+1,r+1) = 1 - this.b; % center + + % output window + I_out = zeros(size(I_in,1)+w-1, size(I_in,2)+w-1, size(I_in,3)+w-1); + + % blur convolution + for s = -r:r + for t = -r:r + for u = -r:r + I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) = I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) + K(r+1+s, r+1+t, r+1+u) * I_in; + end + end + end + + % shrink output window + I_out = I_out(1+r:end-r, 1+r:end-r, 1+r:end-r); + + end + + %------------------------------------------------------------------ + function V_out = apply_3D_gpu(this, V_in) + + vol_geom = astra_create_vol_geom(size(V_in)); + data_id = astra_mex_data3d('create', '-vol', vol_geom, V_in); + + cfg = astra_struct('DARTSMOOTHING3D_CUDA'); + cfg.InDataId = data_id; + cfg.OutDataId = data_id; + cfg.option.Intensity = this.b; + cfg.option.Radius = this.radius; + cfg.option.GPUindex = this.gpu_core; + + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('iterate', alg_id, 1); + V_out = astra_mex_data3d('get', data_id); + + astra_mex_algorithm('delete', alg_id); + astra_mex_data3d('delete', data_id); + + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/SmoothingGPU.m b/matlab/algorithms/DART/SmoothingGPU.m new file mode 100644 index 0000000..857da37 --- /dev/null +++ b/matlab/algorithms/DART/SmoothingGPU.m @@ -0,0 +1,119 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef SmoothingGPU < matlab.mixin.Copyable + + % Default policy class for smoothing for DART. + + %---------------------------------------------------------------------- + properties (Access=public) + radius = 1; % SETTING: Radius of smoothing kernel. + b = 0.1; % SETTING: Intensity of smoothing. Between 0 and 1. + full3d = 'yes'; % SETTING: smooth in 3D? {'yes','no'} + gpu_core = 0; % SETTING: + end + + + %---------------------------------------------------------------------- + methods (Access=public) + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.smoothing.getsettings(); + settings.radius = this.radius; + settings.b = this.b; + settings.full3d = this.full3d; + end + + %------------------------------------------------------------------ + function V_out = apply(this, ~, V_in) + % Applies smoothing. + % >> V_out = DART.smoothing.apply(DART, V_in); + + % 2D, one slice + if size(V_in,3) == 1 + V_out = this.apply_2D(V_in); + + % 3D, slice by slice + elseif ~strcmp(this.full3d,'yes') + V_out = zeros(size(V_in)); + for slice = 1:size(V_in,3) + V_out(:,:,slice) = this.apply_2D(V_in(:,:,slice)); + end + + % 3D, full + else + V_out = this.apply_3D(V_in); + end + + end + + end + + %---------------------------------------------------------------------- + methods (Access=protected) + + %------------------------------------------------------------------ + function V_out = apply_2D(this, V_in) + + vol_geom = astra_create_vol_geom(size(V_in)); + in_id = astra_mex_data2d('create', '-vol', vol_geom, V_in); + out_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + + cfg = astra_struct('DARTSMOOTHING_CUDA'); + cfg.InDataId = in_id; + cfg.OutDataId = out_id; + cfg.Intensity = this.b; + cfg.option.GPUindex = this.gpu_core; + + alg_id = astra_mex_algorithm('create',cfg); + astra_mex_algorithm('iterate',alg_id,1); + V_out = astra_mex_data2d('get', out_id); + + astra_mex_algorithm('delete', alg_id); + astra_mex_data2d('delete', in_id, out_id); + + + end + + %------------------------------------------------------------------ + function I_out = apply_3D(this, I_in) + + r = this.radius; + w = 2 * r + 1; + + % Set Kernel + K = ones(w,w,w) * this.b / (w.^3-1); % edges + K(r+1,r+1,r+1) = 1 - this.b; % center + + % output window + I_out = zeros(size(I_in,1)+w-1, size(I_in,2)+w-1, size(I_in,3)+w-1); + + % blur convolution + for s = -r:r + for t = -r:r + for u = -r:r + I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) = I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) + K(r+1+s, r+1+t, r+1+u) * I_in; + end + end + end + + % shrink output window + I_out = I_out(1+r:end-r, 1+r:end-r, 1+r:end-r); + + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/StatisticsDefault.m b/matlab/algorithms/DART/StatisticsDefault.m new file mode 100644 index 0000000..7822c5f --- /dev/null +++ b/matlab/algorithms/DART/StatisticsDefault.m @@ -0,0 +1,72 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef StatisticsDefault < matlab.mixin.Copyable + + % Default policy class for statistics for DART. + + properties (Access=public) + pixel_error = 'yes'; % SETTING: Store pixel error? {'yes','no'} + proj_diff = 'yes'; % SETTING: Store projection difference? {'yes','no'} + timing = 'yes'; % SETTING: Store timings? {'yes','no'} + end + + + methods (Access=public) + + %------------------------------------------------------------------ + function stats = apply(this, DART) + % Applies statistics. + % >> stats = DART.statistics.apply(DART); + + stats = DART.stats; + + % timing + if strcmp(this.timing, 'yes') + stats.timing(DART.iterationcount) = toc(DART.start_tic); + end + + % pixel error + if strcmp(this.pixel_error, 'yes') && isfield(DART.base,'phantom') + [stats.rnmp, stats.nmp] = compute_rnmp(DART.base.phantom, DART.S); + stats.rnmp_hist(DART.iterationcount) = stats.rnmp; + stats.nmp_hist(DART.iterationcount) = stats.nmp; + end + + % projection difference + if strcmp(this.proj_diff, 'yes') + new_sino = DART.tomography.createForwardProjection(DART, DART.S); + stats.proj_diff = sum((new_sino(:) - DART.base.sinogram(:)) .^2 ) ./ (sum(DART.base.sinogram(:)) ); + stats.proj_diff_hist(DART.iterationcount) = stats.proj_diff; + end + + end + + %------------------------------------------------------------------ + function s = tostring(~, stats) + % To string. + % >> stats = DART.statistics.apply(stats); + + s = ''; + if isfield(stats, 'nmp') + s = sprintf('%s [%d]', s, stats.nmp); + end + if isfield(stats, 'proj_diff') + s = sprintf('%s {%0.2d}', s, stats.proj_diff); + end + + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/TomographyDefault.m b/matlab/algorithms/DART/TomographyDefault.m new file mode 100644 index 0000000..4db3905 --- /dev/null +++ b/matlab/algorithms/DART/TomographyDefault.m @@ -0,0 +1,73 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef TomographyDefault < IterativeTomography + + % Policy class for tomography for DART. + + %---------------------------------------------------------------------- + properties (Access=public) + t = 5; % SETTING: # ARMiterations, each DART iteration. + t0 = 100; % SETTING: # ARM iterations at DART initialization. + end + %---------------------------------------------------------------------- + + methods + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.tomography.getsettings(); +% settings = getsettings@IterativeTomography(); + settings.t = this.t; + settings.t0 = this.t0; + end + + %------------------------------------------------------------------ + function initialize(this, DART) + % Initializes this object. + % >> DART.tomography.initialize(); + this.proj_geom = DART.base.proj_geom; + this.initialize@IterativeTomography(); + end + + %------------------------------------------------------------------ + function P = createForwardProjection(this, ~, volume) + % Compute forward projection. + % >> DART.tomography.createForwardProjection(DART, volume); + P = this.project_c(volume); + end + + %------------------------------------------------------------------ + function I = createReconstruction(this, ~, sinogram, V0, mask) + % Compute reconstruction (with mask). + % >> DART.tomography.createReconstruction(DART, sinogram, V0, mask); + if strcmp(this.inner_circle,'yes') + mask = ROIselectfull(mask, size(mask,1)); + end + I = this.reconstruct_c(sinogram, V0, mask, this.t); + end + + %------------------------------------------------------------------ + function I = createInitialReconstruction(this, ~, sinogram) + % Compute reconstruction (initial). + % >> DART.tomography.createInitialReconstruction(DART, sinogram); + I = this.reconstruct_c(sinogram, [], [], this.t0); + if strcmp(this.inner_circle,'yes') + I = ROIselectfull(I, size(I,1)); + end + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/TomographyDefault3D.m b/matlab/algorithms/DART/TomographyDefault3D.m new file mode 100644 index 0000000..2be1b17 --- /dev/null +++ b/matlab/algorithms/DART/TomographyDefault3D.m @@ -0,0 +1,73 @@ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +% +% Author of this DART Algorithm: Wim van Aarle + + +classdef TomographyDefault3D < IterativeTomography3D + + % Policy class for 3D tomography for DART. + + %---------------------------------------------------------------------- + properties (Access=public) + t = 5; % SETTING: # ARMiterations, each DART iteration. + t0 = 100; % SETTING: # ARM iterations at DART initialization. + end + %---------------------------------------------------------------------- + + methods + + %------------------------------------------------------------------ + function settings = getsettings(this) + % Returns a structure containing all settings of this object. + % >> settings = DART.tomography.getsettings(); +% settings = getsettings@IterativeTomography(); + settings.t = this.t; + settings.t0 = this.t0; + end + + %------------------------------------------------------------------ + function initialize(this, DART) + % Initializes this object. + % >> DART.tomography.initialize(); + this.proj_geom = DART.base.proj_geom; + this.initialize@IterativeTomography3D(); + end + + %------------------------------------------------------------------ + function P = createForwardProjection(this, ~, volume) + % Compute forward projection. + % >> DART.tomography.createForwardProjection(DART, volume); + P = this.project_c(volume); + end + + %------------------------------------------------------------------ + function I = createReconstruction(this, ~, sinogram, V0, mask) + % Compute reconstruction (with mask). + % >> DART.tomography.createReconstruction(DART, sinogram, V0, mask); + if strcmp(this.inner_circle,'yes') + mask = ROIselectfull(mask, size(mask,1)); + end + I = this.reconstruct_c(sinogram, V0, mask, this.t); + end + + %------------------------------------------------------------------ + function I = createInitialReconstruction(this, ~, sinogram) + % Compute reconstruction (initial). + % >> DART.tomography.createInitialReconstruction(DART, sinogram); + I = this.reconstruct_c(sinogram, [], [], this.t0); + if strcmp(this.inner_circle,'yes') + I = ROIselectfull(I, size(I,1)); + end + end + %------------------------------------------------------------------ + + end + +end + diff --git a/matlab/algorithms/DART/examples/cylinders.png b/matlab/algorithms/DART/examples/cylinders.png Binary files differnew file mode 100644 index 0000000..8d1c0b2 --- /dev/null +++ b/matlab/algorithms/DART/examples/cylinders.png diff --git a/matlab/algorithms/DART/examples/example1.m b/matlab/algorithms/DART/examples/example1.m new file mode 100644 index 0000000..daa3ce8 --- /dev/null +++ b/matlab/algorithms/DART/examples/example1.m @@ -0,0 +1,79 @@ +clear all; + +addpath('..'); + +% +% Example 1: parallel beam, three slices. +% + +% Configuration +proj_count = 20; +slice_count = 3; +dart_iterations = 20; +filename = 'cylinders.png'; +outdir = './'; +prefix = 'example1'; +rho = [0, 1]; +tau = 0.5; +gpu_core = 0; + +% Load phantom. +I = double(imread(filename)) / 255; + +% Create projection and volume geometries. +det_count = size(I, 1); +angles = linspace(0, pi - pi / proj_count, proj_count); +proj_geom = astra_create_proj_geom('parallel3d', 1, 1, slice_count, det_count, angles); +vol_geom = astra_create_vol_geom(det_count, det_count, 1); + +% Create sinogram. +[sinogram_id, sinogram] = astra_create_sino3d_cuda(I, proj_geom, vol_geom); +astra_mex_data3d('delete', sinogram_id); + +% +% DART +% + +base.sinogram = sinogram; +base.proj_geom = proj_geom; + +D = DARTalgorithm(base); + +D.tomography = TomographyDefault3D(); +D.tomography.t0 = 100; +D.tomography.t = 10; +D.tomography.method = 'SIRT3D_CUDA'; +D.tomography.gpu_core = gpu_core; +D.tomography.use_minc = 'yes'; +% D.tomography.maxc = 0.003; % Not a sensible value, just for demonstration. + +D.segmentation.rho = rho; +D.segmentation.tau = tau; + +D.smoothing.b = 0.1; +D.smoothing.full3d = 'yes'; +D.smoothing.gpu_core = gpu_core; + +D.masking.random = 0.1; +D.masking.conn = 6; +D.masking.gpu_core = gpu_core; + +D.output.directory = outdir; +D.output.pre = [prefix '_']; +D.output.save_images = 'no'; +D.output.save_results = {'stats', 'settings', 'S', 'V'}; +D.output.save_interval = dart_iterations; +D.output.verbose = 'yes'; + +D.statistics.proj_diff = 'no'; + +D.initialize(); + +disp([D.output.directory D.output.pre]); + +D.iterate(dart_iterations); + +% Convert middle slice of final iteration to png. +load([outdir '/' prefix '_results_' num2str(dart_iterations) '.mat']); +imwritesc(D.S(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_S.png']); +imwritesc(D.V(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_V.png']); diff --git a/matlab/algorithms/DART/examples/example2.m b/matlab/algorithms/DART/examples/example2.m new file mode 100644 index 0000000..8ee8cba --- /dev/null +++ b/matlab/algorithms/DART/examples/example2.m @@ -0,0 +1,80 @@ +clear all; + +addpath('..'); + +% +% Example 2: cone beam, full cube. +% + +% Configuration +det_count = 128; +proj_count = 45; +slice_count = det_count; +dart_iterations = 20; +outdir = './'; +prefix = 'example2'; +rho = [0 0.5 1]; +tau = [0.25 0.75]; +gpu_core = 0; + +% Create phantom. +% I = phantom3d([1 0.9 0.9 0.9 0 0 0 0 0 0; -0.5 0.8 0.8 0.8 0 0 0 0 0 0; -0.5 0.3 0.3 0.3 0 0 0 0 0 0], det_count); +% save('phantom3d', 'I'); +load('phantom3d'); % Loads I. + +% Create projection and volume geometries. +angles = linspace(0, pi - pi / proj_count, proj_count); +proj_geom = astra_create_proj_geom('cone', 1, 1, slice_count, det_count, angles, 500, 0); +vol_geom = astra_create_vol_geom(det_count, det_count, slice_count); + +% Create sinogram. +[sinogram_id, sinogram] = astra_create_sino3d_cuda(I, proj_geom, vol_geom); +astra_mex_data3d('delete', sinogram_id); + +% +% DART +% + +base.sinogram = sinogram; +base.proj_geom = proj_geom; + +D = DARTalgorithm(base); + +D.tomography = TomographyDefault3D(); +D.tomography.t0 = 100; +D.tomography.t = 10; +D.tomography.method = 'SIRT3D_CUDA'; +D.tomography.gpu_core = gpu_core; +D.tomography.use_minc = 'yes'; +% D.tomography.maxc = 0.003; % Not a sensible value, just for demonstration. + +D.segmentation.rho = rho; +D.segmentation.tau = tau; + +D.smoothing.b = 0.1; +D.smoothing.full3d = 'yes'; +D.smoothing.gpu_core = gpu_core; + +D.masking.random = 0.1; +D.masking.conn = 6; +D.masking.gpu_core = gpu_core; + +D.output.directory = outdir; +D.output.pre = [prefix '_']; +D.output.save_images = 'no'; +D.output.save_results = {'stats', 'settings', 'S', 'V'}; +D.output.save_interval = dart_iterations; +D.output.verbose = 'yes'; + +D.statistics.proj_diff = 'no'; + +D.initialize(); + +disp([D.output.directory D.output.pre]); + +D.iterate(dart_iterations); + +% Convert middle slice of final iteration to png. +load([outdir '/' prefix '_results_' num2str(dart_iterations) '.mat']); +imwritesc(D.S(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_S.png']); +imwritesc(D.V(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_V.png']); diff --git a/matlab/algorithms/DART/examples/example3.m b/matlab/algorithms/DART/examples/example3.m new file mode 100644 index 0000000..f6e360e --- /dev/null +++ b/matlab/algorithms/DART/examples/example3.m @@ -0,0 +1,79 @@ +clear all; + +addpath('..'); + +% +% Example 3: parallel beam, 2D +% + +% Configuration +proj_count = 30; +dart_iterations = 20; +filename = 'cylinders.png'; +outdir = './'; +prefix = 'example3'; +rho = [0, 1]; +tau = 0.5; +gpu_core = 0; + +% Load phantom. +I = double(imread(filename)) / 255; + +% Create projection and volume geometries. +det_count = size(I, 1); +angles = linspace(0, pi - pi / proj_count, proj_count); +proj_geom = astra_create_proj_geom('parallel', 1, det_count, angles); +vol_geom = astra_create_vol_geom(det_count, det_count); + +% Create sinogram. +[sinogram_id, sinogram] = astra_create_sino_cuda(I, proj_geom, vol_geom); +astra_mex_data2d('delete', sinogram_id); + +% +% DART +% + +base.sinogram = sinogram; +base.proj_geom = proj_geom; + +D = DARTalgorithm(base); + +%D.tomography = TomographyDefault3D(); +D.tomography.t0 = 100; +D.tomography.t = 10; +D.tomography.method = 'SIRT_CUDA'; +D.tomography.proj_type = 'strip'; +D.tomography.gpu_core = gpu_core; +D.tomography.use_minc = 'yes'; +% D.tomography.maxc = 0.003; % Not a sensible value, just for demonstration. + +D.segmentation.rho = rho; +D.segmentation.tau = tau; + +D.smoothing.b = 0.1; +D.smoothing.full3d = 'yes'; +D.smoothing.gpu_core = gpu_core; + +D.masking.random = 0.1; +D.masking.conn = 6; +D.masking.gpu_core = gpu_core; + +D.output.directory = outdir; +D.output.pre = [prefix '_']; +D.output.save_images = 'no'; +D.output.save_results = {'stats', 'settings', 'S', 'V'}; +D.output.save_interval = dart_iterations; +D.output.verbose = 'yes'; + +D.statistics.proj_diff = 'no'; + +D.initialize(); + +disp([D.output.directory D.output.pre]); + +D.iterate(dart_iterations); + +% Convert output of final iteration to png. +load([outdir '/' prefix '_results_' num2str(dart_iterations) '.mat']); +imwritesc(D.S, [outdir '/' prefix '_S.png']); +imwritesc(D.V, [outdir '/' prefix '_V.png']); diff --git a/matlab/algorithms/DART/examples/phantom3d.mat b/matlab/algorithms/DART/examples/phantom3d.mat Binary files differnew file mode 100644 index 0000000..6d70c16 --- /dev/null +++ b/matlab/algorithms/DART/examples/phantom3d.mat diff --git a/matlab/mex/astra_mex.cpp b/matlab/mex/astra_mex.cpp new file mode 100644 index 0000000..4b77f76 --- /dev/null +++ b/matlab/mex/astra_mex.cpp @@ -0,0 +1,121 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <mex.h> +#include "mexHelpFunctions.h" + +#include "astra/Globals.h" + +using namespace std; +using namespace astra; + + +//----------------------------------------------------------------------------------------- +/** astra_mex('credits'); + * + * Print Credits + */ +void astra_mex_credits(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + cout << "All Scale Tomographic Reconstruction Antwerp Toolbox (ASTRA-Toolbox) was developed at the University of Antwerp by" << endl; + cout << " * Joost Batenburg, PhD" << endl; + cout << " * Gert Merckx" << endl; + cout << " * Willem Jan Palenstijn" << endl; + cout << " * Tom Roelandts" << endl; + cout << " * Prof. Dr. Jan Sijbers" << endl; + cout << " * Wim van Aarle" << endl; + cout << " * Sander van der Maar" << endl; + cout << " * Gert Van Gompel, PhD" << endl; +} + +//----------------------------------------------------------------------------------------- +/** use_cuda = astra_mex('use_cuda'); + * + * Is CUDA enabled? + */ +void astra_mex_use_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(astra::cudaEnabled() ? 1 : 0); + } +} + +//----------------------------------------------------------------------------------------- +/** version_number = astra_mex('version'); + * + * Fetch the version number of the toolbox. + */ +void astra_mex_version(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(astra::getVersion()); + } else { + cout << "astra toolbox version " << astra::getVersionString() << endl; + } +} + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf(" Valid modes: version, use_cuda, credits\n"); +} + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex(type,...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + + // INPUT0: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == std::string("version")) { + astra_mex_version(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("use_cuda")) { + astra_mex_use_cuda(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("credits")) { + astra_mex_credits(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + + return; +} + + diff --git a/matlab/mex/astra_mex_algorithm_c.cpp b/matlab/mex/astra_mex_algorithm_c.cpp new file mode 100644 index 0000000..7476ba4 --- /dev/null +++ b/matlab/mex/astra_mex_algorithm_c.cpp @@ -0,0 +1,348 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_algorithm_c.cpp + * + * \brief Creates and manages algorithms (reconstruction,projection,...). + */ +#include <mex.h> +#include "mexHelpFunctions.h" + +#define USE_MATLAB_UNDOCUMENTED + +#ifdef USE_MATLAB_UNDOCUMENTED +extern "C" { bool utIsInterruptPending(); } + +#ifdef __linux__ +#define USE_PTHREADS_CTRLC +#include <pthread.h> +#else +#include <boost/thread.hpp> +#endif + +#endif + + + +#include "astra/Globals.h" + +#include "astra/AstraObjectManager.h" +#include "astra/AstraObjectFactory.h" + +#include "astra/XMLNode.h" +#include "astra/XMLDocument.h" + +using namespace std; +using namespace astra; +//----------------------------------------------------------------------------------------- +/** id = astra_mex_algorithm('create', cfg); + * + * Create and configure a new algorithm object. + * cfg: MATLAB struct containing the configuration parameters, see doxygen documentation for details. + * id: identifier of the algorithm object as it is now stored in the astra-library. + */ +void astra_mex_algorithm_create(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + if (!mxIsStruct(prhs[1])) { + mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n"); + } + + // turn MATLAB struct to an XML-based Config object + XMLDocument* xml = struct2XML("Algorithm", prhs[1]); + Config cfg; + cfg.self = xml->getRootNode(); + + CAlgorithm* pAlg = CAlgorithmFactory::getSingleton().create(cfg.self->getAttribute("type")); + if (!pAlg) { + delete xml; + mexErrMsgTxt("Unknown algorithm. \n"); + return; + } + + // create algorithm + if (!pAlg->initialize(cfg)) { + delete xml; + delete pAlg; + mexErrMsgTxt("Algorithm not initialized. \n"); + return; + } + + delete xml; + + // store algorithm + int iIndex = CAlgorithmManager::getSingleton().store(pAlg); + + // step4: set output + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } + +} + +#ifdef USE_MATLAB_UNDOCUMENTED + +#ifndef USE_PTHREADS_CTRLC + +// boost version +void waitForInterrupt_boost(CAlgorithm* _pAlg) +{ + boost::posix_time::milliseconds rel(2000); + + while (!utIsInterruptPending()) { + + // This is an interruption point. If the main thread calls + // interrupt(), this thread will terminate here. + boost::this_thread::sleep(rel); + } + + //mexPrintf("Aborting. Please wait.\n"); + + // One last quick check to see if the algorithm already finished + boost::this_thread::interruption_point(); + + _pAlg->signalAbort(); +} + +#else + +// pthreads version +void *waitForInterrupt_pthreads(void *threadid) +{ + CAlgorithm* _pAlg = (CAlgorithm*)threadid; + + while (!utIsInterruptPending()) { + usleep(50000); + pthread_testcancel(); + } + + //mexPrintf("Aborting. Please wait.\n"); + + // One last quick check to see if the algorithm already finished + pthread_testcancel(); + + _pAlg->signalAbort(); + + return 0; +} + +#endif +#endif + +//----------------------------------------------------------------------------------------- +/** astra_mex_algorithm('run', id); or astra_mex_algorithm('iterate', id, iterations); + * + * Run or do iterations on a certain algorithm. + * id: identifier of the algorithm object as stored in the astra-library. + * iterations: if the algorithm is iterative, this specifies the number of iterations to perform. + */ +void astra_mex_algorithm_run(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iAid = (int)(mxGetScalar(prhs[1])); + int iIterations = 0; + if (3 <= nrhs) { + iIterations = (int)(mxGetScalar(prhs[2])); + } + + // step2: get algorithm object + CAlgorithm* pAlg = CAlgorithmManager::getSingleton().get(iAid); + if (!pAlg) { + mexErrMsgTxt("Invalid algorithm ID.\n"); + return; + } + if (!pAlg->isInitialized()) { + mexErrMsgTxt("Algorithm not initialized. \n"); + return; + } + + // step3: perform actions +#ifndef USE_MATLAB_UNDOCUMENTED + + pAlg->run(iIterations); + +#elif defined(USE_PTHREADS_CTRLC) + + // Start a new thread to watch if the user pressed Ctrl-C + pthread_t thread; + pthread_create(&thread, 0, waitForInterrupt_pthreads, (void*)pAlg); + + pAlg->run(iIterations); + + // kill the watcher thread in case it's still running + pthread_cancel(thread); + pthread_join(thread, 0); + +#else + + // Start a new thread to watch if the user pressed Ctrl-C + boost::thread interruptThread(waitForInterrupt_boost, pAlg); + + pAlg->run(iIterations); + + // kill the watcher thread in case it's still running + interruptThread.interrupt(); + interruptThread.join(); + +#endif +} +//----------------------------------------------------------------------------------------- +/** astra_mex_algorithm('get_res_norm', id); + * + * Get the L2-norm of the residual sinogram. Not all algorithms + * support this operation. + */ +void astra_mex_algorithm_get_res_norm(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iAid = (int)(mxGetScalar(prhs[1])); + + // step2: get algorithm object + CAlgorithm* pAlg = CAlgorithmManager::getSingleton().get(iAid); + if (!pAlg) { + mexErrMsgTxt("Invalid algorithm ID.\n"); + return; + } + if (!pAlg->isInitialized()) { + mexErrMsgTxt("Algorithm not initialized. \n"); + return; + } + + CReconstructionAlgorithm2D* pAlg2D = dynamic_cast<CReconstructionAlgorithm2D*>(pAlg); + CReconstructionAlgorithm3D* pAlg3D = dynamic_cast<CReconstructionAlgorithm3D*>(pAlg); + + float res = 0.0f; + bool ok; + if (pAlg2D) + ok = pAlg2D->getResidualNorm(res); + else if (pAlg3D) + ok = pAlg3D->getResidualNorm(res); + else + ok = false; + + if (!ok) { + mexErrMsgTxt("Operation not supported.\n"); + return; + } + + plhs[0] = mxCreateDoubleScalar(res); +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_algorithm('delete', id1, id2, ...); + * + * Delete one or more algorithm objects currently stored in the astra-library. + * id1, id2, ... : identifiers of the algorithm objects as stored in the astra-library. + */ +void astra_mex_algorithm_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get algorithm ID + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + for (int i = 1; i < nrhs; i++) { + int iAid = (int)(mxGetScalar(prhs[i])); + CAlgorithmManager::getSingleton().remove(iAid); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_algorithm('clear'); + * + * Delete all algorithm objects currently stored in the astra-library. + */ +void astra_mex_algorithm_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + CAlgorithmManager::getSingleton().clear(); +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_algorithm('info'); + * + * Print information about all the algorithm objects currently stored in the astra-library. + */ +void astra_mex_algorithm_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + mexPrintf("%s", astra::CAlgorithmManager::getSingleton().info().c_str()); +} + +//----------------------------------------------------------------------------------------- +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf("Valid modes: create, info, delete, clear, run/iterate, get_res_norm\n"); +} + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex_algorithm(mode, ...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + // INPUT: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == "create") { + astra_mex_algorithm_create(nlhs, plhs, nrhs, prhs); + } else if (sMode == "info") { + astra_mex_algorithm_info(nlhs, plhs, nrhs, prhs); + } else if (sMode == "delete") { + astra_mex_algorithm_delete(nlhs, plhs, nrhs, prhs); + } else if (sMode == "clear") { + astra_mex_algorithm_clear(nlhs, plhs, nrhs, prhs); + } else if (sMode == "run" || sMode == "iterate") { + astra_mex_algorithm_run(nlhs, plhs, nrhs, prhs); + } else if (sMode == "get_res_norm") { + astra_mex_algorithm_get_res_norm(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + return; +} diff --git a/matlab/mex/astra_mex_algorithm_vc08.vcproj b/matlab/mex/astra_mex_algorithm_vc08.vcproj new file mode 100644 index 0000000..baa4c44 --- /dev/null +++ b/matlab/mex/astra_mex_algorithm_vc08.vcproj @@ -0,0 +1,593 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex_algorithm" + ProjectGUID="{056BF7A9-294D-487C-8CC3-BE629077CA94}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="false" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + BrowseInformation="1" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_algorithm_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/astra_mex_c.cpp b/matlab/mex/astra_mex_c.cpp new file mode 100644 index 0000000..0068664 --- /dev/null +++ b/matlab/mex/astra_mex_c.cpp @@ -0,0 +1,127 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_c.cpp + * + * \brief Contains some basic "about" functions. + */ + +#include <mex.h> +#include "mexHelpFunctions.h" + +#include "astra/Globals.h" + +using namespace std; +using namespace astra; + + +//----------------------------------------------------------------------------------------- +/** astra_mex('credits'); + * + * Print Credits + */ +void astra_mex_credits(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + mexPrintf("All Scale Tomographic Reconstruction Antwerp Toolbox (ASTRA-Toolbox) was developed at the University of Antwerp by\n"); + mexPrintf(" * Prof. dr. Joost Batenburg\n"); + mexPrintf(" * Andrei Dabravolski\n"); + mexPrintf(" * Gert Merckx\n"); + mexPrintf(" * Willem Jan Palenstijn\n"); + mexPrintf(" * Tom Roelandts\n"); + mexPrintf(" * Prof. dr. Jan Sijbers\n"); + mexPrintf(" * dr. Wim van Aarle\n"); + mexPrintf(" * Sander van der Maar\n"); + mexPrintf(" * dr. Gert Van Gompel\n"); +} + +//----------------------------------------------------------------------------------------- +/** use_cuda = astra_mex('use_cuda'); + * + * Is CUDA enabled? + */ +void astra_mex_use_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(astra::cudaEnabled() ? 1 : 0); + } +} + +//----------------------------------------------------------------------------------------- +/** version_number = astra_mex('version'); + * + * Fetch the version number of the toolbox. + */ +void astra_mex_version(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(astra::getVersion()); + } else { + mexPrintf("astra toolbox version %s\n", astra::getVersionString()); + } +} + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf(" Valid modes: version, use_cuda, credits\n"); +} + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex(type,...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + + // INPUT0: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == std::string("version")) { + astra_mex_version(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("use_cuda")) { + astra_mex_use_cuda(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("credits")) { + astra_mex_credits(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + + return; +} + + diff --git a/matlab/mex/astra_mex_data2d_c.cpp b/matlab/mex/astra_mex_data2d_c.cpp new file mode 100644 index 0000000..99fb38e --- /dev/null +++ b/matlab/mex/astra_mex_data2d_c.cpp @@ -0,0 +1,667 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_data2d_c.cpp + * + * \brief Creates, manages and manipulates 2D volume and projection data objects. + */ +#include <mex.h> +#include "mexHelpFunctions.h" + +#include <list> + +#include "astra/Globals.h" + +#include "astra/AstraObjectManager.h" + +#include "astra/Float32ProjectionData2D.h" +#include "astra/Float32VolumeData2D.h" +#include "astra/SparseMatrixProjectionGeometry2D.h" +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" + +using namespace std; +using namespace astra; + +//----------------------------------------------------------------------------------------- +/** astra_mex_data2d('delete', id1, id2, ...); + * + * Delete one or more data objects currently stored in the astra-library. + * id1, id2, ... : identifiers of the 2d data objects as stored in the astra-library. + */ +void astra_mex_data2d_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + // step2: delete all specified data objects + for (int i = 1; i < nrhs; i++) { + int iDataID = (int)(mxGetScalar(prhs[i])); + CData2DManager::getSingleton().remove(iDataID); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_data2d('clear'); + * + * Delete all data objects currently stored in the astra-library. + */ +void astra_mex_data2d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + CData2DManager::getSingleton().clear(); +} + +//----------------------------------------------------------------------------------------- +/** id = astra_mex_data2d('create', datatype, geometry, data); + * + * Create a new data 2d object in the astra-library. + * type: '-vol' for volume data, '-sino' for projection data + * geom: MATLAB struct with the geometry for the data + * data: Optional. Can be either a MATLAB matrix containing the data. In that case the dimensions + * should match that of the geometry of the object. It can also be a single value, in which case + * the entire data will be set to that value. If this isn't specified all values are set to 0. + * id: identifier of the 2d data object as it is now stored in the astra-library. + */ +void astra_mex_data2d_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[]) +{ + // step1: get datatype + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + string sDataType = mex_util_get_string(prhs[1]); + CFloat32Data2D* pDataObject2D = NULL; + + if (nrhs >= 4 && !(mex_is_scalar(prhs[3])|| mxIsDouble(prhs[3]) || mxIsLogical(prhs[3]) || mxIsSingle(prhs[3]) )) { + mexErrMsgTxt("Data must be single, double or logical."); + return; + } + + // SWITCH DataType + if (sDataType == "-vol") { + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + XMLDocument* xml = struct2XML(string("VolumeGeometry"), prhs[2]); + if (!xml) + return; + Config cfg; + cfg.self = xml->getRootNode(); + CVolumeGeometry2D* pGeometry = new CVolumeGeometry2D(); + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete xml; + delete pGeometry; + return; + } + // If data is specified, check dimensions + if (nrhs >= 4 && !mex_is_scalar(prhs[3])) { + if (pGeometry->getGridColCount() != mxGetN(prhs[3]) || pGeometry->getGridRowCount() != mxGetM(prhs[3])) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete xml; + delete pGeometry; + return; + } + } + // Initialize data object + pDataObject2D = new CFloat32VolumeData2D(pGeometry); + delete pGeometry; + delete xml; + } + else if (sDataType == "-sino") { + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]); + if (!xml) + return; + Config cfg; + cfg.self = xml->getRootNode(); + // FIXME: Change how the base class is created. (This is duplicated + // in 'change_geometry' and Projector2D.cpp.) + std::string type = cfg.self->getAttribute("type"); + CProjectionGeometry2D* pGeometry; + if (type == "sparse_matrix") { + pGeometry = new CSparseMatrixProjectionGeometry2D(); + } else if (type == "fanflat") { + //CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D(); + //pFanFlatProjectionGeometry->initialize(Config(node)); + //m_pProjectionGeometry = pFanFlatProjectionGeometry; + pGeometry = new CFanFlatProjectionGeometry2D(); + } else if (type == "fanflat_vec") { + pGeometry = new CFanFlatVecProjectionGeometry2D(); + } else { + pGeometry = new CParallelProjectionGeometry2D(); + } + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete pGeometry; + delete xml; + return; + } + // If data is specified, check dimensions + if (nrhs >= 4 && !mex_is_scalar(prhs[3])) { + if (pGeometry->getDetectorCount() != mxGetN(prhs[3]) || pGeometry->getProjectionAngleCount() != mxGetM(prhs[3])) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete pGeometry; + delete xml; + return; + } + } + // Initialize data object + pDataObject2D = new CFloat32ProjectionData2D(pGeometry); + delete pGeometry; + delete xml; + } + else { + mexErrMsgTxt("Invalid datatype. Please specify '-vol' or '-sino'. \n"); + return; + } + + // Check initialization + if (!pDataObject2D->isInitialized()) { + mexErrMsgTxt("Couldn't initialize data object.\n"); + delete pDataObject2D; + return; + } + + // Store data + if (nrhs == 3) { + for (int i = 0; i < pDataObject2D->getSize(); ++i) { + pDataObject2D->getData()[i] = 0.0f; + } + } + + // Store data + if (nrhs >= 4) { + // fill with scalar value + if (mex_is_scalar(prhs[3])) { + float32 fValue = (float32)mxGetScalar(prhs[3]); + for (int i = 0; i < pDataObject2D->getSize(); ++i) { + pDataObject2D->getData()[i] = fValue; + } + } + // fill with array value + else { + const mwSize* dims = mxGetDimensions(prhs[3]); + // Check Data dimensions + if (pDataObject2D->getWidth() != mxGetN(prhs[3]) || pDataObject2D->getHeight() != mxGetM(prhs[3])) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + return; + } + + // logical data + if (mxIsLogical(prhs[3])) { + bool* pbMatlabData = mxGetLogicals(prhs[3]); + int i = 0; + int col, row; + for (col = 0; col < dims[1]; ++col) { + for (row = 0; row < dims[0]; ++row) { + pDataObject2D->getData2D()[row][col] = (float32)pbMatlabData[i]; + ++i; + } + } + // double data + } else if (mxIsDouble(prhs[3])) { + double* pdMatlabData = mxGetPr(prhs[3]); + int i = 0; + int col, row; + for (col = 0; col < dims[1]; ++col) { + for (row = 0; row < dims[0]; ++row) { + pDataObject2D->getData2D()[row][col] = pdMatlabData[i]; + ++i; + } + } + // single data + } else if (mxIsSingle(prhs[3])) { + const float* pfMatlabData = (const float *)mxGetData(prhs[3]); + int i = 0; + int col, row; + for (col = 0; col < dims[1]; ++col) { + for (row = 0; row < dims[0]; ++row) { + pDataObject2D->getData2D()[row][col] = pfMatlabData[i]; + ++i; + } + } + } else { + ASTRA_ASSERT(false); + } + } + } + + // step4: store data object + int iIndex = CData2DManager::getSingleton().store(pDataObject2D); + + // step5: return data id + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } + +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_data2d('store', id, data); + * + * Store data in an existing astra 2d dataobject with a MATLAB matrix or with a scalar value. + * id: identifier of the 2d data object as stored in the astra-library. + * data: can be either a MATLAB matrix containing the data. In that case the dimensions should match that of the geometry of the object. It can also be a single value, in which case the entire data will be set to that value. + */ +void astra_mex_data2d_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + if (!(mex_is_scalar(prhs[2]) || mxIsDouble(prhs[2]) || mxIsLogical(prhs[2]) || mxIsSingle(prhs[2]))) { + mexErrMsgTxt("Data must be single, double or logical."); + return; + } + + // step2: get data object + CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // step3: insert data + // fill with scalar value + if (mex_is_scalar(prhs[2])) { + float32 fValue = (float32)mxGetScalar(prhs[2]); + for (int i = 0; i < pDataObject->getSize(); ++i) { + pDataObject->getData()[i] = fValue; + } + } else { + // Check Data dimensions + if (pDataObject->getWidth() != mxGetN(prhs[2]) || pDataObject->getHeight() != mxGetM(prhs[2])) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + return; + } + const mwSize* dims = mxGetDimensions(prhs[2]); + + // logical data + if (mxIsLogical(prhs[2])) { + bool* pbMatlabData = mxGetLogicals(prhs[2]); + int i = 0; + int col, row; + for (col = 0; col < dims[1]; ++col) { + for (row = 0; row < dims[0]; ++row) { + pDataObject->getData2D()[row][col] = (float32)pbMatlabData[i]; + ++i; + } + } + // double data + } else if (mxIsDouble(prhs[2])) { + double* pdMatlabData = mxGetPr(prhs[2]); + int i = 0; + int col, row; + for (col = 0; col < dims[1]; ++col) { + for (row = 0; row < dims[0]; ++row) { + pDataObject->getData2D()[row][col] = pdMatlabData[i]; + ++i; + } + } + // single data + } else if (mxIsSingle(prhs[2])) { + const float* pfMatlabData = (const float *)mxGetData(prhs[2]); + int i = 0; + int col, row; + for (col = 0; col < dims[1]; ++col) { + for (row = 0; row < dims[0]; ++row) { + pDataObject->getData2D()[row][col] = pfMatlabData[i]; + ++i; + } + } + } else { + ASTRA_ASSERT(false); + } + } +} + +//----------------------------------------------------------------------------------------- +/** geom = astra_mex_data2d('get_geometry', id); + * + * Fetch the geometry of a 2d data object stored in the astra-library. + * id: identifier of the 2d data object as stored in the astra-library. + * geom: MATLAB-struct containing information about the used geometry. + */ +void astra_mex_data2d_get_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + if (1 <= nlhs) { + if (pDataObject->getType() == CFloat32Data2D::PROJECTION) { + CFloat32ProjectionData2D* pDataObject2 = dynamic_cast<CFloat32ProjectionData2D*>(pDataObject); + plhs[0] = createProjectionGeometryStruct(pDataObject2->getGeometry()); + } + else if (pDataObject->getType() == CFloat32Data2D::VOLUME) { + CFloat32VolumeData2D* pDataObject2 = dynamic_cast<CFloat32VolumeData2D*>(pDataObject); + plhs[0] = createVolumeGeometryStruct(pDataObject2->getGeometry()); + } + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_data2d('change_geometry', id, geom); + * + * Change the associated geometry of a 2d data object (volume or sinogram) + * id: identifier of the 2d data object as stored in the astra-library. + * geom: the new geometry struct, as created by astra_create_vol/proj_geom + */ +void astra_mex_data2d_change_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: check input + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + + // step2: get data object + int iDataID = (int)(mxGetScalar(prhs[1])); + CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + CFloat32ProjectionData2D* pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(pDataObject); + + if (pSinogram) { + // Projection data + + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]); + Config cfg; + cfg.self = xml->getRootNode(); + // FIXME: Change how the base class is created. (This is duplicated + // in 'create' and Projector2D.cpp.) + std::string type = cfg.self->getAttribute("type"); + CProjectionGeometry2D* pGeometry; + if (type == "sparse_matrix") { + pGeometry = new CSparseMatrixProjectionGeometry2D(); + } else if (type == "fanflat") { + //CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D(); + //pFanFlatProjectionGeometry->initialize(Config(node)); + //m_pProjectionGeometry = pFanFlatProjectionGeometry; + pGeometry = new CFanFlatProjectionGeometry2D(); + } else if (type == "fanflat_vec") { + pGeometry = new CFanFlatVecProjectionGeometry2D(); + } else { + pGeometry = new CParallelProjectionGeometry2D(); + } + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete pGeometry; + delete xml; + return; + } + // If data is specified, check dimensions + if (pGeometry->getDetectorCount() != pSinogram->getDetectorCount() || pGeometry->getProjectionAngleCount() != pSinogram->getAngleCount()) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete pGeometry; + delete xml; + return; + } + + // If ok, change geometry + pSinogram->changeGeometry(pGeometry); + delete pGeometry; + delete xml; + + return; + } + + CFloat32VolumeData2D* pVolume = dynamic_cast<CFloat32VolumeData2D*>(pDataObject); + + if (pVolume) { + // Volume data + + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + XMLDocument* xml = struct2XML(string("VolumeGeometry"), prhs[2]); + Config cfg; + cfg.self = xml->getRootNode(); + CVolumeGeometry2D* pGeometry = new CVolumeGeometry2D(); + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete xml; + delete pGeometry; + return; + } + // If data is specified, check dimensions + if (pGeometry->getGridColCount() != pVolume->getWidth() || pGeometry->getGridRowCount() != pVolume->getHeight()) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete xml; + delete pGeometry; + return; + } + + // If ok, change geometry + pVolume->changeGeometry(pGeometry); + delete xml; + delete pGeometry; + + } + + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; +} + +//----------------------------------------------------------------------------------------- +/** data = astra_mex_data2d('get', id); + * + * Fetch data from the astra-library to a MATLAB matrix. + * id: identifier of the 2d data object as stored in the astra-library. + * data: MATLAB data + */ +void astra_mex_data2d_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: check input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + + // step2: get data object + int iDataID = (int)(mxGetScalar(prhs[1])); + CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleMatrix(pDataObject->getHeight(), // # rows + pDataObject->getWidth(), // # cols + mxREAL); // datatype 64-bits + double* out = mxGetPr(plhs[0]); + int i = 0; + int row, col; + for (col = 0; col < pDataObject->getWidth(); ++col) { + for (row = 0; row < pDataObject->getHeight(); ++row) { + out[i] = pDataObject->getData2D()[row][col]; + ++i; + } + } + } + +} + +//----------------------------------------------------------------------------------------- +/** data = astra_mex_data2d('get_single', id); + * + * Fetch data from the astra-library to a MATLAB matrix. + * id: identifier of the 2d data object as stored in the astra-library. + * data: MATLAB data + */ +void astra_mex_data2d_get_single(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: check input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + + // step2: get data object + int iDataID = (int)(mxGetScalar(prhs[1])); + CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + if (1 <= nlhs) { + mwSize dims[2]; + dims[0] = pDataObject->getHeight(); + dims[1] = pDataObject->getWidth(); + plhs[0] = mxCreateNumericArray(2, dims, mxSINGLE_CLASS, mxREAL); + float* out = (float *)mxGetData(plhs[0]); + int i = 0; + int row, col; + for (col = 0; col < pDataObject->getWidth(); ++col) { + for (row = 0; row < pDataObject->getHeight(); ++row) { + out[i] = pDataObject->getData2D()[row][col]; + ++i; + } + } + } + +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_data2d('info'); + * + * Print information about all the 2d data objects currently stored in the astra-library. + */ +void astra_mex_data2d_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + mexPrintf("%s", astra::CData2DManager::getSingleton().info().c_str()); +} + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf("Valid modes: get, get_single, delete, clear, set/store, create, get_geometry, change_geometry, info\n"); +} + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex_data2d(type,...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + + // INPUT0: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == std::string("get")) { + astra_mex_data2d_get(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("get_single")) { + astra_mex_data2d_get_single(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("delete")) { + astra_mex_data2d_delete(nlhs, plhs, nrhs, prhs); + } else if (sMode == "clear") { + astra_mex_data2d_clear(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("store") || + sMode == std::string("set")) { + astra_mex_data2d_store(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("create")) { + astra_mex_data2d_create(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("get_geometry")) { + astra_mex_data2d_get_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("change_geometry")) { + astra_mex_data2d_change_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("info")) { + astra_mex_data2d_info(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + + return; +} + + diff --git a/matlab/mex/astra_mex_data2d_vc08.vcproj b/matlab/mex/astra_mex_data2d_vc08.vcproj new file mode 100644 index 0000000..8f1fc13 --- /dev/null +++ b/matlab/mex/astra_mex_data2d_vc08.vcproj @@ -0,0 +1,591 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex_data2d" + ProjectGUID="{E4092269-B19C-46F7-A84E-4F146CC70E44}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + BrowseInformation="1" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_data2d_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/astra_mex_data3d_c.cpp b/matlab/mex/astra_mex_data3d_c.cpp new file mode 100644 index 0000000..1af8844 --- /dev/null +++ b/matlab/mex/astra_mex_data3d_c.cpp @@ -0,0 +1,1036 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_data3d_c.cpp + * + * \brief Creates, manages and manipulates 3D volume and projection data objects. + */ +#include <mex.h> +#include "mexHelpFunctions.h" + +#include <list> + +#include "astra/Globals.h" + +#include "astra/AstraObjectManager.h" + +#include "astra/Float32ProjectionData2D.h" +#include "astra/Float32VolumeData2D.h" +#include "astra/Float32ProjectionData3D.h" +#include "astra/Float32ProjectionData3DMemory.h" +#include "astra/Float32VolumeData3D.h" +#include "astra/Float32VolumeData3DMemory.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +using namespace std; +using namespace astra; + + + +//----------------------------------------------------------------------------------------- +/** + * id = astra_mex_io_data('create', datatype, geometry, data); + * datatype: ['-vol','-sino','-sinocone'] + */ +void astra_mex_data3d_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[]) +{ + // step1: get datatype + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + string sDataType = mex_util_get_string(prhs[1]); + CFloat32Data3DMemory* pDataObject3D = NULL; + + if (nrhs >= 4 && !(mex_is_scalar(prhs[3]) || mxIsDouble(prhs[3]) || mxIsSingle(prhs[3]))) { + mexErrMsgTxt("Data must be single or double."); + return; + } + + mwSize dims[3]; + + // SWITCH DataType + if (sDataType == "-vol") { + + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + Config cfg; + XMLDocument* xml = struct2XML("VolumeGeometry", prhs[2]); + if (!xml) + return; + cfg.self = xml->getRootNode(); + CVolumeGeometry3D* pGeometry = new CVolumeGeometry3D(); + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete pGeometry; + delete xml; + return; + } + delete xml; + + // If data is specified, check dimensions + if (nrhs >= 4 && !mex_is_scalar(prhs[3])) { + get3DMatrixDims(prhs[3], dims); + if (pGeometry->getGridColCount() != dims[0] || pGeometry->getGridRowCount() != dims[1] || pGeometry->getGridSliceCount() != dims[2]) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete pGeometry; + return; + } + } + + // Initialize data object + pDataObject3D = new CFloat32VolumeData3DMemory(pGeometry); + delete pGeometry; + } + + else if (sDataType == "-sino" || sDataType == "-proj3d") { + + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]); + if (!xml) + return; + Config cfg; + cfg.self = xml->getRootNode(); + + // FIXME: Change how the base class is created. (This is duplicated + // in Projector2D.cpp.) + std::string type = cfg.self->getAttribute("type"); + CProjectionGeometry3D* pGeometry = 0; + if (type == "parallel3d") { + pGeometry = new CParallelProjectionGeometry3D(); + } else if (type == "parallel3d_vec") { + pGeometry = new CParallelVecProjectionGeometry3D(); + } else if (type == "cone") { + pGeometry = new CConeProjectionGeometry3D(); + } else if (type == "cone_vec") { + pGeometry = new CConeVecProjectionGeometry3D(); + } else { + mexErrMsgTxt("Invalid geometry type.\n"); + return; + } + + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete pGeometry; + delete xml; + return; + } + delete xml; + + // If data is specified, check dimensions + if (nrhs >= 4 && !mex_is_scalar(prhs[3])) { + get3DMatrixDims(prhs[3], dims); + if (pGeometry->getDetectorColCount() != dims[0] || pGeometry->getProjectionCount() != dims[1] || pGeometry->getDetectorRowCount() != dims[2]) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete pGeometry; + return; + } + } + + // Initialize data object + pDataObject3D = new CFloat32ProjectionData3DMemory(pGeometry); + } + + else if (sDataType == "-sinocone") { + // Read geometry + if (!mxIsStruct(prhs[2])) { + mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n"); + } + XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]); + if (!xml) + return; + Config cfg; + cfg.self = xml->getRootNode(); + CConeProjectionGeometry3D* pGeometry = new CConeProjectionGeometry3D(); + if (!pGeometry->initialize(cfg)) { + mexErrMsgTxt("Geometry class not initialized. \n"); + delete xml; + delete pGeometry; + return; + } + delete xml; + // If data is specified, check dimensions + if (nrhs >= 4 && !mex_is_scalar(prhs[3])) { + get3DMatrixDims(prhs[3], dims); + if (pGeometry->getDetectorRowCount() != dims[2] || pGeometry->getProjectionCount() != dims[1] || pGeometry->getDetectorColCount() != dims[0]) { + mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n"); + delete pGeometry; + return; + } + } + // Initialize data object + pDataObject3D = new CFloat32ProjectionData3DMemory(pGeometry); + delete pGeometry; + } + else { + mexErrMsgTxt("Invalid datatype. Please specify '-vol' or '-proj3d'. \n"); + return; + } + + // Check initialization + if (!pDataObject3D->isInitialized()) { + mexErrMsgTxt("Couldn't initialize data object.\n"); + delete pDataObject3D; + return; + } + + // Store data + + // fill with scalar value + if (nrhs < 4 || mex_is_scalar(prhs[3])) { + float32 fValue = 0.0f; + if (nrhs >= 4) + fValue = (float32)mxGetScalar(prhs[3]); + for (int i = 0; i < pDataObject3D->getSize(); ++i) { + pDataObject3D->getData()[i] = fValue; + } + } + // fill with array value + else if (mxIsDouble(prhs[3])) { + double* pdMatlabData = mxGetPr(prhs[3]); + int i = 0; + int col, row, slice; + for (slice = 0; slice < dims[2]; ++slice) { + for (row = 0; row < dims[1]; ++row) { + for (col = 0; col < dims[0]; ++col) { + // TODO: Benchmark and remove triple indexing? + pDataObject3D->getData3D()[slice][row][col] = pdMatlabData[i]; + ++i; + } + } + } + } + else if (mxIsSingle(prhs[3])) { + const float* pfMatlabData = (const float*)mxGetData(prhs[3]); + int i = 0; + int col, row, slice; + for (slice = 0; slice < dims[2]; ++slice) { + for (row = 0; row < dims[1]; ++row) { + for (col = 0; col < dims[0]; ++col) { + // TODO: Benchmark and remove triple indexing? + pDataObject3D->getData3D()[slice][row][col] = pfMatlabData[i]; + ++i; + } + } + } + } + pDataObject3D->updateStatistics(); + + // step4: store data object + int iIndex = CData3DManager::getSingleton().store(pDataObject3D); + + // step5: return data id + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } + +} + +//----------------------------------------------------------------------------------------- +/** + * [id] = astra_mex_io_data('create_cache', config); + */ +void astra_mex_data3d_create_cache(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ +// if (nrhs < 2) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// +// if (!mxIsStruct(prhs[1])) { +// mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n"); +// } +// +// // turn MATLAB struct to an XML-based Config object +// XMLDocument* xml = struct2XML("Data3D", prhs[1]); +// Config cfg; +// cfg.self = xml->getRootNode(); +// +// // create dataobject +// string sType = cfg.self->getAttribute("type"); +// int iIndex; +// if (sType == "ProjectionCached") { +// CFloat32ProjectionData3DCached* pData = new CFloat32ProjectionData3DCached(cfg); +// iIndex = CData3DManager::getSingleton().store(pData); +// } +//// else if (sType == "VolumeCached") { +//// CFloat32VolumeData3DCached* pData = new CFloat32VolumeData3DCached(cfg); +//// pData->initialize(cfg); +//// iIndex = CData3DManager::getSingleton().store(pData); +//// } +// +// // step4: set output +// if (1 <= nlhs) { +// plhs[0] = mxCreateDoubleScalar(iIndex); +// } + +} + + +//----------------------------------------------------------------------------------------- +/** + * data = astra_mex_data3d('get', id); + * + * Fetch data from the astra-library to a MATLAB matrix. + * id: identifier of the 3d data object as stored in the astra-library. + * data: MATLAB data + + */ +void astra_mex_data3d_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CFloat32Data3DMemory* pDataObject = dynamic_cast<CFloat32Data3DMemory*>(astra::CData3DManager::getSingleton().get(iDataID)); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + if (1 <= nlhs) { + mwSize dims[3]; + dims[0] = pDataObject->getWidth(); + dims[1] = pDataObject->getHeight(); + dims[2] = pDataObject->getDepth(); + + plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL); + double* out = mxGetPr(plhs[0]); + + int i = 0; + for (int slice = 0; slice < pDataObject->getDepth(); slice++) { + for (int row = 0; row < pDataObject->getHeight(); row++) { + for (int col = 0; col < pDataObject->getWidth(); col++) { + // TODO: Benchmark and remove triple indexing? + out[i] = pDataObject->getData3D()[slice][row][col]; + ++i; + } + } + } + } + +} + +//----------------------------------------------------------------------------------------- +/** + * data = astra_mex_data3d('get_single', id); + * + * Fetch data from the astra-library to a MATLAB matrix. + * id: identifier of the 3d data object as stored in the astra-library. + * data: MATLAB data + + */ +void astra_mex_data3d_get_single(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CFloat32Data3DMemory* pDataObject = dynamic_cast<CFloat32Data3DMemory*>(astra::CData3DManager::getSingleton().get(iDataID)); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + if (1 <= nlhs) { + mwSize dims[3]; + dims[0] = pDataObject->getWidth(); + dims[1] = pDataObject->getHeight(); + dims[2] = pDataObject->getDepth(); + + plhs[0] = mxCreateNumericArray(3, dims, mxSINGLE_CLASS, mxREAL); + float* out = (float *)mxGetData(plhs[0]); + + int i = 0; + for (int slice = 0; slice < pDataObject->getDepth(); slice++) { + for (int row = 0; row < pDataObject->getHeight(); row++) { + for (int col = 0; col < pDataObject->getWidth(); col++) { + // TODO: Benchmark and remove triple indexing? + out[i] = pDataObject->getData3D()[slice][row][col]; + ++i; + } + } + } + } + +} + + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_data3d('store', id, data); + * + * Store MATLAB matrix data in the astra-library. + * id: identifier of the 3d data object as stored in the astra-library. + * data: MATLAB data + + */ +void astra_mex_data3d_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CFloat32Data3DMemory* pDataObject = dynamic_cast<CFloat32Data3DMemory*>(astra::CData3DManager::getSingleton().get(iDataID)); + if (!pDataObject || !pDataObject->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + if (!(mex_is_scalar(prhs[2]) || mxIsDouble(prhs[2]) || mxIsSingle(prhs[2]))) { + mexErrMsgTxt("Data must be single or double."); + return; + } + + // fill with scalar value + if (mex_is_scalar(prhs[2])) { + float32 fValue = (float32)mxGetScalar(prhs[2]); + for (int i = 0; i < pDataObject->getSize(); ++i) { + pDataObject->getData()[i] = fValue; + } + } + // fill with array value + else if (mxIsDouble(prhs[2])) { + mwSize dims[3]; + get3DMatrixDims(prhs[2], dims); + if (dims[0] != pDataObject->getWidth() || dims[1] != pDataObject->getHeight() || dims[2] != pDataObject->getDepth()) { + mexErrMsgTxt("Data object dimensions don't match.\n"); + return; + + } + double* pdMatlabData = mxGetPr(prhs[2]); + int i = 0; + int col, row, slice; + for (slice = 0; slice < dims[2]; ++slice) { + for (row = 0; row < dims[1]; ++row) { + for (col = 0; col < dims[0]; ++col) { + // TODO: Benchmark and remove triple indexing? + pDataObject->getData3D()[slice][row][col] = pdMatlabData[i]; + ++i; + } + } + } + } + else if (mxIsSingle(prhs[2])) { + mwSize dims[3]; + get3DMatrixDims(prhs[2], dims); + if (dims[0] != pDataObject->getWidth() || dims[1] != pDataObject->getHeight() || dims[2] != pDataObject->getDepth()) { + mexErrMsgTxt("Data object dimensions don't match.\n"); + return; + + } + const float* pfMatlabData = (const float *)mxGetData(prhs[2]); + int i = 0; + int col, row, slice; + for (slice = 0; slice < dims[2]; ++slice) { + for (row = 0; row < dims[1]; ++row) { + for (col = 0; col < dims[0]; ++col) { + // TODO: Benchmark and remove triple indexing? + pDataObject->getData3D()[slice][row][col] = pfMatlabData[i]; + ++i; + } + } + } + } + pDataObject->updateStatistics(); +} + + +//----------------------------------------------------------------------------------------- +/** + * [id] = astra_mex_io_data('fetch_slice', id, slicenr); + */ +void astra_mex_data3d_fetch_slice_z(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ +// // step1: get input +// if (nrhs < 3) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// int iDid = (int)(mxGetScalar(prhs[1])); +// int iSliceNr = (int)(mxGetScalar(prhs[2])); +// +// // Get data object +// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); +// if (!pData) { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +// +// CFloat32Data2D* res = NULL; +// // Projection Data +// if (pData->getType() == CFloat32Data3D::PROJECTION) { +// CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData); +//// res = pData2->fetchSlice(iSliceNr); +// } +// // Volume Data +// else if (pData->getType() == CFloat32Data3D::VOLUME) { +// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); +//// res = pData2->fetchSliceZ(iSliceNr); +// } +// // Error +// else { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +// +// // store data +// int iIndex = CData2DManager::getSingleton().store(res); +// +// // step4: set output +// if (1 <= nlhs) { +// plhs[0] = mxCreateDoubleScalar(iIndex); +// } +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_io_data('returnSlice', id, slicenr); + */ +void astra_mex_data3d_return_slice_z(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ +// // step1: get input +// if (nrhs < 3) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// int iDid = (int)(mxGetScalar(prhs[1])); +// int iSliceNr = (int)(mxGetScalar(prhs[2])); +// +// // Get data object +// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); +// if (!pData) { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +// +// // Projection Data +// if (pData->getType() == CFloat32Data3D::PROJECTION) { +// CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData); +//// TODO: think about returning slices +//// pData2->returnSlice(iSliceNr); +// } +// // Volume Data +// else if (pData->getType() == CFloat32Data3D::VOLUME) { +// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); +//// TODO: think about returning slices +//// pData2->returnSliceZ(iSliceNr); +// } +// // Error +// else { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +} + +//----------------------------------------------------------------------------------------- +/** + * [id] = astra_mex_io_data('fetch_projection', id, slicenr); + */ +void astra_mex_data3d_fetch_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// step1: get input + //if (nrhs < 3) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iDid = (int)(mxGetScalar(prhs[1])); + //int iProjectionNr = (int)(mxGetScalar(prhs[2])); + + //// Get data object + //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); + //if (!pData) { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + + //CFloat32Data2D* res = NULL; + //// Projection Data + //if (pData->getType() == CFloat32Data3D::PROJECTION) { + // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData); + // res = pData2->fetchProjection(iProjectionNr); + //} + //// Error + //else { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + // + //// store data + //int iIndex = CData2DManager::getSingleton().store(res); + + //// step4: set output + //if (1 <= nlhs) { + // plhs[0] = mxCreateDoubleScalar(iIndex); + //} +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_io_data('return_projection', id, slicenr); + */ +void astra_mex_data3d_return_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// step1: get input + //if (nrhs < 3) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iDid = (int)(mxGetScalar(prhs[1])); + //int iProjectionNr = (int)(mxGetScalar(prhs[2])); + + //// Get data object + //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); + //if (!pData) { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + + //// Projection Data + //if (pData->getType() == CFloat32Data3D::PROJECTION) { + // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData); + //// pData2->returnProjection(iProjectionNr); + //} + //// Error + //else { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} +} + +//----------------------------------------------------------------------------------------- +/** + * [id] = astra_mex_io_data('fetch_projection', id, slicenr); + */ +void astra_mex_data3d_fetch_slice_x(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// step1: get input + //if (nrhs < 3) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iDid = (int)(mxGetScalar(prhs[1])); + //int iSliceNr = (int)(mxGetScalar(prhs[2])); + + //// Get data object + //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); + //if (!pData) { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + + //CFloat32Data2D* res = NULL; + //// Projection Data + //if (pData->getType() == CFloat32Data3D::VOLUME) { + // CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); + // res = pData2->fetchSliceX(iSliceNr); + //} + //// Error + //else { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + // + //// store data + //int iIndex = CData2DManager::getSingleton().store(res); + + //// step4: set output + //if (1 <= nlhs) { + // plhs[0] = mxCreateDoubleScalar(iIndex); + //} +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_io_data('return_slice_x', id, slicenr); + */ +void astra_mex_data3d_return_slice_x(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ +// // step1: get input +// if (nrhs < 3) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// int iDid = (int)(mxGetScalar(prhs[1])); +// int iSliceNr = (int)(mxGetScalar(prhs[2])); +// +// // Get data object +// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); +// if (!pData) { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +// +// // Projection Data +// if (pData->getType() == CFloat32Data3D::VOLUME) { +// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); +//// TODO: think about returning slices +//// pData2->returnSliceX(iSliceNr); +// } +// // Error +// else { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +} + + +//----------------------------------------------------------------------------------------- +/** + * [id] = astra_mex_io_data('fetch_slice_y', id, slicenr); + */ +void astra_mex_data3d_fetch_slice_y(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// step1: get input + //if (nrhs < 3) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iDid = (int)(mxGetScalar(prhs[1])); + //int iSliceNr = (int)(mxGetScalar(prhs[2])); + + //// Get data object + //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); + //if (!pData) { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + + //CFloat32Data2D* res = NULL; + //// Projection Data + //if (pData->getType() == CFloat32Data3D::VOLUME) { + // CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); + // res = pData2->fetchSliceY(iSliceNr); + //} + //// Error + //else { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + // + //// store data + //int iIndex = CData2DManager::getSingleton().store(res); + + //// step4: set output + //if (1 <= nlhs) { + // plhs[0] = mxCreateDoubleScalar(iIndex); + //} +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_io_data('return_slice_y', id, slicenr); + */ +void astra_mex_data3d_return_slice_y(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ +// // step1: get input +// if (nrhs < 3) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// int iDid = (int)(mxGetScalar(prhs[1])); +// int iSliceNr = (int)(mxGetScalar(prhs[2])); +// +// // Get data object +// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); +// if (!pData) { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +// +// // Projection Data +// if (pData->getType() == CFloat32Data3D::VOLUME) { +// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); +//// TODO: think about returning slices +//// pData2->returnSliceY(iSliceNr); +// } +// // Error +// else { +// mexErrMsgTxt("DataObject not valid. \n"); +// return; +// } +} + +//----------------------------------------------------------------------------------------- +/** + * [dim_x dim_y dim_z] = astra_mex_io_data('dimensions', id); + */ +void astra_mex_data3d_dimensions(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iDid = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CFloat32Data3D* pData; + if (!(pData = CData3DManager::getSingleton().get(iDid))) { + mexErrMsgTxt("DataObject not valid. \n"); + return; + } + + // step3: output + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(pData->getWidth()); + } + if (2 <= nlhs) { + plhs[1] = mxCreateDoubleScalar(pData->getHeight()); + } + if (3 <= nlhs) { + plhs[2] = mxCreateDoubleScalar(pData->getDepth()); + } +} + +//----------------------------------------------------------------------------------------- +/** + * [geom] = astra_mex_data3d('geometry', id); + */ +void astra_mex_data3d_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// Get input + //if (nrhs < 2) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iDid = (int)(mxGetScalar(prhs[1])); + + //// Get data object + //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); + //if (!pData) { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + + //// Projection Data + //if (pData->getType() == CFloat32Data3D::PROJECTION) { + // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData); + // CProjectionGeometry3D* pProjGeom = pData2->getGeometry(); + // XMLDocument* config = pProjGeom->toXML(); + + // if (1 <= nlhs) { + // plhs[0] = XML2struct(config); + // } + //} + //// Volume Data + //else if (pData->getType() == CFloat32Data3D::VOLUME) { + //// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); + //// CVolumeGeometry2D* pVolGeom = pData2->getGeometry2D(iSliceNr); + //// if (1 <= nlhs) { + //// plhs[0] = createVolumeGeometryStruct(pVolGeom); + //// } + //} + //// Error + //else { + // mexErrMsgTxt("Type not valid. \n"); + // return; + //} +} + +//----------------------------------------------------------------------------------------- +/** + * [geom_xml] = astra_mex_data3d('geometry_xml', id); + */ +void astra_mex_data3d_geometry_xml(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// Get input + //if (nrhs < 2) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iDid = (int)(mxGetScalar(prhs[1])); + + //// Get data object + //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid); + //if (!pData) { + // mexErrMsgTxt("DataObject not valid. \n"); + // return; + //} + + //// Projection Data + //if (pData->getType() == CFloat32Data3D::PROJECTION) { + // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData); + // CProjectionGeometry3D* pProjGeom = pData2->getGeometry(); + // XMLDocument* config = pProjGeom->toXML(); + + // if (1 <= nlhs) { + // plhs[0] = mxCreateString(config->getRootNode()->toString().c_str()); + // } + //} + //// Volume Data + //else if (pData->getType() == CFloat32Data3D::VOLUME) { + //// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData); + //// CVolumeGeometry2D* pVolGeom = pData2->getGeometry2D(iSliceNr); + //// if (1 <= nlhs) { + //// plhs[0] = createVolumeGeometryStruct(pVolGeom); + //// } + //} + //// Error + //else { + // mexErrMsgTxt("Type not valid. \n"); + // return; + //} +} +//----------------------------------------------------------------------------------------- +/** + * astra_mex_data3d('delete', did1, did2, ...); + */ +void astra_mex_data3d_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + for (int i = 1; i < nrhs; i++) { + int iDataID = (int)(mxGetScalar(prhs[i])); + CData3DManager::getSingleton().remove(iDataID); + } +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_data3d('clear'); + */ +void astra_mex_data3d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + CData3DManager::getSingleton().clear(); +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_data3d('info'); + */ +void astra_mex_data3d_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + mexPrintf("%s", astra::CData3DManager::getSingleton().info().c_str()); +} + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf("Valid modes: create, create_cache, get, get_single, delete, clear, info\n"); + mexPrintf(" fetch_projection, return_projection, fetch_slice[_z],\n"); + mexPrintf(" return_slice[_z], fetch_slice_x, return slice_x\n"); + mexPrintf(" fetch_slice_y, return slice_y, dimensions, geometry\n"); + mexPrintf(" geometry_xml\n"); +} + + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex_io_data(mode,...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + + // INPUT: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // 3D data + if (sMode == std::string("create")) { + astra_mex_data3d_create(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("create_cache")) { + astra_mex_data3d_create_cache(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("get")) { + astra_mex_data3d_get(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("get_single")) { + astra_mex_data3d_get_single(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("store") || + sMode == std::string("set")) { + astra_mex_data3d_store(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("delete")) { + astra_mex_data3d_delete(nlhs, plhs, nrhs, prhs); + } else if (sMode == "clear") { + astra_mex_data3d_clear(nlhs, plhs, nrhs, prhs); + } else if (sMode == "info") { + astra_mex_data3d_info(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("fetch_projection")) { + astra_mex_data3d_fetch_projection(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("return_projection")) { + astra_mex_data3d_return_projection(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("fetch_slice") || sMode == std::string("fetch_slice_z")) { + astra_mex_data3d_fetch_slice_z(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("return_slice") || sMode == std::string("return_slice_z")) { + astra_mex_data3d_return_slice_z(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("fetch_slice_x")) { + astra_mex_data3d_fetch_slice_x(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("return_slice_x")) { + astra_mex_data3d_return_slice_x(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("fetch_slice_y")) { + astra_mex_data3d_fetch_slice_y(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("return_slice_y")) { + astra_mex_data3d_return_slice_y(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("dimensions")) { + astra_mex_data3d_dimensions(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("geometry")) { + astra_mex_data3d_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("geometry_xml")) { + astra_mex_data3d_geometry_xml(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + + return; +} + + diff --git a/matlab/mex/astra_mex_data3d_vc08.vcproj b/matlab/mex/astra_mex_data3d_vc08.vcproj new file mode 100644 index 0000000..2e69c16 --- /dev/null +++ b/matlab/mex/astra_mex_data3d_vc08.vcproj @@ -0,0 +1,588 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex_data3d" + ProjectGUID="{0BEC029B-0929-4BF9-BD8B-9C9806A52065}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_data3d_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/astra_mex_matrix_c.cpp b/matlab/mex/astra_mex_matrix_c.cpp new file mode 100644 index 0000000..accaab5 --- /dev/null +++ b/matlab/mex/astra_mex_matrix_c.cpp @@ -0,0 +1,437 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_matrix_c.cpp + * + * \brief Create sparse (projection) matrices in the ASTRA workspace + */ +#include <mex.h> +#include "mexHelpFunctions.h" + +#include <list> + +#include "astra/Globals.h" + +#include "astra/AstraObjectManager.h" + +#include "astra/SparseMatrix.h" + +using namespace std; +using namespace astra; + +//----------------------------------------------------------------------------------------- +/** astra_mex_matrix('delete', id1, id2, ...); + * + * Delete one or more data objects currently stored in the astra-library. + * id1, id2, ... : identifiers of the 2d data objects as stored in the astra-library. + */ +void astra_mex_matrix_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + // step2: delete all specified data objects + for (int i = 1; i < nrhs; i++) { + int iDataID = (int)(mxGetScalar(prhs[i])); + CMatrixManager::getSingleton().remove(iDataID); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_matrix('clear'); + * + * Delete all data objects currently stored in the astra-library. + */ +void astra_mex_matrix_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + CMatrixManager::getSingleton().clear(); +} + + + +static bool matlab_to_astra(const mxArray* _rhs, CSparseMatrix* _pMatrix) +{ + // Check input + if (!mxIsSparse (_rhs)) { + mexErrMsgTxt("Argument is not a valid MATLAB sparse matrix.\n"); + return false; + } + if (!_pMatrix->isInitialized()) { + mexErrMsgTxt("Couldn't initialize data object.\n"); + return false; + } + + unsigned int iHeight = mxGetM(_rhs); + unsigned int iWidth = mxGetN(_rhs); + unsigned long lSize = mxGetNzmax(_rhs); + + if (_pMatrix->m_lSize < lSize || _pMatrix->m_iHeight < iHeight) { + // TODO: support resizing? + mexErrMsgTxt("Matrix too large to store in this object.\n"); + return false; + } + + // Transpose matrix, as matlab stores a matrix column-by-column + // but we want it row-by-row. + // 1. Compute sizes of rows. We store these in _pMatrix->m_plRowStarts. + // 2. Fill data structure + // Complexity: O( #rows + #entries ) + + for (unsigned int i = 0; i <= iHeight; ++i) + _pMatrix->m_plRowStarts[i] = 0; + + mwIndex *colStarts = mxGetJc(_rhs); + mwIndex *rowIndices = mxGetIr(_rhs); + double *floatValues = 0; + bool *boolValues = 0; + bool bLogical = mxIsLogical(_rhs); + if (bLogical) + boolValues = mxGetLogicals(_rhs); + else + floatValues = mxGetPr(_rhs); + + for (mwIndex i = 0; i < colStarts[iWidth]; ++i) { + unsigned int iRow = rowIndices[i]; + assert(iRow < iHeight); + _pMatrix->m_plRowStarts[iRow+1]++; + } + + // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in row i + + for (unsigned int i = 1; i <= iHeight; ++i) + _pMatrix->m_plRowStarts[i] += _pMatrix->m_plRowStarts[i-1]; + + // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in rows <= i, + // so the intended start of row i+1 + + int iCol = 0; + for (mwIndex i = 0; i < colStarts[iWidth]; ++i) { + while (i >= colStarts[iCol+1]) + iCol++; + + unsigned int iRow = rowIndices[i]; + assert(iRow < iHeight); + float32 fVal; + if (bLogical) + fVal = (float32)boolValues[i]; + else + fVal = (float32)floatValues[i]; + + unsigned long lIndex = _pMatrix->m_plRowStarts[iRow]++; + _pMatrix->m_pfValues[lIndex] = fVal; + _pMatrix->m_piColIndices[lIndex] = iCol; + } + + // Now _pMatrix->m_plRowStarts[i] is the start of row i+1 + + for (unsigned int i = iHeight; i > 0; --i) + _pMatrix->m_plRowStarts[i] = _pMatrix->m_plRowStarts[i-1]; + _pMatrix->m_plRowStarts[0] = 0; + +#if 0 + // Debugging: dump matrix + for (unsigned int i = 0; i < iHeight; ++i) { + printf("Row %d: %ld-%ld\n", i, _pMatrix->m_plRowStarts[i], _pMatrix->m_plRowStarts[i+1]); + for (unsigned long j = _pMatrix->m_plRowStarts[i]; j < _pMatrix->m_plRowStarts[i+1]; ++j) { + printf("(%d,%d) = %f\n", i, _pMatrix->m_piColIndices[j], _pMatrix->m_pfValues[j]); + } + } +#endif + + return true; +} + +static bool astra_to_matlab(const CSparseMatrix* _pMatrix, mxArray*& _lhs) +{ + if (!_pMatrix->isInitialized()) { + mexErrMsgTxt("Uninitialized data object.\n"); + return false; + } + + unsigned int iHeight = _pMatrix->m_iHeight; + unsigned int iWidth = _pMatrix->m_iWidth; + unsigned long lSize = _pMatrix->m_lSize; + + _lhs = mxCreateSparse(iHeight, iWidth, lSize, mxREAL); + if (!mxIsSparse (_lhs)) { + mexErrMsgTxt("Couldn't initialize matlab sparse matrix.\n"); + return false; + } + + mwIndex *colStarts = mxGetJc(_lhs); + mwIndex *rowIndices = mxGetIr(_lhs); + double *floatValues = mxGetPr(_lhs); + + for (unsigned int i = 0; i <= iWidth; ++i) + colStarts[i] = 0; + + for (unsigned int i = 0; i < _pMatrix->m_plRowStarts[iHeight]; ++i) { + unsigned int iCol = _pMatrix->m_piColIndices[i]; + assert(iCol < iWidth); + colStarts[iCol+1]++; + } + // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in row i + + for (unsigned int i = 1; i <= iWidth; ++i) + colStarts[i] += colStarts[i-1]; + // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in rows <= i, + // so the intended start of row i+1 + + unsigned int iRow = 0; + for (unsigned int i = 0; i < _pMatrix->m_plRowStarts[iHeight]; ++i) { + while (i >= _pMatrix->m_plRowStarts[iRow+1]) + iRow++; + + unsigned int iCol = _pMatrix->m_piColIndices[i]; + assert(iCol < iWidth); + double fVal = _pMatrix->m_pfValues[i]; + unsigned long lIndex = colStarts[iCol]++; + floatValues[lIndex] = fVal; + rowIndices[lIndex] = iRow; + } + // Now _pMatrix->m_plRowStarts[i] is the start of row i+1 + + for (unsigned int i = iWidth; i > 0; --i) + colStarts[i] = colStarts[i-1]; + colStarts[0] = 0; + + return true; +} + +//----------------------------------------------------------------------------------------- +/** id = astra_mex_matrix('create', data); + * + * Create a new matrix object in the astra-library. + * data: a sparse MATLAB matrix containing the data. + * id: identifier of the matrix object as it is now stored in the astra-library. + */ +void astra_mex_matrix_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[]) +{ + // step1: get datatype + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + if (!mxIsSparse (prhs[1])) { + mexErrMsgTxt("Argument is not a valid MATLAB sparse matrix.\n"); + return; + } + + unsigned int iHeight = mxGetM(prhs[1]); + unsigned int iWidth = mxGetN(prhs[1]); + unsigned long lSize = mxGetNzmax(prhs[1]); + + CSparseMatrix* pMatrix = new CSparseMatrix(iHeight, iWidth, lSize); + + // Check initialization + if (!pMatrix->isInitialized()) { + mexErrMsgTxt("Couldn't initialize data object.\n"); + delete pMatrix; + return; + } + + bool bResult = matlab_to_astra(prhs[1], pMatrix); + + if (!bResult) { + mexErrMsgTxt("Failed to create data object.\n"); + delete pMatrix; + return; + } + + // store data object + int iIndex = CMatrixManager::getSingleton().store(pMatrix); + + // return data id + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_matrix('store', id, data); + * + * Store a sparse MATLAB matrix in an existing astra matrix dataobject. + * id: identifier of the 2d data object as stored in the astra-library. + * data: a sparse MATLAB matrix. + */ +void astra_mex_matrix_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CSparseMatrix* pMatrix = astra::CMatrixManager::getSingleton().get(iDataID); + if (!pMatrix || !pMatrix->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + bool bResult = matlab_to_astra(prhs[2], pMatrix); + if (!bResult) { + mexErrMsgTxt("Failed to store matrix.\n"); + } +} + +//----------------------------------------------------------------------------------------- +/** geom = astra_mex_matrix('get_size', id); + * + * Fetch the dimensions and size of a matrix stored in the astra-library. + * id: identifier of the 2d data object as stored in the astra-library. + * geom: a 1x2 matrix containing [rows, columns] + */ +void astra_mex_matrix_get_size(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CSparseMatrix* pMatrix = astra::CMatrixManager::getSingleton().get(iDataID); + if (!pMatrix || !pMatrix->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + // TODO +} + +//----------------------------------------------------------------------------------------- +/** data = astra_mex_matrix('get', id); + * + * Fetch data from the astra-library to a MATLAB matrix. + * id: identifier of the matrix data object as stored in the astra-library. + * data: MATLAB + */ +void astra_mex_matrix_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: check input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + if (!mxIsDouble(prhs[1])) { + mexErrMsgTxt("Identifier should be a scalar value. \n"); + return; + } + int iDataID = (int)(mxGetScalar(prhs[1])); + + // step2: get data object + CSparseMatrix* pMatrix = astra::CMatrixManager::getSingleton().get(iDataID); + if (!pMatrix || !pMatrix->isInitialized()) { + mexErrMsgTxt("Data object not found or not initialized properly.\n"); + return; + } + + // create output + if (1 <= nlhs) { + bool bResult = astra_to_matlab(pMatrix, plhs[0]); + if (!bResult) { + mexErrMsgTxt("Failed to get matrix.\n"); + } + } + +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_matrix('info'); + * + * Print information about all the matrix objects currently stored in the astra-library. + */ +void astra_mex_matrix_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + mexPrintf("%s", astra::CMatrixManager::getSingleton().info().c_str()); +} + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf("Valid modes: get, delete, clear, store, create, get_size, info\n"); +} + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex_matrix(type,...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + + // INPUT0: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == std::string("get")) { + astra_mex_matrix_get(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("delete")) { + astra_mex_matrix_delete(nlhs, plhs, nrhs, prhs); + } else if (sMode == "clear") { + astra_mex_matrix_clear(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("store")) { + astra_mex_matrix_store(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("create")) { + astra_mex_matrix_create(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("get_size")) { + astra_mex_matrix_get_size(nlhs, plhs, nrhs, prhs); + } else if (sMode == std::string("info")) { + astra_mex_matrix_info(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + + return; +} + + diff --git a/matlab/mex/astra_mex_matrix_vc08.vcproj b/matlab/mex/astra_mex_matrix_vc08.vcproj new file mode 100644 index 0000000..47509f6 --- /dev/null +++ b/matlab/mex/astra_mex_matrix_vc08.vcproj @@ -0,0 +1,591 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex_matrix" + ProjectGUID="{9D041710-2119-4230-BCF2-5FBE753FDE49}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + BrowseInformation="1" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_matrix_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/astra_mex_projector3d_c.cpp b/matlab/mex/astra_mex_projector3d_c.cpp new file mode 100644 index 0000000..1385863 --- /dev/null +++ b/matlab/mex/astra_mex_projector3d_c.cpp @@ -0,0 +1,433 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_projector3d_c.cpp + * + * \brief Create and manage 3d projectors in the ASTRA workspace + */ + +#include <mex.h> +#include "mexHelpFunctions.h" + +#include "astra/Globals.h" + +#include "astra/Projector3D.h" +#include "astra/AstraObjectManager.h" +#include "astra/AstraObjectFactory.h" + +#include "astra/ProjectionGeometry3D.h" +#include "astra/VolumeGeometry3D.h" + +#include <map> +#include <vector> + +using namespace std; +using namespace astra; + +//----------------------------------------------------------------------------------------- +/** +* [pid] = astra_mex_projector('create', cfgstruct); +*/ +void astra_mex_projector3d_create(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + if (!mxIsStruct(prhs[1])) { + mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n"); + } + + // turn MATLAB struct to an XML-based Config object + XMLDocument* xml = struct2XML("Projector3D", prhs[1]); + Config cfg; + cfg.self = xml->getRootNode(); + + // create algorithm + CProjector3D* pProj = CProjector3DFactory::getSingleton().create(cfg); + if (pProj == NULL) { + mexErrMsgTxt("Error creating Projector3D. \n"); + return; + } + + // store projector + int iIndex = CProjector3DManager::getSingleton().store(pProj); + + // step4: set output + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } + + } + +//----------------------------------------------------------------------------------------- +/** +* astra_mex_projector3d('destroy', pid1, pid2, ...); +*/ +void astra_mex_projector3d_destroy(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + for (int i = 1; i < nrhs; i++) { + int iPid = (int)(mxGetScalar(prhs[i])); + CProjector3DManager::getSingleton().remove(iPid); + } +} + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_projector3d('clear'); + */ +void astra_mex_projector3d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + CProjector3DManager::getSingleton().clear(); +} + + +//----------------------------------------------------------------------------------------- +/** +* [proj_geom] = astra_mex_projector3d('get_projection_geometry', pid); +*/ +void astra_mex_projector3d_get_projection_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector3D* pProjector; + if (!(pProjector = CProjector3DManager::getSingleton().get(iPid))) { + mexErrMsgTxt("Projector not found.\n"); + return; + } + + // step3: get projection_geometry and turn it into a MATLAB struct + //if (1 <= nlhs) { + // plhs[0] = createProjectionGeometryStruct(pProjector->getProjectionGeometry()); + //} +} + +//----------------------------------------------------------------------------------------- +/** +* [recon_geom] = astra_mex_projector3d('get_volume_geometry', pid); +*/ +void astra_mex_projector3d_get_reconstruction_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector3D* pProjector; + if (!(pProjector = CProjector3DManager::getSingleton().get(iPid))) { + mexErrMsgTxt("Projector not found.\n"); + return; + } + + // step3: get projection_geometry and turn it into a MATLAB struct + //if (1 <= nlhs) { + // plhs[0] = createVolumeGeometryStruct(pProjector->getVolumeGeometry()); + //} +} + +//----------------------------------------------------------------------------------------- +/** +* [weights] = astra_mex_projector3d('weights_single_ray', pid, projection_index, detector_index); +*/ +void astra_mex_projector_weights_single_ray(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + //// step1: get input + //if (nrhs < 4) { + // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + // return; + //} + //int iPid = (int)(mxGetScalar(prhs[1])); + //int iProjectionIndex = (int)(mxGetScalar(prhs[2])); + //int iDetectorIndex = (int)(mxGetScalar(prhs[3])); + + //// step2: get projector + //CProjector3D* pProjector; + //if (!(pProjector = CProjector3DManager::getSingleton().get(iPid))) { + // mexErrMsgTxt("Projector not found.\n"); + // return; + //} + // + //// step3: create output vars + //int iStoredPixelCount; + //int iMaxPixelCount = pProjector->getProjectionWeightsCount(iProjectionIndex); + //SWeightedPixel* pPixelsWeights = new SWeightedPixel3D[iMaxPixelCount]; + // + //// step4: perform operation + //pProjector->computeSingleRayWeights(iProjectionIndex, + // iDetectorIndex, + // pPixelsWeights, + // iMaxPixelCount, + // iStoredPixelCount); + + //// step5: return output + //if (1 <= nlhs) { + // mwSize dims[2]; + // dims[0] = iStoredPixelCount; + // dims[1] = 2; + + // plhs[0] = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxREAL); + // double* out = mxGetPr(plhs[0]); + + // for (int col = 0; col < iStoredPixelCount; col++) { + // out[col] = pPixelsWeights[col].m_iIndex; + // out[iStoredPixelCount+col] = pPixelsWeights[col].m_fWeight; + // //cout << pPixelsWeights[col].m_iIndex << " " << pPixelsWeights[col].m_fWeight <<endl; + // } + //} + // + //// garbage collection + //delete[] pPixelsWeights; +} + +////----------------------------------------------------------------------------------------- +///** +//* [weights] = astra_mex_projector('weights_projection', pid, projection_index); +//*/ +//void astra_mex_projector_weights_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +//{ +// // step1: get input +// if (nrhs < 3) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// int iPid = (int)(mxGetScalar(prhs[1])); +// int iProjectionIndex = (int)(mxGetScalar(prhs[2])); +// +// // step2: get projector +// CProjector2D* pProjector; +// if (!(pProjector = CProjectorManager::getSingleton().get(iPid))) { +// mexErrMsgTxt("Projector not found.\n"); +// return; +// } +// +// // step3: create output vars +// SWeightedPixel2D* pPixelsWheights = new SWeightedPixel2D[pProjector->getProjectionWeightsCount(iProjectionIndex)]; +// int* piRayStoredPixelCount = new int[pProjector->getProjectionGeometry()->getDetectorCount()]; +// +// // step4: perform operation +// pProjector->computeProjectionRayWeights(iProjectionIndex, pPixelsWheights, piRayStoredPixelCount); +// +// // step5: return output +// if (1 <= nlhs) { +// // get basic values +// int iMatrixSize = pProjector->getVolumeGeometry()->getWindowLengthX() * +// pProjector->getVolumeGeometry()->getWindowLengthY(); +// int iDetectorCount = pProjector->getProjectionGeometry()->getDetectorCount(); +// int iTotalStoredPixelCount = 0; +// for (int i = 0; i < iDetectorCount; i++) { +// iTotalStoredPixelCount += piRayStoredPixelCount[i]; +// } +// +// // create matlab sparse matrix +// plhs[0] = mxCreateSparse(iMatrixSize, // number of rows (#pixels) +// iDetectorCount, // number of columns (#detectors) +// iTotalStoredPixelCount, // number of non-zero elements +// mxREAL); // element type +// double* values = mxGetPr(plhs[0]); +// mwIndex* rows = mxGetIr(plhs[0]); +// mwIndex* cols = mxGetJc(plhs[0]); +// +// int currentBase = 0; +// int currentIndex = 0; +// for (int i = 0; i < iDetectorCount; i++) { +// for (int j = 0; j < piRayStoredPixelCount[i]; j++) { +// values[currentIndex + j] = pPixelsWheights[currentBase + j].m_fWeight; +// rows[currentIndex + j] = pPixelsWheights[currentBase + j].m_iIndex; +// } +// +// currentBase += pProjector->getProjectionWeightsCount(iProjectionIndex) / pProjector->getProjectionGeometry()->getDetectorCount(); +// currentIndex += piRayStoredPixelCount[i]; +// } +// cols[0] = piRayStoredPixelCount[0]; +// for (int j = 1; j < iDetectorCount; j++) { +// cols[j] = cols[j-1] + piRayStoredPixelCount[j]; +// } +// cols[iDetectorCount] = iTotalStoredPixelCount; +// } +// +//} +// +////----------------------------------------------------------------------------------------- +///** +//* output = astra_mex_projector('splat', pid, x, y); +//*/ +//void astra_mex_projector_splat(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +//{ +// // step1: get input +// if (nrhs < 4) { +// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); +// return; +// } +// int iPid = (int)(mxGetScalar(prhs[1])); +// int iX = (int)(mxGetScalar(prhs[2])); +// int iY = (int)(mxGetScalar(prhs[3])); +// +// // step2: get projector +// CProjector2D* pProjector; +// if (!(pProjector = CProjectorManager::getSingleton().get(iPid))) { +// mexErrMsgTxt("Projector not found.\n"); +// return; +// } +// +// // step3: perform action +// vector<SDetector2D> detinfo = pProjector->projectPoint(iX, iY); +// +// // step4: output +// if (nlhs <= 1) { +// plhs[0] = mxCreateDoubleMatrix(detinfo.size(), // # rows +// 2, // # cols +// mxREAL); // datatype 32-bits +// double* out = mxGetPr(plhs[0]); +// +// // fill up output +// int i = 0; +// for (int x = 0; x < detinfo.size() ; x++) { +// out[i] = detinfo[x].m_iAngleIndex; +// i++; +// } +// for (int x = 0; x < detinfo.size() ; x++) { +// out[i] = detinfo[x].m_iDetectorIndex; +// i++; +// } +// } +// +// +//} + +//----------------------------------------------------------------------------------------- +/** result = astra_mex_projector3d('is_cuda', id); + * + * Return is the specified projector is a cuda projector. + * id: identifier of the projector object as stored in the astra-library. + */ +void astra_mex_projector3d_is_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector3D* pProjector = CProjector3DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + +#ifdef ASTRA_CUDA + CCudaProjector3D* pCP = dynamic_cast<CCudaProjector3D*>(pProjector); + plhs[0] = mxCreateLogicalScalar(pCP ? 1 : 0); +#else + plhs[0] = mxCreateLogicalScalar(0); +#endif +} + + +//----------------------------------------------------------------------------------------- +/** + * astra_mex_projector3d('help'); + */ +void astra_mex_projector3d_help(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + cout << "astra_mex_projector3d help:" <<endl; + cout << "---------------------------" <<endl; +} + + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf("Valid modes: create, delete, clear, get_projection_geometry,\n"); + mexPrintf(" get_volume_geometry, weights_single_ray, weights_projection\n"); + mexPrintf(" splat, is_cuda\n"); +} + +//----------------------------------------------------------------------------------------- +/** + * [pid] = astra_mex_projector('read', projection_geometry, reconstruction_geometry); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + // INPUT: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == "create") { + astra_mex_projector3d_create(nlhs, plhs, nrhs, prhs); + } else if (sMode == "delete") { + astra_mex_projector3d_destroy(nlhs, plhs, nrhs, prhs); + } else if (sMode == "clear") { + astra_mex_projector3d_clear(nlhs, plhs, nrhs, prhs); + } else if (sMode == "get_projection_geometry") { + astra_mex_projector3d_get_projection_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == "get_volume_geometry") { + astra_mex_projector3d_get_reconstruction_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == "weights_single_ray") { + astra_mex_projector_weights_single_ray(nlhs, plhs, nrhs, prhs); + //} else if (sMode == "weights_projection") { + // astra_mex_projector_weights_projection(nlhs, plhs, nrhs, prhs); + //} else if (sMode == "splat") { + // astra_mex_projector_splat(nlhs, plhs, nrhs, prhs); + } else if (sMode == "is_cuda") { + astra_mex_projector3d_is_cuda(nlhs, plhs, nrhs, prhs); + } else if (sMode == "help") { + astra_mex_projector3d_help(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + return; +} + + diff --git a/matlab/mex/astra_mex_projector3d_vc08.vcproj b/matlab/mex/astra_mex_projector3d_vc08.vcproj new file mode 100644 index 0000000..bedc53b --- /dev/null +++ b/matlab/mex/astra_mex_projector3d_vc08.vcproj @@ -0,0 +1,588 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex_projector3d" + ProjectGUID="{F94CCD79-AA11-42DF-AC8A-6C9D2238A883}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_projector3d_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/astra_mex_projector_c.cpp b/matlab/mex/astra_mex_projector_c.cpp new file mode 100644 index 0000000..5cbe502 --- /dev/null +++ b/matlab/mex/astra_mex_projector_c.cpp @@ -0,0 +1,510 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file astra_mex_projector_c.cpp + * + * \brief Create and manage 2d projectors in the ASTRA workspace + */ +#include "astra/Globals.h" + +#include <mex.h> +#include "mexHelpFunctions.h" + +#include "astra/AstraObjectManager.h" +#include "astra/Projector2D.h" +#include "astra/AstraObjectFactory.h" + +#include "astra/Float32VolumeData2D.h" + +#include "astra/ProjectionGeometry2D.h" +#include "astra/ParallelProjectionGeometry2D.h" +#include "astra/VolumeGeometry2D.h" + + +#include <map> +#include <vector> + +using namespace std; +using namespace astra; + +//----------------------------------------------------------------------------------------- +/** id = astra_mex_projector('create', cfg); + * + * Create and configure a new projector object. + * cfg: MATLAB struct containing the configuration parameters, see doxygen documentation for details. + * id: identifier of the projector object as it is now stored in the astra-library. + */ +void astra_mex_projector_create(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + int iIndex = 0; + + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + if (!mxIsStruct(prhs[1])) { + mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n"); + } + + + // turn MATLAB struct to an XML-based Config object + XMLDocument* xml = struct2XML("Projector2D", prhs[1]); + Config cfg; + cfg.self = xml->getRootNode(); + + // create algorithm + CProjector2D* pProj = CProjector2DFactory::getSingleton().create(cfg); + if (pProj == NULL) { + delete xml; + mexErrMsgTxt("Error creating projector. \n"); + return; + } + + delete xml; + + // store projector + iIndex = CProjector2DManager::getSingleton().store(pProj); + + // step4: set output + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_projector('delete', id1, id2, ...); + * + * Delete one or more projector objects currently stored in the astra-library. + * id1, id2, ... : identifiers of the projector objects as stored in the astra-library. + */ +void astra_mex_projector_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + + for (int i = 1; i < nrhs; i++) { + int iPid = (int)(mxGetScalar(prhs[i])); + CProjector2DManager::getSingleton().remove(iPid); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_projector('clear'); + * + * Delete all projector objects currently stored in the astra-library. + */ +void astra_mex_projector_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + CProjector2DManager::getSingleton().clear(); +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_projector('info'); + * + * Print information about all the projector objects currently stored in the astra-library. + */ +void astra_mex_projector_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + mexPrintf("%s", astra::CProjector2DManager::getSingleton().info().c_str()); +} + +//----------------------------------------------------------------------------------------- +/** proj_geom = astra_mex_projector('projection_geometry', id); + * + * Fetch the projection geometry of a certain projector. + * id: identifier of the projector object as stored in the astra-library. + * proj_geom: MATLAB struct containing all information about the projection geometry +*/ +void astra_mex_projector_projection_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + + // step3: get projection_geometry and turn it into a MATLAB struct + if (1 <= nlhs) { + plhs[0] = createProjectionGeometryStruct(pProjector->getProjectionGeometry()); + } +} + +//----------------------------------------------------------------------------------------- +/** vol_geom = astra_mex_projector('volume_geometry', id); + * + * Fetch the volume geometry of a certain projector. + * id: identifier of the projector object as stored in the astra-library. + * vol_geom: MATLAB struct containing all information about the volume geometry + */ +void astra_mex_projector_volume_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: read input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + + // step3: get projection_geometry and turn it into a MATLAB struct + if (1 <= nlhs) { + plhs[0] = createVolumeGeometryStruct(pProjector->getVolumeGeometry()); + } +} + +//----------------------------------------------------------------------------------------- +/** weights = astra_mex_projector('weights_single_ray', id, projection_index, detector_index); + * + * Calculate the nonzero weights of a certain projection ray. + * id: identifier of the projector object as stored in the astra-library. + * projection_index: index of the projection angle + * detector_index: index of the detector + * weights: list of computed weights [pixel_index, weight] + */ +void astra_mex_projector_weights_single_ray(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 4) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + int iProjectionIndex = (int)(mxGetScalar(prhs[2])); + int iDetectorIndex = (int)(mxGetScalar(prhs[3])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + + // step3: create output vars + int iStoredPixelCount; + int iMaxPixelCount = pProjector->getProjectionWeightsCount(iProjectionIndex); + SPixelWeight* pPixelsWeights = new SPixelWeight[iMaxPixelCount]; + + // step4: perform operation + pProjector->computeSingleRayWeights(iProjectionIndex, + iDetectorIndex, + pPixelsWeights, + iMaxPixelCount, + iStoredPixelCount); + + // step5: return output + if (1 <= nlhs) { + mwSize dims[2]; + dims[0] = iStoredPixelCount; + dims[1] = 2; + + plhs[0] = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxREAL); + double* out = mxGetPr(plhs[0]); + + for (int col = 0; col < iStoredPixelCount; col++) { + out[col] = pPixelsWeights[col].m_iIndex; + out[iStoredPixelCount+col] = pPixelsWeights[col].m_fWeight; + } + } + + // garbage collection + delete[] pPixelsWeights; +} + +//----------------------------------------------------------------------------------------- +/** weights = astra_mex_projector('weights_projection', id, projection_index); + * + * Calculate the nonzero weights of all rays in a certain projection. + * id: identifier of the projector object as stored in the astra-library. + * projection_index: index of the projection angle + * weights: sparse matrix containing the rows of the projection matric belonging to the requested projection angle. + */ +void astra_mex_projector_weights_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 3) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + int iProjectionIndex = (int)(mxGetScalar(prhs[2])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + + // step3: create output vars + SPixelWeight* pPixelsWheights = new SPixelWeight[pProjector->getProjectionWeightsCount(iProjectionIndex)]; + int* piRayStoredPixelCount = new int[pProjector->getProjectionGeometry()->getDetectorCount()]; + + // step4: perform operation + pProjector->computeProjectionRayWeights(iProjectionIndex, pPixelsWheights, piRayStoredPixelCount); + + // step5: return output + if (1 <= nlhs) { + // get basic values + int iMatrixSize = pProjector->getVolumeGeometry()->getWindowLengthX() * + pProjector->getVolumeGeometry()->getWindowLengthY(); + int iDetectorCount = pProjector->getProjectionGeometry()->getDetectorCount(); + int iTotalStoredPixelCount = 0; + for (int i = 0; i < iDetectorCount; i++) { + iTotalStoredPixelCount += piRayStoredPixelCount[i]; + } + + // create matlab sparse matrix + plhs[0] = mxCreateSparse(iMatrixSize, // number of rows (#pixels) + iDetectorCount, // number of columns (#detectors) + iTotalStoredPixelCount, // number of non-zero elements + mxREAL); // element type + double* values = mxGetPr(plhs[0]); + mwIndex* rows = mxGetIr(plhs[0]); + mwIndex* cols = mxGetJc(plhs[0]); + + int currentBase = 0; + int currentIndex = 0; + for (int i = 0; i < iDetectorCount; i++) { + for (int j = 0; j < piRayStoredPixelCount[i]; j++) { + values[currentIndex + j] = pPixelsWheights[currentBase + j].m_fWeight; + rows[currentIndex + j] = pPixelsWheights[currentBase + j].m_iIndex; + } + + currentBase += pProjector->getProjectionWeightsCount(iProjectionIndex) / pProjector->getProjectionGeometry()->getDetectorCount(); + currentIndex += piRayStoredPixelCount[i]; + } + cols[0] = piRayStoredPixelCount[0]; + for (int j = 1; j < iDetectorCount; j++) { + cols[j] = cols[j-1] + piRayStoredPixelCount[j]; + } + cols[iDetectorCount] = iTotalStoredPixelCount; + } + + delete[] pPixelsWheights; + delete[] piRayStoredPixelCount; +} + +//----------------------------------------------------------------------------------------- +/** hit_detectors = astra_mex_projector('splat', id, col, row); + * + * Create a list of detector indices which have a nonzero contribution to the projection matrix for a pixel [row,col]. + * id: identifier of the projector object as stored in the astra-library. + * col: column of the pixel + * row: row of the pixel + * hit_detectors: list of detector indices [angle_index, det_index] that are hit + */ +void astra_mex_projector_splat(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 4) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + int iX = (int)(mxGetScalar(prhs[2])); + int iY = (int)(mxGetScalar(prhs[3])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + + // step3: perform action + vector<SDetector2D> detinfo = pProjector->projectPoint(iX, iY); + + // step4: output + if (nlhs <= 1) { + plhs[0] = mxCreateDoubleMatrix(detinfo.size(), // # rows + 2, // # cols + mxREAL); // datatype 32-bits + double* out = mxGetPr(plhs[0]); + + // fill up output + int i = 0; + int x; + for (x = 0; x < detinfo.size(); ++x) { + out[i] = detinfo[x].m_iAngleIndex; + ++i; + } + for (x = 0; x < detinfo.size(); ++x) { + out[i] = detinfo[x].m_iDetectorIndex; + ++i; + } + } + + +} + +//----------------------------------------------------------------------------------------- +/** matrix_id = astra_mex_projector('matrix', id); + * + * Create an explicit projection matrix for this projector. + * It returns an ID usable with astra_mex_matrix(). + * id: identifier of the projector object as stored in the astra-library. + */ +void astra_mex_projector_matrix(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + + CSparseMatrix* pMatrix = pProjector->getMatrix(); + if (!pMatrix || !pMatrix->isInitialized()) { + mexErrMsgTxt("Couldn't initialize data object.\n"); + delete pMatrix; + return; + } + + // store data object + int iIndex = CMatrixManager::getSingleton().store(pMatrix); + + // return data id + if (1 <= nlhs) { + plhs[0] = mxCreateDoubleScalar(iIndex); + } +} + +//----------------------------------------------------------------------------------------- +/** result = astra_mex_projector('is_cuda', id); + * + * Return is the specified projector is a cuda projector. + * id: identifier of the projector object as stored in the astra-library. + */ +void astra_mex_projector_is_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) +{ + // step1: get input + if (nrhs < 2) { + mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n"); + return; + } + int iPid = (int)(mxGetScalar(prhs[1])); + + // step2: get projector + CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid); + if (!pProjector || !pProjector->isInitialized()) { + mexErrMsgTxt("Projector not initialized.\n"); + return; + } + +#ifdef ASTRA_CUDA + CCudaProjector2D* pCP = dynamic_cast<CCudaProjector2D*>(pProjector); + plhs[0] = mxCreateLogicalScalar(pCP ? 1 : 0); +#else + plhs[0] = mxCreateLogicalScalar(0); +#endif +} + + + +//----------------------------------------------------------------------------------------- + +static void printHelp() +{ + mexPrintf("Please specify a mode of operation.\n"); + mexPrintf("Valid modes: create, delete, clear, info, projection_geometry,\n"); + mexPrintf(" volume_geometry, weights_single_ray, weights_projection\n"); + mexPrintf(" splat, matrix, is_cuda\n"); +} + + +//----------------------------------------------------------------------------------------- +/** + * ... = astra_mex_projector(mode, ...); + */ +void mexFunction(int nlhs, mxArray* plhs[], + int nrhs, const mxArray* prhs[]) +{ + // INPUT: Mode + string sMode = ""; + if (1 <= nrhs) { + sMode = mex_util_get_string(prhs[0]); + } else { + printHelp(); + return; + } + + // SWITCH (MODE) + if (sMode == "create") { + astra_mex_projector_create(nlhs, plhs, nrhs, prhs); + } else if (sMode == "delete") { + astra_mex_projector_delete(nlhs, plhs, nrhs, prhs); + } else if (sMode == "clear") { + astra_mex_projector_clear(nlhs, plhs, nrhs, prhs); + } else if (sMode == "info") { + astra_mex_projector_info(nlhs, plhs, nrhs, prhs); + } else if (sMode == "projection_geometry") { + astra_mex_projector_projection_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == "volume_geometry") { + astra_mex_projector_volume_geometry(nlhs, plhs, nrhs, prhs); + } else if (sMode == "weights_single_ray") { + astra_mex_projector_weights_single_ray(nlhs, plhs, nrhs, prhs); + } else if (sMode == "weights_projection") { + astra_mex_projector_weights_projection(nlhs, plhs, nrhs, prhs); + } else if (sMode == "splat") { + astra_mex_projector_splat(nlhs, plhs, nrhs, prhs); + } else if (sMode == "matrix") { + astra_mex_projector_matrix(nlhs, plhs, nrhs, prhs); + } else if (sMode == "is_cuda") { + astra_mex_projector_is_cuda(nlhs, plhs, nrhs, prhs); + } else { + printHelp(); + } + return; +} + + diff --git a/matlab/mex/astra_mex_projector_vc08.vcproj b/matlab/mex/astra_mex_projector_vc08.vcproj new file mode 100644 index 0000000..1380061 --- /dev/null +++ b/matlab/mex/astra_mex_projector_vc08.vcproj @@ -0,0 +1,591 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex_projector" + ProjectGUID="{4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories=""$(MATLAB_ROOT)\extern\include\";"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + BrowseInformation="1" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_projector_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/astra_mex_vc08.vcproj b/matlab/mex/astra_mex_vc08.vcproj new file mode 100644 index 0000000..58c1e0a --- /dev/null +++ b/matlab/mex/astra_mex_vc08.vcproj @@ -0,0 +1,591 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="astra_mex" + ProjectGUID="{3FDA35E0-0D54-4663-A3E6-5ABA96F32221}" + RootNamespace="astraMatlab" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;"$(CUDA_INC_PATH)";..\..\lib\include;..\..\lib\include\cuda;..\..\include\;" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=""$(CUDA_INC_PATH)";$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + PreprocessorDefinitions="ASTRA_CUDA" + RuntimeLibrary="3" + BrowseInformation="1" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib libut.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw32" + AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft" + ModuleDefinitionFile="mex.def" + GenerateDebugInformation="true" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\$(ProjectName)" + ConfigurationType="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include" + RuntimeLibrary="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib" + OutputFile="$(OutDir)\$(ProjectName)_c.mexw64" + AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft" + ModuleDefinitionFile="mex.def" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\astra_mex_c.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.cpp" + > + </File> + <File + RelativePath=".\mexHelpFunctions.h" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/matlab/mex/mex.def b/matlab/mex/mex.def new file mode 100644 index 0000000..c54c4e0 --- /dev/null +++ b/matlab/mex/mex.def @@ -0,0 +1 @@ +EXPORTS mexFunction
\ No newline at end of file diff --git a/matlab/mex/mexHelpFunctions.cpp b/matlab/mex/mexHelpFunctions.cpp new file mode 100644 index 0000000..4105ee1 --- /dev/null +++ b/matlab/mex/mexHelpFunctions.cpp @@ -0,0 +1,642 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +/** \file mexHelpFunctions.cpp + * + * \brief Contains some functions for interfacing matlab with c data structures + */ +#include "mexHelpFunctions.h" + +#include "astra/SparseMatrixProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/AstraObjectManager.h" + +using namespace std; +using namespace astra; + + +//----------------------------------------------------------------------------------------- +// get string from matlab +std::string mex_util_get_string(const mxArray* pInput) +{ + if (!mxIsChar(pInput)) { + return ""; + } + mwSize iLength = mxGetNumberOfElements(pInput) + 1; + char* buf = new char[iLength]; + mxGetString(pInput, buf, iLength); + std::string res = std::string(buf); + delete[] buf; + return res; +} + +//----------------------------------------------------------------------------------------- +// is option +bool isOption(std::list<std::string> lOptions, std::string sOption) +{ + return std::find(lOptions.begin(), lOptions.end(), sOption) != lOptions.end(); +} + +//----------------------------------------------------------------------------------------- +// turn a matlab struct into a c++ map +std::map<std::string, mxArray*> parseStruct(const mxArray* pInput) +{ + std::map<std::string, mxArray*> res; + + // check type + if (!mxIsStruct(pInput)) { + mexErrMsgTxt("Input must be a struct."); + return res; + } + + // get field names + int nfields = mxGetNumberOfFields(pInput); + for (int i = 0; i < nfields; i++) { + std::string sFieldName = std::string(mxGetFieldNameByNumber(pInput, i)); + res[sFieldName] = mxGetFieldByNumber(pInput,0,i); + } + return res; +} + +//----------------------------------------------------------------------------------------- +// turn a c++ map into a matlab struct +mxArray* buildStruct(std::map<std::string, mxArray*> mInput) +{ + mwSize dims[2] = {1, 1}; + mxArray* res = mxCreateStructArray(2,dims,0,0); + + for (std::map<std::string, mxArray*>::iterator it = mInput.begin(); it != mInput.end(); it++) { + mxAddField(res, (*it).first.c_str()); + mxSetField(res, 0, (*it).first.c_str(), (*it).second); + } + return res; +} + +//----------------------------------------------------------------------------------------- +// parse projection geometry data +astra::CProjectionGeometry2D* parseProjectionGeometryStruct(const mxArray* prhs) +{ + // parse struct + std::map<string, mxArray*> mStruct = parseStruct(prhs); + + // create projection geometry object + string type = mex_util_get_string(mStruct["type"]); + if (type == "parallel") { + + // detector_width + float32 fDetWidth = 1.0f; + mxArray* tmp = mStruct["detector_width"]; + if (tmp != NULL) { + fDetWidth = (float32)(mxGetScalar(tmp)); + } + + // detector_count + int iDetCount = 100; + tmp = mStruct["detector_count"]; + if (tmp != NULL) { + iDetCount = (int)(mxGetScalar(tmp)); + } + + // angles + float32* pfAngles; + int iAngleCount; + tmp = mStruct["projection_angles"]; + if (tmp != NULL) { + double* angleValues = mxGetPr(tmp); + iAngleCount = mxGetN(tmp) * mxGetM(tmp); + pfAngles = new float32[iAngleCount]; + for (int i = 0; i < iAngleCount; i++) { + pfAngles[i] = angleValues[i]; + } + } else { + mexErrMsgTxt("'angles' not specified, error."); + return NULL; + } + + // create projection geometry + return new astra::CParallelProjectionGeometry2D(iAngleCount, // number of projections + iDetCount, // number of detectors + fDetWidth, // width of the detectors + pfAngles); // angles array + } + + else if (type == "fanflat") { + + // detector_width + float32 fDetWidth = 1.0f; + mxArray* tmp = mStruct["detector_width"]; + if (tmp != NULL) { + fDetWidth = (float32)(mxGetScalar(tmp)); + } + + // detector_count + int iDetCount = 100; + tmp = mStruct["detector_count"]; + if (tmp != NULL) { + iDetCount = (int)(mxGetScalar(tmp)); + } + + // angles + float32* pfAngles; + int iAngleCount; + tmp = mStruct["projection_angles"]; + if (tmp != NULL) { + double* angleValues = mxGetPr(tmp); + iAngleCount = mxGetN(tmp) * mxGetM(tmp); + pfAngles = new float32[iAngleCount]; + for (int i = 0; i < iAngleCount; i++) { + pfAngles[i] = angleValues[i]; + } + } else { + mexErrMsgTxt("'angles' not specified, error."); + return NULL; + } + + // origin_source_dist + int iDistOriginSource = 100; + tmp = mStruct["origin_source_dist"]; + if (tmp != NULL) { + iDistOriginSource = (int)(mxGetScalar(tmp)); + } + + // origin_det_dist + int iDistOriginDet = 100; + tmp = mStruct["origin_det_dist"]; + if (tmp != NULL) { + iDistOriginDet = (int)(mxGetScalar(tmp)); + } + + // create projection geometry + return new astra::CFanFlatProjectionGeometry2D(iAngleCount, // number of projections + iDetCount, // number of detectors + fDetWidth, // width of the detectors + pfAngles, // angles array + iDistOriginSource, // distance origin source + iDistOriginDet); // distance origin detector + } + + else { + mexPrintf("Only parallel and fanflat projection geometry implemented."); + return NULL; + } +} + +//----------------------------------------------------------------------------------------- +// create projection geometry data +mxArray* createProjectionGeometryStruct(astra::CProjectionGeometry2D* _pProjGeom) +{ + // temporary map to store the data for the MATLAB struct + std::map<std::string, mxArray*> mGeometryInfo; + + // detectorCount + mGeometryInfo["DetectorCount"] = mxCreateDoubleScalar(_pProjGeom->getDetectorCount()); + + if (!_pProjGeom->isOfType("fanflat_vec")) { + // detectorWidth + mGeometryInfo["DetectorWidth"] = mxCreateDoubleScalar(_pProjGeom->getDetectorWidth()); + + // pfProjectionAngles + mxArray* pAngles = mxCreateDoubleMatrix(1, _pProjGeom->getProjectionAngleCount(), mxREAL); + double* out = mxGetPr(pAngles); + for (int i = 0; i < _pProjGeom->getProjectionAngleCount(); i++) { + out[i] = _pProjGeom->getProjectionAngle(i); + } + mGeometryInfo["ProjectionAngles"] = pAngles; + } + else { + astra::CFanFlatVecProjectionGeometry2D* pVecGeom = dynamic_cast<astra::CFanFlatVecProjectionGeometry2D*>(_pProjGeom); + mxArray* pVectors = mxCreateDoubleMatrix(1, pVecGeom->getProjectionAngleCount()*6, mxREAL); + double* out = mxGetPr(pVectors); + int iDetCount = pVecGeom->getDetectorCount(); + for (int i = 0; i < pVecGeom->getProjectionAngleCount(); i++) { + const SFanProjection* p = &pVecGeom->getProjectionVectors()[i]; + out[6*i + 0] = p->fSrcX; + out[6*i + 1] = p->fSrcY; + out[6*i + 2] = p->fDetSX + 0.5f*iDetCount*p->fDetUX; + out[6*i + 3] = p->fDetSY + 0.5f*iDetCount*p->fDetUY; + out[6*i + 4] = p->fDetUX; + out[6*i + 5] = p->fDetUY; + } + mGeometryInfo["Vectors"] = pVectors; + } + + // parallel specific options + if (_pProjGeom->isOfType("parallel")) { + // type + mGeometryInfo["type"] = mxCreateString("parallel"); + } + // fanflat specific options + else if (_pProjGeom->isOfType("fanflat")) { + astra::CFanFlatProjectionGeometry2D* pFanFlatGeom = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(_pProjGeom); + // detectorCount + mGeometryInfo["DistanceOriginSource"] = mxCreateDoubleScalar(pFanFlatGeom->getOriginSourceDistance()); + // detectorWidth + mGeometryInfo["DistanceOriginDetector"] = mxCreateDoubleScalar(pFanFlatGeom->getOriginDetectorDistance()); + // type + mGeometryInfo["type"] = mxCreateString("fanflat"); + } + else if (_pProjGeom->isOfType("sparse_matrix")) { + astra::CSparseMatrixProjectionGeometry2D* pSparseMatrixGeom = dynamic_cast<astra::CSparseMatrixProjectionGeometry2D*>(_pProjGeom); + mGeometryInfo["type"] = mxCreateString("sparse_matrix"); + mGeometryInfo["MatrixID"] = mxCreateDoubleScalar(CMatrixManager::getSingleton().getIndex(pSparseMatrixGeom->getMatrix())); + } + else if(_pProjGeom->isOfType("fanflat_vec")) { + mGeometryInfo["type"] = mxCreateString("fanflat_vec"); + } + + // build and return the MATLAB struct + return buildStruct(mGeometryInfo); +} + +//----------------------------------------------------------------------------------------- +// parse reconstruction geometry data +astra::CVolumeGeometry2D* parseVolumeGeometryStruct(const mxArray* prhs) +{ + // parse struct + std::map<string, mxArray*> mStruct = parseStruct(prhs); + + std::map<string, mxArray*> mOptions = parseStruct(mStruct["option"]); + + // GridColCount + int iWindowColCount = 128; + mxArray* tmp = mStruct["GridColCount"]; + if (tmp != NULL) { + iWindowColCount = (int)(mxGetScalar(tmp)); + } + + // GridRowCount + int iWindowRowCount = 128; + tmp = mStruct["GridRowCount"]; + if (tmp != NULL) { + iWindowRowCount = (int)(mxGetScalar(tmp)); + } + + // WindowMinX + float32 fWindowMinX = - iWindowColCount / 2; + tmp = mOptions["WindowMinX"]; + if (tmp != NULL) { + fWindowMinX = (float32)(mxGetScalar(tmp)); + } + + // WindowMaxX + float32 fWindowMaxX = iWindowColCount / 2; + tmp = mOptions["WindowMaxX"]; + if (tmp != NULL) { + fWindowMaxX = (float32)(mxGetScalar(tmp)); + } + + // WindowMinY + float32 fWindowMinY = - iWindowRowCount / 2; + tmp = mOptions["WindowMinY"]; + if (tmp != NULL) { + fWindowMinY = (float32)(mxGetScalar(tmp)); + } + + // WindowMaxX + float32 fWindowMaxY = iWindowRowCount / 2; + tmp = mOptions["WindowMaxY"]; + if (tmp != NULL) { + fWindowMaxY = (float32)(mxGetScalar(tmp)); + } + + // create and return reconstruction geometry + return new astra::CVolumeGeometry2D(iWindowColCount, iWindowRowCount, + fWindowMinX, fWindowMinY, + fWindowMaxX, fWindowMaxY); +} + +//----------------------------------------------------------------------------------------- +// create reconstruction geometry data +mxArray* createVolumeGeometryStruct(astra::CVolumeGeometry2D* _pReconGeom) +{ + // temporary map to store the data for the MATLAB struct + std::map<std::string, mxArray*> mGeometryInfo; + + // fill up map + mGeometryInfo["GridColCount"] = mxCreateDoubleScalar(_pReconGeom->getGridColCount()); + mGeometryInfo["GridRowCount"] = mxCreateDoubleScalar(_pReconGeom->getGridRowCount()); + + std::map<std::string, mxArray*> mGeometryOptions; + mGeometryOptions["WindowMinX"] = mxCreateDoubleScalar(_pReconGeom->getWindowMinX()); + mGeometryOptions["WindowMaxX"] = mxCreateDoubleScalar(_pReconGeom->getWindowMaxX()); + mGeometryOptions["WindowMinY"] = mxCreateDoubleScalar(_pReconGeom->getWindowMinY()); + mGeometryOptions["WindowMaxY"] = mxCreateDoubleScalar(_pReconGeom->getWindowMaxY()); + + mGeometryInfo["option"] = buildStruct(mGeometryOptions); + + // build and return the MATLAB struct + return buildStruct(mGeometryInfo); +} + + +//----------------------------------------------------------------------------------------- +string matlab2string(const mxArray* pField) +{ + // is string? + if (mxIsChar(pField)) { + return mex_util_get_string(pField); + } + + // is scalar? + if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) == 1) { + return boost::lexical_cast<string>(mxGetScalar(pField)); + } + + return ""; +} + +//----------------------------------------------------------------------------------------- +// Options struct to xml node +bool readOptions(XMLNode* node, const mxArray* pOptionStruct) +{ + // loop all fields + int nfields = mxGetNumberOfFields(pOptionStruct); + for (int i = 0; i < nfields; i++) { + std::string sFieldName = std::string(mxGetFieldNameByNumber(pOptionStruct, i)); + const mxArray* pField = mxGetFieldByNumber(pOptionStruct, 0, i); + + if (node->hasOption(sFieldName)) { + mexErrMsgTxt("Duplicate option"); + return false; + } + + // string or scalar + if (mxIsChar(pField) || mex_is_scalar(pField)) { + string sValue = matlab2string(pField); + node->addOption(sFieldName, sValue); + } else + // numerical array + if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) > 1) { + if (!mxIsDouble(pField)) { + mexErrMsgTxt("Numeric input must be double."); + return false; + } + + XMLNode* listbase = node->addChildNode("Option"); + listbase->addAttribute("key", sFieldName); + listbase->addAttribute("listsize", mxGetM(pField)*mxGetN(pField)); + double* pdValues = mxGetPr(pField); + int index = 0; + for (unsigned int row = 0; row < mxGetM(pField); row++) { + for (unsigned int col = 0; col < mxGetN(pField); col++) { + XMLNode* item = listbase->addChildNode("ListItem"); + item->addAttribute("index", index); + item->addAttribute("value", pdValues[col*mxGetM(pField)+row]); + index++; + delete item; + } + } + delete listbase; + } else { + mexErrMsgTxt("Unsupported option type"); + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------------------- +// struct to xml node +bool readStruct(XMLNode* root, const mxArray* pStruct) +{ + // loop all fields + int nfields = mxGetNumberOfFields(pStruct); + for (int i = 0; i < nfields; i++) { + + // field and fieldname + std::string sFieldName = std::string(mxGetFieldNameByNumber(pStruct, i)); + const mxArray* pField = mxGetFieldByNumber(pStruct, 0, i); + + // string + if (mxIsChar(pField)) { + string sValue = matlab2string(pField); + if (sFieldName == "type") { + root->addAttribute("type", sValue); + } else { + delete root->addChildNode(sFieldName, sValue); + } + } + + // scalar + if (mex_is_scalar(pField)) { + string sValue = matlab2string(pField); + delete root->addChildNode(sFieldName, sValue); + } + + // numerical array + if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) > 1) { + if (!mxIsDouble(pField)) { + mexErrMsgTxt("Numeric input must be double."); + return false; + } + XMLNode* listbase = root->addChildNode(sFieldName); + listbase->addAttribute("listsize", mxGetM(pField)*mxGetN(pField)); + double* pdValues = mxGetPr(pField); + int index = 0; + for (unsigned int row = 0; row < mxGetM(pField); row++) { + for (unsigned int col = 0; col < mxGetN(pField); col++) { + XMLNode* item = listbase->addChildNode("ListItem"); + item->addAttribute("index", index); + item->addAttribute("value", pdValues[col*mxGetM(pField)+row]); + index++; + delete item; + } + } + delete listbase; + } + + + // not castable to a single string + if (mxIsStruct(pField)) { + if (sFieldName == "options" || sFieldName == "option" || sFieldName == "Options" || sFieldName == "Option") { + bool ret = readOptions(root, pField); + if (!ret) + return false; + } else { + XMLNode* newNode = root->addChildNode(sFieldName); + bool ret = readStruct(newNode, pField); + delete newNode; + if (!ret) + return false; + } + } + + } + + return true; +} + +//----------------------------------------------------------------------------------------- +// turn a MATLAB struct into an XML Document +XMLDocument* struct2XML(string rootname, const mxArray* pStruct) +{ + if (!mxIsStruct(pStruct)) { + mexErrMsgTxt("Input must be a struct."); + return NULL; + } + + // create the document + XMLDocument* doc = XMLDocument::createDocument(rootname); + XMLNode* rootnode = doc->getRootNode(); + + // read the struct + bool ret = readStruct(rootnode, pStruct); + //doc->getRootNode()->print(); + delete rootnode; + + if (!ret) { + delete doc; + doc = 0; + } + + return doc; +} + + + + + +//----------------------------------------------------------------------------------------- +// turn an std vector<float32> object to an mxArray +mxArray* vectorToMxArray(std::vector<astra::float32> mInput) +{ + mxArray* res = mxCreateDoubleMatrix(1, mInput.size(), mxREAL); + double* pdData = mxGetPr(res); + for (unsigned int i = 0; i < mInput.size(); i++) { + pdData[i] = mInput[i]; + } + return res; +} + +//----------------------------------------------------------------------------------------- +// turn a vector<vector<float32>> object to an mxArray +mxArray* vector2DToMxArray(std::vector<std::vector<astra::float32> > mInput) +{ + unsigned int sizex = mInput.size(); + if (sizex == 0) return mxCreateString("empty"); + unsigned int sizey = mInput[0].size(); + + mxArray* res = mxCreateDoubleMatrix(sizex, sizey, mxREAL); + double* pdData = mxGetPr(res); + for (unsigned int i = 0; i < sizex; i++) { + for (unsigned int j = 0; j < sizey && j < mInput[i].size(); j++) { + pdData[j*sizex+i] = mInput[i][j]; + } + } + return res; +} + +//----------------------------------------------------------------------------------------- +// turn a boost::any object to an mxArray +mxArray* anyToMxArray(boost::any _any) +{ + if (_any.type() == typeid(std::string)) { + std::string str = boost::any_cast<std::string>(_any); + return mxCreateString(str.c_str()); + } + if (_any.type() == typeid(int)) { + return mxCreateDoubleScalar(boost::any_cast<int>(_any)); + } + if (_any.type() == typeid(float32)) { + return mxCreateDoubleScalar(boost::any_cast<float32>(_any)); + } + if (_any.type() == typeid(std::vector<astra::float32>)) { + return vectorToMxArray(boost::any_cast<std::vector<float32> >(_any)); + } + if (_any.type() == typeid(std::vector<std::vector<astra::float32> >)) { + return vector2DToMxArray(boost::any_cast<std::vector<std::vector<float32> > >(_any)); + } + return NULL; +} +//----------------------------------------------------------------------------------------- +// return true ig the argument is a scalar +bool mex_is_scalar(const mxArray* pInput) +{ + return (mxIsNumeric(pInput) && mxGetM(pInput)*mxGetN(pInput) == 1); +} + +//----------------------------------------------------------------------------------------- +mxArray* XML2struct(astra::XMLDocument* xml) +{ + XMLNode* node = xml->getRootNode(); + mxArray* str = XMLNode2struct(xml->getRootNode()); + delete node; + return str; +} + +//----------------------------------------------------------------------------------------- +mxArray* XMLNode2struct(astra::XMLNode* node) +{ + std::map<std::string, mxArray*> mList; + + // type_attribute + if (node->hasAttribute("type")) { + mList["type"] = mxCreateString(node->getAttribute("type").c_str()); + } + + list<XMLNode*> nodes = node->getNodes(); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + XMLNode* subnode = (*it); + // list + if (subnode->hasAttribute("listsize")) { + cout << "lkmdsqldqsjkl" << endl; + cout << " " << node->getContentNumericalArray().size() << endl; + mList[subnode->getName()] = vectorToMxArray(node->getContentNumericalArray()); + } + // string + else { + mList[subnode->getName()] = mxCreateString(subnode->getContent().c_str()); + } + delete subnode; + } + + return buildStruct(mList); +} + +void get3DMatrixDims(const mxArray* x, mwSize *dims) +{ + const mwSize* mdims = mxGetDimensions(x); + mwSize dimCount = mxGetNumberOfDimensions(x); + if (dimCount == 1) { + dims[0] = mdims[0]; + dims[1] = 1; + dims[2] = 1; + } else if (dimCount == 2) { + dims[0] = mdims[0]; + dims[1] = mdims[1]; + dims[2] = 1; + } else if (dimCount == 3) { + dims[0] = mdims[0]; + dims[1] = mdims[1]; + dims[2] = mdims[2]; + } else { + dims[0] = 0; + dims[1] = 0; + dims[2] = 0; + } +} diff --git a/matlab/mex/mexHelpFunctions.h b/matlab/mex/mexHelpFunctions.h new file mode 100644 index 0000000..425b4ef --- /dev/null +++ b/matlab/mex/mexHelpFunctions.h @@ -0,0 +1,76 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _INC_ASTRA_MEX_HELPFUNCTIONS +#define _INC_ASTRA_MEX_HELPFUNCTIONS + +#include <string> +#include <list> +#include <iostream> +#include <sstream> +#include <map> +#include <algorithm> +#include <mex.h> + +#include <boost/lexical_cast.hpp> +#include <boost/any.hpp> + +#include "astra/Globals.h" +#include "astra/Utilities.h" + +#include "astra/ParallelProjectionGeometry2D.h" +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/VolumeGeometry2D.h" + +#include "astra/XMLDocument.h" +#include "astra/XMLNode.h" + +std::string mex_util_get_string(const mxArray* pInput); +bool isOption(std::list<std::string> lOptions, std::string sOption); + +bool mex_is_scalar(const mxArray* pInput); + +std::map<std::string, mxArray*> parseStruct(const mxArray* pInput); +mxArray* buildStruct(std::map<std::string, mxArray*> mInput); +mxArray* vectorToMxArray(std::vector<astra::float32> mInput); + +mxArray* anyToMxArray(boost::any _any); + +astra::CProjectionGeometry2D* parseProjectionGeometryStruct(const mxArray*); +mxArray* createProjectionGeometryStruct(astra::CProjectionGeometry2D*); +astra::CVolumeGeometry2D* parseVolumeGeometryStruct(const mxArray*); +mxArray* createVolumeGeometryStruct(astra::CVolumeGeometry2D* _pReconGeom); + +astra::XMLDocument* struct2XML(string rootname, const mxArray* pStruct); + +mxArray* XML2struct(astra::XMLDocument* xml); +mxArray* XMLNode2struct(astra::XMLNode* xml); + +void get3DMatrixDims(const mxArray* x, mwSize *dims); + +#endif diff --git a/matlab/tools/ROIselectfull.m b/matlab/tools/ROIselectfull.m new file mode 100644 index 0000000..a50c979 --- /dev/null +++ b/matlab/tools/ROIselectfull.m @@ -0,0 +1,18 @@ +function V_out = ROIselectfull(input, ROI) + + s1 = size(input,1); + s2 = size(input,2); + [x y] = meshgrid(-(s2-1)/2:(s2-1)/2,(s1-1)/2:-1:-(s1-1)/2); + A = Afstand(x,y,0,0); + + V_out = zeros(size(input)); + for slice = 1:size(input,3); + V = input(:,:,slice); + V(A > ROI/2) = 0; + V_out(:,:,slice) = V; + end +end + +function A = Afstand(x1,y1,x2,y2) + A = sqrt((x1-x2).^2+(y1-y2).^2); +end
\ No newline at end of file diff --git a/matlab/tools/astra_add_noise_to_sino.m b/matlab/tools/astra_add_noise_to_sino.m new file mode 100644 index 0000000..a262f49 --- /dev/null +++ b/matlab/tools/astra_add_noise_to_sino.m @@ -0,0 +1,47 @@ +function sinogram_out = astra_add_noise_to_sino(sinogram_in,I0) + +%-------------------------------------------------------------------------- +% sinogram_out = astra_add_noise_to_sino(sinogram_in,I0) +% +% Add poisson noise to a sinogram. +% +% sinogram_in: input sinogram, can be either MATLAB-data or an +% astra-identifier. In the latter case, this operation is inplace and the +% result will also be stored in this data object. +% I0: background intensity, used to set noise level, lower equals more +% noise +% sinogram_out: output sinogram in MATLAB-data. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +if numel(sinogram_in) == 1 + sinogramRaw = astra_mex_data2d('get', sinogram_in); +else + sinogramRaw = sinogram_in; +end + +% scale to [0,1] +max_sinogramRaw = max(sinogramRaw(:)); +sinogramRawScaled = sinogramRaw ./ max_sinogramRaw; +% to detector count +sinogramCT = I0 * exp(-sinogramRawScaled); +% add poison noise +sinogramCT_A = sinogramCT * 1e-12; +sinogramCT_B = double(imnoise(sinogramCT_A, 'poisson')); +sinogramCT_C = sinogramCT_B * 1e12; +% to density +sinogramCT_D = sinogramCT_C / I0; +sinogram_out = -max_sinogramRaw * log(sinogramCT_D); + +if numel(sinogram_in) == 1 + astra_mex_data2d('store', sinogram_in, sinogram_out); +end diff --git a/matlab/tools/astra_clear.m b/matlab/tools/astra_clear.m new file mode 100644 index 0000000..d42e395 --- /dev/null +++ b/matlab/tools/astra_clear.m @@ -0,0 +1,19 @@ +%-------------------------------------------------------------------------- +% Clears and frees memory of all objects (data, projectors, algorithms) +% currently in the astra-library. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +astra_mex_data2d('clear'); +astra_mex_data3d('clear'); +astra_mex_algorithm('clear'); +astra_mex_projector('clear'); diff --git a/matlab/tools/astra_create_backprojection.m b/matlab/tools/astra_create_backprojection.m new file mode 100644 index 0000000..7f0b02f --- /dev/null +++ b/matlab/tools/astra_create_backprojection.m @@ -0,0 +1,63 @@ +function [vol_id, vol] = astra_create_backprojection(data, proj_id) + +%-------------------------------------------------------------------------- +% [vol_id, vol] = astra_create_backprojection(data, proj_id) +% +% Create a CPU based back projection. +% +% data: input sinogram, can be either MATLAB-data or an astra-identifier. +% proj_id: identifier of the projector as it is stored in the astra-library +% vol_id: identifier of the volume data object as it is now stored in the astra-library. +% vol: MATLAB data version of the volume +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% get projection geometry +proj_geom = astra_mex_projector('projection_geometry', proj_id); +vol_geom = astra_mex_projector('volume_geometry', proj_id); + +% store sinogram +if (numel(data) > 1) + sino_id = astra_mex_data2d('create','-sino', proj_geom, data); +else + sino_id = data; +end + +% store volume +vol_id = astra_mex_data2d('create','-vol', vol_geom, 0); + +if astra_mex_projector('is_cuda', proj_id) + cfg = astra_struct('BP_CUDA'); +else + cfg = astra_struct('BP'); +end + +cfg.ProjectorId = proj_id; +cfg.ProjectionDataId = sino_id; +cfg.ReconstructionDataId = vol_id; + +% create backprojection +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data2d('delete', sino_id); +end + +if nargout >= 2 + vol = astra_mex_data2d('get',vol_id); +end + + + diff --git a/matlab/tools/astra_create_backprojection3d_cuda.m b/matlab/tools/astra_create_backprojection3d_cuda.m new file mode 100644 index 0000000..afa41db --- /dev/null +++ b/matlab/tools/astra_create_backprojection3d_cuda.m @@ -0,0 +1,54 @@ +function [vol_id, vol] = astra_create_backprojection3d_cuda(data, proj_geom, vol_geom) + +%-------------------------------------------------------------------------- +% [vol_id, vol] = astra_create_backprojection3d_cuda(data, proj_geom, vol_geom) +% +% Create a GPU based backprojection. +% +% data: input projection data, can be either MATLAB-data or an astra-identifier. +% proj_geom: MATLAB struct containing the projection geometry. +% vol_geom: MATLAB struct containing the volume geometry. +% vol_id: identifier of the volume data object as it is now stored in +% the astra-library. +% vol: MATLAB data version of the volume. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% store projection data +if (numel(data) > 1) + sino_id = astra_mex_data3d('create','-proj3d', proj_geom, data); +else + sino_id = data; +end + +% store volume +vol_id = astra_mex_data3d('create','-vol', vol_geom, 0); + +% create sinogram +cfg = astra_struct('BP3D_CUDA'); +cfg.ProjectionDataId = sino_id; +cfg.ReconstructionDataId = vol_id; +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data3d('delete', sino_id); +end + +if nargout >= 2 + vol = astra_mex_data3d('get',vol_id); +end + + + diff --git a/matlab/tools/astra_create_backprojection_cuda.m b/matlab/tools/astra_create_backprojection_cuda.m new file mode 100644 index 0000000..cef7864 --- /dev/null +++ b/matlab/tools/astra_create_backprojection_cuda.m @@ -0,0 +1,39 @@ +function backProj = astra_create_backprojection_cuda(sinogramData, proj_geom, vol_geom) + %-------------------------------------------------------------------------- + % backProj = astra_create_backprojection_cuda(sinogramData, proj_geom, vol_geom) + % + % Creates a CUDA-based simple backprojection + % + % sinogramData: 2D matrix with projections stored row-based + % theta: projection angles, length should be equal to the number of rows in + % sinogramData + % reconstructionSize: vector with length 2 with the row and column count of + % the reconstruction image + % backProj: 2D back projection from sinogram data + %-------------------------------------------------------------------------- + %------------------------------------------------------------------------ + % This file is part of the + % All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") + % + % Copyright: iMinds-Vision Lab, University of Antwerp + % License: Open Source under GPLv3 + % Contact: mailto:astra@ua.ac.be + % Website: http://astra.ua.ac.be + %------------------------------------------------------------------------ + % $Id$ + + recon_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogramData); + + cfg = astra_struct('BP_CUDA'); + cfg.ProjectionDataId = sinogram_id; + cfg.ReconstructionDataId = recon_id; + + alg_id = astra_mex_algorithm('create', cfg); + astra_mex_algorithm('run', alg_id); + backProj = astra_mex_data2d('get', recon_id); + + astra_mex_data2d('delete', sinogram_id); + astra_mex_data2d('delete', recon_id); + astra_mex_algorithm('delete', alg_id); +end diff --git a/matlab/tools/astra_create_fbp_reconstruction.m b/matlab/tools/astra_create_fbp_reconstruction.m new file mode 100644 index 0000000..4456f9c --- /dev/null +++ b/matlab/tools/astra_create_fbp_reconstruction.m @@ -0,0 +1,23 @@ +function [FBP_id, FBP] = astra_create_fbp_reconstruction(sinogram, proj_id) + +proj_geom = astra_mex_projector('projection_geometry', proj_id); +vol_geom = astra_mex_projector('volume_geometry', proj_id); + +if numel(sinogram) == 1 + sinogram_id = sinogram; +else + sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram); +end + +FBP_id = astra_mex_data2d('create','-vol',vol_geom, 0); + +cfg = astra_struct('FBP_CUDA'); +cfg.ProjectionDataId = sinogram_id; +cfg.ReconstructionDataId = FBP_id; +cfg.FilterType = 'Ram-Lak'; +cfg.ProjectorId = proj_id; +cfg.Options.GPUindex = 0; +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('run', alg_id); + +FBP = astra_mex_data2d('get', FBP_id); diff --git a/matlab/tools/astra_create_proj_geom.m b/matlab/tools/astra_create_proj_geom.m new file mode 100644 index 0000000..dbf0464 --- /dev/null +++ b/matlab/tools/astra_create_proj_geom.m @@ -0,0 +1,204 @@ +function proj_geom = astra_create_proj_geom(type, varargin) + +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('parallel', det_width, det_count, angles) +% +% Create a 2D parallel beam geometry. See the API for more information. +% det_width: distance between two adjacent detectors +% det_count: number of detectors in a single projection +% angles: projection angles in radians, should be between -pi/4 and 7pi/4 +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('parallel3d', det_spacing_x, det_spacing_y, det_row_count, det_col_count, angles) +% +% Create a 3D parallel beam geometry. See the API for more information. +% det_spacing_x: distance between two horizontally adjacent detectors +% det_spacing_y: distance between two vertically adjacent detectors +% det_row_count: number of detector rows in a single projection +% det_col_count: number of detector columns in a single projection +% angles: projection angles in radians, should be between -pi/4 and 7pi/4 +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('fanflat', det_width, det_count, angles, source_origin, origin_det) +% +% Create a 2D flat fan beam geometry. See the API for more information. +% det_width: distance between two adjacent detectors +% det_count: number of detectors in a single projection +% angles: projection angles in radians, should be between -pi/4 and 7pi/4 +% source_origin: distance between the source and the center of rotation +% origin_det: distance between the center of rotation and the detector array +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('fanflat_vec', det_count, vectors) +% +% Create a 2D flat fan beam geometry specified by 2D vectors. +% See the API for more information. +% det_count: number of detectors in a single projection +% vectors: a matrix containing the actual geometry. Each row corresponds +% to a single projection, and consists of: +% ( srcX, srcY, dX, dY, uX, uY ) +% src: the ray source +% d : the center of the detector +% u : the vector from detector pixel 0 to 1 +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('cone', det_spacing_x, det_spacing_y, det_row_count, det_col_count, angles, source_origin, origin_det) +% +% Create a 3D cone beam geometry. See the API for more information. +% det_spacing_x: distance between two horizontally adjacent detectors +% det_spacing_y: distance between two vertically adjacent detectors +% det_row_count: number of detector rows in a single projection +% det_col_count: number of detector columns in a single projection +% angles: projection angles in radians, should be between -pi/4 and 7pi/4 +% source_origin: distance between the source and the center of rotation +% origin_det: distance between the center of rotation and the detector array +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('cone_vec', det_row_count, det_col_count, vectors) +% +% Create a 3D cone beam geometry specified by 3D vectors. +% See the API for more information. +% det_row_count: number of detector rows in a single projection +% det_col_count: number of detector columns in a single projection +% vectors: a matrix containing the actual geometry. Each row corresponds +% to a single projection, and consists of: +% ( srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ ) +% src: the ray source +% d : the center of the detector +% u : the vector from detector pixel (0,0) to (0,1) +% v : the vector from detector pixel (0,0) to (1,0) +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +% proj_geom = astra_create_proj_geom('parallel3d_vec', det_row_count, det_col_count, vectors) +% +% Create a 3D parallel beam geometry specified by 3D vectors. +% See the API for more information. +% det_row_count: number of detector rows in a single projection +% det_col_count: number of detector columns in a single projection +% vectors: a matrix containing the actual geometry. Each row corresponds +% to a single projection, and consists of: +% ( rayX, rayY, rayZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ ) +% ray: the ray direction +% d : the center of the detector +% u : the vector from detector pixel (0,0) to (0,1) +% v : the vector from detector pixel (0,0) to (1,0) +% proj_geom: MATLAB struct containing all information of the geometry +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +if strcmp(type,'parallel') + if numel(varargin) < 3 + error('not enough variables: astra_create_proj_geom(parallel, detector_spacing, det_count, angles)'); + end + proj_geom = struct( ... + 'type', 'parallel', ... + 'DetectorWidth', varargin{1}, ... + 'DetectorCount', varargin{2}, ... + 'ProjectionAngles', varargin{3} ... + ); + +elseif strcmp(type,'fanflat') + if numel(varargin) < 5 + error('not enough variables: astra_create_proj_geom(fanflat, det_width, det_count, angles, source_origin, source_det)'); + end + proj_geom = struct( ... + 'type', 'fanflat', ... + 'DetectorWidth', varargin{1}, ... + 'DetectorCount', varargin{2}, ... + 'ProjectionAngles', varargin{3}, ... + 'DistanceOriginSource', varargin{4}, ... + 'DistanceOriginDetector', varargin{5} ... + ); + +elseif strcmp(type,'fanflat_vec') + if numel(varargin) < 2 + error('not enough variables: astra_create_proj_geom(fanflat_vec, det_count, V') + end + if size(varargin{2}, 2) ~= 6 + error('V should be a Nx6 matrix, with N the number of projections') + end + proj_geom = struct( ... + 'type', 'fanflat_vec', ... + 'DetectorCount', varargin{1}, ... + 'Vectors', varargin{2} ... + ); + +elseif strcmp(type,'parallel3d') + if numel(varargin) < 5 + error('not enough variables: astra_create_proj_geom(parallel3d, detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles)'); + end + proj_geom = struct( ... + 'type', 'parallel3d', ... + 'DetectorSpacingX', varargin{1}, ... + 'DetectorSpacingY', varargin{2}, ... + 'DetectorRowCount', varargin{3}, ... + 'DetectorColCount', varargin{4}, ... + 'ProjectionAngles', varargin{5} ... + ); +elseif strcmp(type,'cone') + if numel(varargin) < 7 + error('not enough variables: astra_create_proj_geom(cone, detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, source_det)'); + end + proj_geom = struct( ... + 'type', 'cone', ... + 'DetectorSpacingX', varargin{1}, ... + 'DetectorSpacingY', varargin{2}, ... + 'DetectorRowCount', varargin{3}, ... + 'DetectorColCount', varargin{4}, ... + 'ProjectionAngles', varargin{5}, ... + 'DistanceOriginSource', varargin{6}, ... + 'DistanceOriginDetector',varargin{7} ... + ); +elseif strcmp(type,'cone_vec') + if numel(varargin) < 3 + error('not enough variables: astra_create_proj_geom(cone_vec, det_row_count, det_col_count, V') + end + if size(varargin{3}, 2) ~= 12 + error('V should be a Nx12 matrix, with N the number of projections') + end + proj_geom = struct( ... + 'type', 'cone_vec', ... + 'DetectorRowCount', varargin{1}, ... + 'DetectorColCount', varargin{2}, ... + 'Vectors', varargin{3} ... + ); +elseif strcmp(type,'parallel3d_vec') + if numel(varargin) < 3 + error('not enough variables: astra_create_proj_geom(parallel3d_vec, det_row_count, det_col_count, V') + end + if size(varargin{3}, 2) ~= 12 + error('V should be a Nx12 matrix, with N the number of projections') + end + proj_geom = struct( ... + 'type', 'parallel3d_vec', ... + 'DetectorRowCount', varargin{1}, ... + 'DetectorColCount', varargin{2}, ... + 'Vectors', varargin{3} ... + ); +elseif strcmp(type,'sparse_matrix') + if numel(varargin) < 3 + error('not enough variables: astra_create_proj_geom(sparse_matrix, det_width, det_count, angles, matrix_id)') + end + proj_geom = struct( ... + 'type', 'sparse_matrix', ... + 'DetectorWidth', varargin{1}, ... + 'DetectorCount', varargin{2}, ... + 'ProjectionAngles', varargin{3}, ... + 'MatrixID', varargin{4} ... + ); + +else + disp(['Error: unknown type ' type]); + proj_geom = struct(); +end + diff --git a/matlab/tools/astra_create_projector.m b/matlab/tools/astra_create_projector.m new file mode 100644 index 0000000..f773d0d --- /dev/null +++ b/matlab/tools/astra_create_projector.m @@ -0,0 +1,50 @@ +function proj_id = astra_create_projector(type, proj_geom, vol_geom) + +%-------------------------------------------------------------------------- +% proj_id = astra_create_projector(type, proj_geom, vol_geom) +% +% Create a new projector object based on projection and volume geometry. +% Used when the default values of each projector are sufficient. +% +% type: type of the projector. 'blob', 'line', 'linear' 'strip', ... See API for more information. +% proj_geom: MATLAB struct containing the projection geometry. +% vol_geom: MATLAB struct containing the volume geometry. +% proj_id: identifier of the projector as it is now stored in the astra-library. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +cfg_proj = astra_struct(type); +cfg_proj.ProjectionGeometry = proj_geom; +cfg_proj.VolumeGeometry = vol_geom; + +if strcmp(type,'blob') + % Blob options + blob_size = 2; + blob_sample_rate = 0.01; + blob_values = kaiserBessel(2, 10.4, blob_size, 0:blob_sample_rate:blob_size); + cfg_proj.Kernel.KernelSize = blob_size; + cfg_proj.Kernel.SampleRate = blob_sample_rate; + cfg_proj.Kernel.SampleCount = length(blob_values); + cfg_proj.Kernel.KernelValues = blob_values; +end + +if strcmp(type,'linear3d') || strcmp(type,'linearcone') || strcmp(type,'cuda3d') + proj_id = astra_mex_projector3d('create', cfg_proj); +else + proj_id = astra_mex_projector('create', cfg_proj); +end + + + + + diff --git a/matlab/tools/astra_create_reconstruction.m b/matlab/tools/astra_create_reconstruction.m new file mode 100644 index 0000000..15e452c --- /dev/null +++ b/matlab/tools/astra_create_reconstruction.m @@ -0,0 +1,97 @@ +function [recon_id, recon] = astra_create_reconstruction(rec_type, proj_id, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc) + +%-------------------------------------------------------------------------- +% [recon_id, recon] = astra_create_reconstruction(rec_type, proj_id, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc) +% +% Create a CPU based iterative reconstruction. +% +% rec_type: reconstruction type, 'ART', 'SART' 'SIRT' or 'CGLS', not all options are adjustable +% proj_id: identifier of the projector as it is stored in the astra-library +% sinogram: sinogram data OR sinogram identifier +% iterations: number of iterations to perform +% use_mask: use a reconstrucionmask? 'yes' or 'no' +% mask: mask data OR mask identifier. +% use_minc: use a minimum constraint? 'yes' or 'no' +% minc: minimum constraint value +% use_maxc: use a maximum constraint? 'yes' or 'no' +% maxc: maximum constraint value +% recon_id: identifier of the reconstruction data object as it is now stored in the astra-library +% recon: MATLAB data version of the reconstruction +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +if nargin <= 4 + use_mask = 'no'; + mask = []; + use_minc = 'no'; + minc = 0; + use_maxc = 'no'; + maxc = 255; +end + +if nargin <= 6 + use_minc = 'no'; + minc = 0; + use_maxc = 'no'; + maxc = 255; +end + +if numel(sinogram) == 1 + sinogram_id = sinogram; +else + proj_geom = astra_mex_projector('projection_geometry', proj_id); + sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram); +end + +% create reconstruction object +vol_geom = astra_mex_projector('volume_geometry', proj_id); +recon_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + +% configure +cfg = astra_struct(rec_type); +cfg.ProjectorId = proj_id; +cfg.ProjectionDataId = sinogram_id; +cfg.ReconstructionDataId = recon_id; +if strcmp(use_mask,'yes') + if numel(mask) == 1 + mask_id = mask; + else + mask_id = astra_mex_data2d('create', '-vol', vol_geom, mask); + end + cfg.options.ReconstructionMaskId = mask_id; +end +cfg.options.UseMinConstraint = use_minc; +cfg.options.MinConstraintValue = minc; +cfg.options.UseMaxConstraint = use_maxc; +cfg.options.MaxConstraintValue = maxc; +cfg.options.ProjectionOrder = 'random'; +alg_id = astra_mex_algorithm('create', cfg); + +% iterate +astra_mex_algorithm('iterate', alg_id, iterations); + +% return object +recon = astra_mex_data2d('get', recon_id); + +% garbage collection +astra_mex_algorithm('delete', alg_id); +if numel(sinogram) ~= 1 + astra_mex_data2d('delete', sinogram_id); +end + +if strcmp(use_mask,'yes') + if numel(mask) ~= 1 + astra_mex_data2d('delete', mask_id); + end +end + diff --git a/matlab/tools/astra_create_reconstruction_cuda.m b/matlab/tools/astra_create_reconstruction_cuda.m new file mode 100644 index 0000000..b428eb5 --- /dev/null +++ b/matlab/tools/astra_create_reconstruction_cuda.m @@ -0,0 +1,80 @@ +function [recon_id, recon] = astra_create_reconstruction_cuda(rec_type, proj_geom, vol_geom, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc) + +%-------------------------------------------------------------------------- +% [recon_id, recon] = astra_create_reconstruction_cuda(rec_type, proj_geom, vol_geom, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc) +% +% Create a GPU based iterative reconstruction. +% +% rec_type: reconstruction type, only 'SIRT_CUDA' for now +% proj_geom: projection geometry struct +% vol_geom: volume geometry struct +% sinogram: sinogram data OR sinogram identifier +% iterations: number of iterations to perform +% use_mask: use a reconstrucionmask? 'yes' or 'no' +% mask: mask data OR mask identifier. +% use_minc: use a minimum constraint? 'yes' or 'no' +% minc: minimum constraint value +% use_maxc: use a maximum constraint? 'yes' or 'no' +% maxc: maximum constraint value +% recon_id: identifier of the reconstruction data object as it is now stored in the astra-library +% recon: MATLAB data version of the reconstruction +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +if numel(sinogram) == 1 + sinogram_id = sinogram; +else + sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram); +end + +% create reconstruction object +recon_id = astra_mex_data2d('create', '-vol', vol_geom, 0); + +% configure +cfg = astra_struct('SIRT_CUDA'); +cfg.ProjectionGeometry = proj_geom; +cfg.ReconstructionGeometry = vol_geom; +cfg.ProjectionDataId = sinogram_id; +cfg.ReconstructionDataId = recon_id; +if strcmp(use_mask,'yes') + if numel(mask) == 1 + mask_id = mask; + else + mask_id = astra_mex_data2d('create', '-vol', vol_geom, mask); + end + cfg.options.ReconstructionMaskId = mask_id; +end +cfg.options.UseMinConstraint = use_minc; +cfg.options.MinConstraintValue = minc; +cfg.options.UseMaxConstraint = use_maxc; +cfg.options.MaxConstraintValue = maxc; +alg_id = astra_mex_algorithm('create', cfg); + +% iterate +astra_mex_algorithm('iterate', alg_id, iterations); + +% return object +recon = astra_mex_data2d('get', recon_id); + +% garbage collection +astra_mex_algorithm('delete', alg_id); +if numel(sinogram) ~= 1 + astra_mex_data2d('delete', sinogram_id); +end + +if strcmp(use_mask,'yes') + if numel(mask) ~= 1 + astra_mex_data2d('delete', mask_id); + end +end + diff --git a/matlab/tools/astra_create_sino.m b/matlab/tools/astra_create_sino.m new file mode 100644 index 0000000..4771bd6 --- /dev/null +++ b/matlab/tools/astra_create_sino.m @@ -0,0 +1,63 @@ +function [sino_id, sino] = astra_create_sino(data, proj_id) + +%-------------------------------------------------------------------------- +% [sino_id, sino] = astra_create_sino(data, proj_id) +% +% Create a CPU based forward projection. +% +% data: input volume, can be either MATLAB-data or an astra-identifier. +% proj_id: identifier of the projector as it is stored in the astra-library +% sino_id: identifier of the sinogram data object as it is now stored in the astra-library. +% sino: MATLAB data version of the sinogram +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% get projection geometry +proj_geom = astra_mex_projector('projection_geometry', proj_id); +vol_geom = astra_mex_projector('volume_geometry', proj_id); + +% store volume +if (numel(data) > 1) + volume_id = astra_mex_data2d('create','-vol', vol_geom, data); +else + volume_id = data; +end + +% store sino +sino_id = astra_mex_data2d('create','-sino', proj_geom, 0); + +if astra_mex_projector('is_cuda', proj_id) + cfg = astra_struct('FP_CUDA'); +else + cfg = astra_struct('FP'); +end + +cfg.ProjectorId = proj_id; +cfg.ProjectionDataId = sino_id; +cfg.VolumeDataId = volume_id; + +% create sinogram +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data2d('delete', volume_id); +end + +if nargout >= 2 + sino = astra_mex_data2d('get',sino_id); +end + + + diff --git a/matlab/tools/astra_create_sino3d_cuda.m b/matlab/tools/astra_create_sino3d_cuda.m new file mode 100644 index 0000000..ef22ebe --- /dev/null +++ b/matlab/tools/astra_create_sino3d_cuda.m @@ -0,0 +1,54 @@ +function [sino_id, sino] = astra_create_sino3d_cuda(data, proj_geom, vol_geom) + +%-------------------------------------------------------------------------- +% [sino_id, sino] = astra_create_sino3d_cuda(data, proj_geom, vol_geom) +% +% Create a GPU based forward projection. +% +% data: input volume, can be either MATLAB-data or an astra-identifier. +% proj_geom: MATLAB struct containing the projection geometry. +% vol_geom: MATLAB struct containing the volume geometry. +% sino_id: identifier of the sinogram data object as it is now stored in +% the astra-library. +% sino: MATLAB data version of the sinogram. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% store volume +if (numel(data) > 1) + volume_id = astra_mex_data3d('create','-vol', vol_geom, data); +else + volume_id = data; +end + +% store sino +sino_id = astra_mex_data3d('create','-sino', proj_geom, 0); + +% create sinogram +cfg = astra_struct('FP3D_CUDA'); +cfg.ProjectionDataId = sino_id; +cfg.VolumeDataId = volume_id; +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data3d('delete', volume_id); +end + +if nargout >= 2 + sino = astra_mex_data3d('get',sino_id); +end + + + diff --git a/matlab/tools/astra_create_sino_cuda.m b/matlab/tools/astra_create_sino_cuda.m new file mode 100644 index 0000000..82bda7c --- /dev/null +++ b/matlab/tools/astra_create_sino_cuda.m @@ -0,0 +1,58 @@ +function [sino_id, sino] = astra_create_sino_cuda(data, proj_geom, vol_geom, gpu_index) + +%-------------------------------------------------------------------------- +% [sino_id, sino] = astra_create_sino_cuda(data, proj_geom, vol_geom, gpu_index) +% +% Create a GPU based forward projection. +% +% data: input volume, can be either MATLAB-data or an astra-identifier. +% proj_geom: MATLAB struct containing the projection geometry. +% vol_geom: MATLAB struct containing the volume geometry. +% gpu_index: the index of the GPU to use (optional). +% sino_id: identifier of the sinogram data object as it is now stored in +% the astra-library. +% sino: MATLAB data version of the sinogram. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% store volume +if (numel(data) > 1) + volume_id = astra_mex_data2d('create','-vol', vol_geom, data); +else + volume_id = data; +end + +% store sino +sino_id = astra_mex_data2d('create','-sino', proj_geom, 0); + +% create sinogram +cfg = astra_struct('FP_CUDA'); +cfg.ProjectionDataId = sino_id; +cfg.VolumeDataId = volume_id; +if nargin > 3 + cfg.option.GPUindex = gpu_index; +end +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data2d('delete', volume_id); +end + +if nargout >= 2 + sino = astra_mex_data2d('get',sino_id); +end + + + diff --git a/matlab/tools/astra_create_sino_gpu.m b/matlab/tools/astra_create_sino_gpu.m new file mode 100644 index 0000000..95a3b09 --- /dev/null +++ b/matlab/tools/astra_create_sino_gpu.m @@ -0,0 +1,58 @@ +function [sino_id, sino] = astra_create_sino_gpu(data, proj_geom, vol_geom, gpu_index) + +%-------------------------------------------------------------------------- +% [sino_id, sino] = astra_create_sino_gpu(data, proj_geom, vol_geom, gpu_index) +% +% Create a GPU based forward projection. +% +% data: input volume, can be either MATLAB-data or an astra-identifier. +% proj_geom: MATLAB struct containing the projection geometry. +% vol_geom: MATLAB struct containing the volume geometry. +% gpu_index: the index of the GPU to use (optional). +% sino_id: identifier of the sinogram data object as it is now stored in +% the astra-library. +% sino: MATLAB data version of the sinogram. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% store volume +if (numel(data) > 1) + volume_id = astra_mex_data2d('create','-vol', vol_geom, data); +else + volume_id = data; +end + +% store sino +sino_id = astra_mex_data2d('create','-sino', proj_geom, 0); + +% create sinogram +cfg = astra_struct('FP_CUDA'); +cfg.ProjectionDataId = sino_id; +cfg.VolumeDataId = volume_id; +if nargin > 3 + cfg.option.GPUindex = gpu_index; +end +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data2d('delete', volume_id); +end + +if nargout >= 2 + sino = astra_mex_data2d('get',sino_id); +end + + + diff --git a/matlab/tools/astra_create_sino_sampling.m b/matlab/tools/astra_create_sino_sampling.m new file mode 100644 index 0000000..6b86d61 --- /dev/null +++ b/matlab/tools/astra_create_sino_sampling.m @@ -0,0 +1,59 @@ +function [sino_id, sino] = astra_create_sino_sampling(data, proj_geom, vol_geom, gpu_index, sampling) + +%-------------------------------------------------------------------------- +% [sino_id, sino] = astra_create_sino_cuda(data, proj_geom, vol_geom, gpu_index) +% +% Create a GPU based forward projection. +% +% data: input volume, can be either MATLAB-data or an astra-identifier. +% proj_geom: MATLAB struct containing the projection geometry. +% vol_geom: MATLAB struct containing the volume geometry. +% gpu_index: the index of the GPU to use (optional). +% sino_id: identifier of the sinogram data object as it is now stored in +% the astra-library. +% sino: MATLAB data version of the sinogram. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + + +% store volume +if (numel(data) > 1) + volume_id = astra_mex_data2d('create','-vol', vol_geom, data); +else + volume_id = data; +end + +% store sino +sino_id = astra_mex_data2d('create','-sino', proj_geom, 0); + +% create sinogram +cfg = astra_struct('FP_CUDA'); +cfg.ProjectionDataId = sino_id; +cfg.VolumeDataId = volume_id; +cfg.option.DetectorSuperSampling = sampling; +if nargin > 3 + cfg.option.GPUindex = gpu_index; +end +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id); +astra_mex_algorithm('delete', alg_id); + +if (numel(data) > 1) + astra_mex_data2d('delete', volume_id); +end + +if nargout >= 2 + sino = astra_mex_data2d('get',sino_id); +end + + + diff --git a/matlab/tools/astra_create_vol_geom.m b/matlab/tools/astra_create_vol_geom.m new file mode 100644 index 0000000..61db8fb --- /dev/null +++ b/matlab/tools/astra_create_vol_geom.m @@ -0,0 +1,96 @@ +function vol_geom = astra_create_vol_geom(varargin) + +%-------------------------------------------------------------------------- +% vol_geom = astra_create_vol_geom([row_count col_count]); +% vol_geom = astra_create_vol_geom(row_count, col_count); +% vol_geom = astra_create_vol_geom(row_count, col_count, min_x, max_x, min_y, max_y); +% +% Create a 2D volume geometry. See the API for more information. +% row_count: number of rows. +% col_count: number of columns. +% min_x: minimum value on the x-axis. +% max_x: maximum value on the x-axis. +% min_y: minimum value on the y-axis. +% max_y: maximum value on the y-axis. +% vol_geom: MATLAB struct containing all information of the geometry. +%-------------------------------------------------------------------------- +% vol_geom = astra_create_vol_geom(row_count, col_count, slice_count); +% +% Create a 3D volume geometry. See the API for more information. +% row_count: number of rows. +% col_count: number of columns. +% slice_count: number of slices. +% vol_geom: MATLAB struct containing all information of the geometry. +%-------------------------------------------------------------------------- +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +% astra_create_vol_geom([row_and_col_count ]) +if numel(varargin) == 1 && numel(varargin{1}) == 1 + vol_geom = struct(); + vol_geom.GridRowCount = varargin{1}(1); + vol_geom.GridColCount = varargin{1}(1); + vol_geom.option.WindowMinX = -varargin{1}(1) / 2; + vol_geom.option.WindowMaxX = varargin{1}(1) / 2; + vol_geom.option.WindowMinY = -varargin{1}(1) / 2; + vol_geom.option.WindowMaxY = varargin{1}(1) / 2; + + +% astra_create_vol_geom([row_count col_count]) +elseif numel(varargin) == 1 && numel(varargin{1}) == 2 + vol_geom = struct(); + vol_geom.GridRowCount = varargin{1}(1); + vol_geom.GridColCount = varargin{1}(2); + vol_geom.option.WindowMinX = -varargin{1}(2) / 2; + vol_geom.option.WindowMaxX = varargin{1}(2) / 2; + vol_geom.option.WindowMinY = -varargin{1}(1) / 2; + vol_geom.option.WindowMaxY = varargin{1}(1) / 2; + +% astra_create_vol_geom([row_count col_count slice_count]) +elseif numel(varargin) == 1 && numel(varargin{1}) == 3 + vol_geom = struct(); + vol_geom.GridRowCount = varargin{1}(1); + vol_geom.GridColCount = varargin{1}(2); + vol_geom.GridSliceCount = varargin{1}(3); + vol_geom.option.WindowMinX = -varargin{1}(2) / 2; + vol_geom.option.WindowMaxX = varargin{1}(2) / 2; + vol_geom.option.WindowMinY = -varargin{1}(1) / 2; + vol_geom.option.WindowMaxY = varargin{1}(1) / 2; + vol_geom.option.WindowMinZ = -varargin{1}(3) / 2; + vol_geom.option.WindowMaxZ = varargin{1}(3) / 2; + +% astra_create_vol_geom(row_count, col_count) +elseif numel(varargin) == 2 + vol_geom = struct(); + vol_geom.GridRowCount = varargin{1}; + vol_geom.GridColCount = varargin{2}; + vol_geom.option.WindowMinX = -varargin{2} / 2; + vol_geom.option.WindowMaxX = varargin{2} / 2; + vol_geom.option.WindowMinY = -varargin{1} / 2; + vol_geom.option.WindowMaxY = varargin{1} / 2; + +% astra_create_vol_geom(row_count, col_count, min_x, max_x, min_y, max_y) +elseif numel(varargin) == 6 + vol_geom = struct(); + vol_geom.GridRowCount = varargin{1}; + vol_geom.GridColCount = varargin{2}; + vol_geom.option.WindowMinX = varargin{3}; + vol_geom.option.WindowMaxX = varargin{4}; + vol_geom.option.WindowMinY = varargin{5}; + vol_geom.option.WindowMaxY = varargin{6}; + +% astra_create_vol_geom(row_count, col_count, slice_count) +elseif numel(varargin) == 3 + vol_geom = struct(); + vol_geom.GridRowCount = varargin{1}; + vol_geom.GridColCount = varargin{2}; + vol_geom.GridSliceCount = varargin{3}; +end diff --git a/matlab/tools/astra_data_gui.fig b/matlab/tools/astra_data_gui.fig Binary files differnew file mode 100644 index 0000000..d73e430 --- /dev/null +++ b/matlab/tools/astra_data_gui.fig diff --git a/matlab/tools/astra_data_gui.m b/matlab/tools/astra_data_gui.m new file mode 100644 index 0000000..337a5d4 --- /dev/null +++ b/matlab/tools/astra_data_gui.m @@ -0,0 +1,396 @@ +function varargout = astra_data_gui(varargin) +% ASTRA_DATA_GUI M-file for ASTRA_DATA_GUI.fig +% ASTRA_DATA_GUI, by itself, creates a new ASTRA_DATA_GUI or raises the existing +% singleton*. +% +% H = ASTRA_DATA_GUI returns the handle to a new ASTRA_DATA_GUI or the handle to +% the existing singleton*. +% +% ASTRA_DATA_GUI('CALLBACK',hObject,eventData,handles,...) calls the local +% function named CALLBACK in ASTRA_DATA_GUI.M with the given input arguments. +% +% ASTRA_DATA_GUI('Property','Value',...) creates a new ASTRA_DATA_GUI or raises the +% existing singleton*. Starting from the left, property value pairs are +% applied to the GUI before ASTRA_DATA_GUI_OpeningFcn gets called. An +% unrecognized property name or invalid value makes property application +% stop. All inputs are passed to ASTRA_DATA_GUI_OpeningFcn via varargin. +% +% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one +% instance to run (singleton)". +% +% See also: GUIDE, GUIDATA, GUIHANDLES + +% Edit the above text to modify the response to help ASTRA_DATA_GUI + +% Last Modified by GUIDE v2.5 05-Mar-2012 14:34:03 + +% Begin initialization code - DO NOT EDIT +gui_Singleton = 1; +gui_State = struct('gui_Name', mfilename, ... + 'gui_Singleton', gui_Singleton, ... + 'gui_OpeningFcn', @astra_data_gui_OpeningFcn, ... + 'gui_OutputFcn', @astra_data_gui_OutputFcn, ... + 'gui_LayoutFcn', [] , ... + 'gui_Callback', []); +if nargin && ischar(varargin{1}) + gui_State.gui_Callback = str2func(varargin{1}); +end + +if nargout + [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); +else + gui_mainfcn(gui_State, varargin{:}); +end +% End initialization code - DO NOT EDIT + + +% --- Executes just before astra_data_gui is made visible. +function astra_data_gui_OpeningFcn(hObject, eventdata, handles, varargin) +% This function has no output args, see OutputFcn. +% hObject handle to figure +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) +% varargin command line arguments to astra_data_gui (see VARARGIN) + +% Choose default command line output for astra_data_gui +handles.output = hObject; +handles.data = []; + +% Update handles structure +guidata(hObject, handles); + +% UIWAIT makes astra_data_gui wait for user response (see UIRESUME) +% uiwait(handles.figure1); + + +% --- Outputs from this function are returned to the command line. +function varargout = astra_data_gui_OutputFcn(hObject, eventdata, handles) +% varargout cell array for returning output args (see VARARGOUT); +% hObject handle to figure +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + +% Get default command line output from handles structure +varargout{1} = handles.output; + + +% Use this function to display a figure using the gui from any m-file +% example: +% Handle = astra_data_gui(); +% astra_data_gui('loadVolume',guihandles(Handle),'rand(30,30,30)',15); +function loadVolume(handles,name,figure_number) +set(handles.txt_var, 'String', name); +set(handles.figure_number, 'String', num2str(figure_number)); +btn_load_Callback(handles.txt_var, [], handles); + + + + + +function txt_var_Callback(hObject, eventdata, handles) %#ok<*DEFNU> +% hObject handle to txt_var (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + +% Hints: get(hObject,'String') returns contents of txt_var as text +% str2double(get(hObject,'String')) returns contents of txt_var as a double + + +% --- Executes during object creation, after setting all properties. +function txt_var_CreateFcn(hObject, eventdata, handles) +% hObject handle to txt_var (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles empty - handles not created until after all CreateFcns called + +% Hint: edit controls usually have a white background on Windows. +% See ISPC and COMPUTER. +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + + +% --- Executes on button press in btn_load. +function btn_load_Callback(hObject, eventdata, handles) +% hObject handle to btn_load (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + +s = get(handles.txt_var, 'String'); +data = evalin('base', s); +handles.data = data; +guidata(hObject, handles); + +% Set Default Stuff +set(handles.sld_slice, 'Min',1); +set(handles.sld_slice, 'Max', size(data,3)); +set(handles.sld_slice, 'SliderStep', [1/(size(data,3)-2) 1/(size(data,3)-2)]); +set(handles.sld_slice, 'Value', size(data,3)/2); + +sliderValue = floor(get(handles.sld_slice, 'Value')); +set(handles.txt_slice, 'String', num2str(sliderValue)); +set(handles.txt_min, 'String', num2str(1)); +set(handles.txt_max, 'String', num2str(size(data,3))); + +set(handles.sld_magnification, 'Min',1); +set(handles.sld_magnification, 'Max', 400); +set(handles.sld_magnification, 'SliderStep', [1/(400-2) 1/(400-2)]); +set(handles.sld_magnification, 'Value', 100); + +sliderValue3 = floor(get(handles.sld_magnification, 'Value')); +set(handles.txt_mag, 'String', num2str(sliderValue3)); + + +figure_number = floor(str2double(get(handles.figure_number, 'String'))); +if(isnan(figure_number) || figure_number < 1) + set(handles.figure_number, 'String', num2str(10)); +end + +showimage(handles); + +% --- SHOW IMAGE +function showimage(handles) + sliderValue = floor(get(handles.sld_slice, 'Value')); + magnification = floor(get(handles.sld_magnification, 'Value')); + figure_number = floor(str2double(get(handles.figure_number, 'String'))); + image_matrix = handles.data; + if get(handles.btn_x, 'Value') == 1 + figure(figure_number), imshow(sliceExtractor((image_matrix(:,:,:)), 'y', sliderValue),[],'InitialMagnification', magnification); + ylabel('y') + xlabel('z') + set(gcf,'Name','ASTRA DATA GUI') + elseif get(handles.btn_y, 'Value') == 1 + figure(figure_number), imshow(sliceExtractor((image_matrix(:,:,:)), 'x', sliderValue),[],'InitialMagnification', magnification); + ylabel('x') + xlabel('z') + set(gcf,'Name','ASTRA DATA GUI') + else + figure(figure_number), imshow(sliceExtractor((image_matrix(:,:,:)), 'z', sliderValue),[],'InitialMagnification', magnification); + ylabel('x') + xlabel('y') + set(gcf,'Name','ASTRA DATA GUI') + end + + +% --- Executes on slider movement. +function sld_slice_Callback(hObject, eventdata, handles) +% hObject handle to sld_slice (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + +sliderValue = floor(get(handles.sld_slice, 'Value')); +set(handles.txt_slice, 'String', num2str(sliderValue)); +showimage(handles); + +% --- Executes during object creation, after setting all properties. +function sld_slice_CreateFcn(hObject, eventdata, handles) +% hObject handle to sld_slice (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles empty - handles not created until after all CreateFcns called + +% Hint: slider controls usually have a light gray background. +if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor',[.9 .9 .9]); +end + + +% --- Executes on button press in pushbutton2. +function pushbutton2_Callback(hObject, eventdata, handles) +% hObject handle to pushbutton2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + + +% --- Executes on button press in pushbutton3. +function pushbutton3_Callback(hObject, eventdata, handles) +% hObject handle to pushbutton3 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + + +% --- Executes on button press in pushbutton4. +function pushbutton4_Callback(hObject, eventdata, handles) +% hObject handle to pushbutton4 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + + +function txt_slice_Callback(hObject, eventdata, handles) +% hObject handle to txt_slice (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) +slice = str2double(get(handles.txt_slice, 'String')); +max = str2num(get(handles.txt_max,'String')); +min = str2num(get(handles.txt_min,'String')); +if(slice > max) + set(handles.txt_slice, 'String', num2str(max)); + set(handles.sld_slice, 'Value', max); +elseif(slice < min) + set(handles.txt_slice, 'String', num2str(min)); + set(handles.sld_slice, 'Value', min); +else + set(handles.sld_slice, 'Value', slice); +end +showimage(handles); + +% --- Executes during object creation, after setting all properties. +function txt_slice_CreateFcn(hObject, eventdata, handles) +% hObject handle to txt_slice (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles empty - handles not created until after all CreateFcns called + +% Hint: edit controls usually have a white background on Windows. +% See ISPC and COMPUTER. +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +% --- Executes on slider movement. +function sld_magnification_Callback(hObject, eventdata, handles) +% hObject handle to sld_slice2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + +% Hints: get(hObject,'Value') returns position of slider +% get(hObject,'Min') and get(hObject,'Max') to determine range of slider +sliderValue3 = floor(get(handles.sld_magnification, 'Value')); +set(handles.txt_mag, 'String', num2str(sliderValue3)); + +if(~isempty(handles.data)) + showimage(handles); +end + + + +% --- Executes during object creation, after setting all properties. +function sld_magnification_CreateFcn(hObject, eventdata, handles) +% hObject handle to sld_slice2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles empty - handles not created until after all CreateFcns called +% Hint: slider controls usually have a light gray background. +if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor',[.9 .9 .9]); +end + + +function txt_mag_Callback(hObject, eventdata, handles) +% hObject handle to txt_slice2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) +magnification = str2double(get(handles.txt_mag, 'String')); +if(magnification > 400) + set(handles.txt_mag, 'String', num2str(400)); + set(handles.sld_magnification, 'Value', 400); +elseif(magnification < 1) + set(handles.txt_mag, 'String', num2str(1)); + set(handles.sld_magnification, 'Value', 1); +else + set(handles.sld_magnification, 'Value', magnification); +end + +if(~isempty(handles.data)) + showimage(handles); +end + +% --- Executes during object creation, after setting all properties. +function txt_mag_CreateFcn(hObject, eventdata, handles) +% hObject handle to txt_slice2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles empty - handles not created until after all CreateFcns called + +% Hint: edit controls usually have a white background on Windows. +% See ISPC and COMPUTER. +if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor','white'); +end + +% --- Executes on slider movement. +function figure_number_Callback(hObject, eventdata, handles) +% hObject handle to sld_slice2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles structure with handles and user data (see GUIDATA) + +% Hints: get(hObject,'Value') returns position of slider +% get(hObject,'Min') and get(hObject,'Max') to determine range of slider +number = floor(str2double(get(handles.figure_number, 'String'))); +if(number < 1) + set(handles.figure_number, 'String', num2str(1)); +else + set(handles.figure_number, 'String', num2str(number)); +end + +if(~isempty(handles.data)) + showimage(handles); +end + + +% --- Executes during object creation, after setting all properties. +function figure_number_CreateFcn(hObject, eventdata, handles) +% hObject handle to sld_slice2 (see GCBO) +% eventdata reserved - to be defined in a future version of MATLAB +% handles empty - handles not created until after all CreateFcns called +% Hint: slider controls usually have a light gray background. +if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) + set(hObject,'BackgroundColor',[.9 .9 .9]); +end + + + +% --- Executes when selected object is changed in btn_dir. +function btn_dir_SelectionChangeFcn(hObject, eventdata, handles) +% hObject handle to the selected object in btn_dir +% eventdata structure with the following fields (see UIBUTTONGROUP) +% EventName: string 'SelectionChanged' (read only) +% OldValue: handle of the previously selected object or empty if none was selected +% NewValue: handle of the currently selected object +% handles structure with handles and user data (see GUIDATA) + +data = handles.data; + +if(hObject == handles.btn_x) + set(handles.btn_x, 'Value', 1); + set(handles.btn_y, 'Value', 0); + set(handles.btn_z, 'Value', 0); +elseif(hObject == handles.btn_y) + set(handles.btn_x, 'Value', 0); + set(handles.btn_y, 'Value', 1); + set(handles.btn_z, 'Value', 0); +elseif(hObject == handles.btn_z) + set(handles.btn_x, 'Value', 0); + set(handles.btn_y, 'Value', 0); + set(handles.btn_z, 'Value', 1); +end + +if get(handles.btn_x, 'Value') == 1 + set(handles.sld_slice, 'Min',1); + set(handles.sld_slice, 'Max', size(data,1)); + set(handles.sld_slice, 'SliderStep', [1/(size(data,1)-2) 1/(size(data,1)-2)]); + set(handles.sld_slice, 'Value', size(data,1)/2); + + sliderValue = get(handles.sld_slice, 'Value'); + set(handles.txt_slice, 'String', num2str(sliderValue)); + set(handles.txt_min, 'String', num2str(1)); + set(handles.txt_max, 'String', num2str(size(data,1))); + +elseif get(handles.btn_y, 'Value') == 1 + set(handles.sld_slice, 'Min',1); + set(handles.sld_slice, 'Max', size(data,2)); + set(handles.sld_slice, 'SliderStep', [1/(size(data,2)-2) 1/(size(data,2)-2)]); + set(handles.sld_slice, 'Value', size(data,2)/2); + + sliderValue = get(handles.sld_slice, 'Value'); + set(handles.txt_slice, 'String', num2str(sliderValue)); + set(handles.txt_min, 'String', num2str(1)); + set(handles.txt_max, 'String', num2str(size(data,2))); +else + set(handles.sld_slice, 'Min',1); + set(handles.sld_slice, 'Max', size(data,3)); + set(handles.sld_slice, 'SliderStep', [1/(size(data,3)-2) 1/(size(data,3)-2)]); + set(handles.sld_slice, 'Value', size(data,3)/2); + + sliderValue = get(handles.sld_slice, 'Value'); + set(handles.txt_slice, 'String', num2str(sliderValue)); + set(handles.txt_min, 'String', num2str(1)); + set(handles.txt_max, 'String', num2str(size(data,3))); +end + +showimage(handles); diff --git a/matlab/tools/astra_data_op.m b/matlab/tools/astra_data_op.m new file mode 100644 index 0000000..b6ef0e2 --- /dev/null +++ b/matlab/tools/astra_data_op.m @@ -0,0 +1,11 @@ +function astra_data_op(op, data, scalar, gpu_core) + +cfg = astra_struct('DataOperation_CUDA'); +cfg.Operation = op; +cfg.Scalar = scalar; +cfg.DataId = data; +cfg.option.GPUindex = gpu_core; + +alg_id = astra_mex_algorithm('create',cfg); +astra_mex_algorithm('run',alg_id); +astra_mex_algorithm('delete',alg_id);
\ No newline at end of file diff --git a/matlab/tools/astra_data_op_mask.m b/matlab/tools/astra_data_op_mask.m new file mode 100644 index 0000000..d46c925 --- /dev/null +++ b/matlab/tools/astra_data_op_mask.m @@ -0,0 +1,12 @@ +function astra_data_op_mask(op, data, scalar, mask, gpu_core) + +cfg = astra_struct('DataOperation_CUDA'); +cfg.Operation = op; +cfg.Scalar = scalar; +cfg.DataId = data; +cfg.option.GPUindex = gpu_core; +cfg.option.MaskId = mask; + +alg_id = astra_mex_algorithm('create',cfg); +astra_mex_algorithm('run',alg_id); +astra_mex_algorithm('delete',alg_id);
\ No newline at end of file diff --git a/matlab/tools/astra_downsample_sinogram.m b/matlab/tools/astra_downsample_sinogram.m new file mode 100644 index 0000000..30c1cdd --- /dev/null +++ b/matlab/tools/astra_downsample_sinogram.m @@ -0,0 +1,36 @@ +function [sinogram_new, proj_geom_new] = astra_downsample_sinogram(sinogram, proj_geom, factor) + +%------------------------------------------------------------------------ +% [sinogram_new, proj_geom_new] = astra_downsample_sinogram(sinogram, proj_geom, factor) +% +% Downsample the sinogram with some factor and adjust projection geometry +% accordingly +% +% sinogram: MATLAB data version of the sinogram. +% proj_geom: MATLAB struct containing the projection geometry. +% factor: the factor by which the number of detectors is divided. +% sinogram_new: MATLAB data version of the resampled sinogram. +% proj_geom_new: MATLAB struct containing the new projection geometry. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +if mod(size(sinogram,2),factor) ~= 0 + disp('size of the sinogram must be a divisor of the factor'); +end + +sinogram_new = zeros(size(sinogram,1),size(sinogram,2)/factor); +for i = 1:size(sinogram,2)/factor + sinogram_new(:,i) = sum(sinogram(:,(factor*(i-1)+1):factor*i),2); +end + +proj_geom_new = proj_geom; +proj_geom_new.DetectorCount = proj_geom_new.DetectorCount / factor; diff --git a/matlab/tools/astra_geom_2vec.m b/matlab/tools/astra_geom_2vec.m new file mode 100644 index 0000000..0abd07c --- /dev/null +++ b/matlab/tools/astra_geom_2vec.m @@ -0,0 +1,84 @@ +function proj_geom_out = astra_geom_2vec(proj_geom) + + % FANFLAT + if strcmp(proj_geom.type,'fanflat') + + vectors = zeros(numel(proj_geom.ProjectionAngles), 6); + for i = 1:numel(proj_geom.ProjectionAngles) + + % source + vectors(i,1) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource; + vectors(i,2) = -cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource; + + % center of detector + vectors(i,3) = -sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector; + vectors(i,4) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector; + + % vector from detector pixel 0 to 1 + vectors(i,5) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorWidth; + vectors(i,6) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorWidth; + end + + proj_geom_out = astra_create_proj_geom('fanflat_vec', proj_geom.DetectorCount, vectors); + + % CONE + elseif strcmp(proj_geom.type,'cone') + + vectors = zeros(numel(proj_geom.ProjectionAngles), 12); + for i = 1:numel(proj_geom.ProjectionAngles) + + % source + vectors(i,1) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource; + vectors(i,2) = -cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource; + vectors(i,3) = 0; + + % center of detector + vectors(i,4) = -sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector; + vectors(i,5) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector; + vectors(i,6) = 0; + + % vector from detector pixel (0,0) to (0,1) + vectors(i,7) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX; + vectors(i,8) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX; + vectors(i,9) = 0; + + % vector from detector pixel (0,0) to (1,0) + vectors(i,10) = 0; + vectors(i,11) = 0; + vectors(i,12) = proj_geom.DetectorSpacingY; + end + + proj_geom_out = astra_create_proj_geom('cone_vec', proj_geom.DetectorRowCount, proj_geom.DetectorColCount, vectors); + + % PARALLEL + elseif strcmp(proj_geom.type,'parallel3d') + + vectors = zeros(numel(proj_geom.ProjectionAngles), 12); + for i = 1:numel(proj_geom.ProjectionAngles) + + % ray direction + vectors(i,1) = sin(proj_geom.ProjectionAngles(i)); + vectors(i,2) = -cos(proj_geom.ProjectionAngles(i)); + vectors(i,3) = 0; + + % center of detector + vectors(i,4) = 0; + vectors(i,5) = 0; + vectors(i,6) = 0; + + % vector from detector pixel (0,0) to (0,1) + vectors(i,7) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX; + vectors(i,8) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX; + vectors(i,9) = 0; + + % vector from detector pixel (0,0) to (1,0) + vectors(i,10) = 0; + vectors(i,11) = 0; + vectors(i,12) = proj_geom.DetectorSpacingY; + end + + proj_geom_out = astra_create_proj_geom('parallel3d_vec', proj_geom.DetectorRowCount, proj_geom.DetectorColCount, vectors); + + else + error(['No suitable vector geometry found for type: ' proj_geom.type]) + end diff --git a/matlab/tools/astra_geom_postalignment.m b/matlab/tools/astra_geom_postalignment.m new file mode 100644 index 0000000..4115af2 --- /dev/null +++ b/matlab/tools/astra_geom_postalignment.m @@ -0,0 +1,11 @@ +function proj_geom = astra_geom_postalignment(proj_geom, factor) + + if strcmp(proj_geom.type,'fanflat_vec') + proj_geom.Vectors(:,3:4) = proj_geom.Vectors(:,3:4) + factor * proj_geom.Vectors(:,5:6); + + elseif strcmp(proj_geom.type,'cone_vec') || strcmp(proj_geom.type,'parallel3d_vec') + proj_geom.Vectors(:,4:6) = proj_geom.Vectors(:,4:6) + factor * proj_geom.Vectors(:,7:9); + + else + error('Projection geometry not suited for postalignment correction.') + end diff --git a/matlab/tools/astra_geom_size.m b/matlab/tools/astra_geom_size.m new file mode 100644 index 0000000..c4956f5 --- /dev/null +++ b/matlab/tools/astra_geom_size.m @@ -0,0 +1,28 @@ +function s = astra_geom_size(geom, dim) + + if isfield(geom, 'GridSliceCount') + % 3D Volume geometry? + s = [ geom.GridColCount, geom.GridRowCount, geom.GridSliceCount ]; + elseif isfield(geom, 'GridColCount') + % 2D Volume geometry? + s = [ geom.GridRowCount, geom.GridColCount ]; + elseif strcmp(geom.type,'parallel') || strcmp(geom.type,'fanflat') + s = [numel(geom.ProjectionAngles), geom.DetectorCount]; + + elseif strcmp(geom.type,'parallel3d') || strcmp(geom.type,'cone') + s = [geom.DetectorRowCount, numel(geom.ProjectionAngles), geom.DetectorColCount]; + + elseif strcmp(geom.type,'fanflat_vec') + s = [size(geom.Vectors,1), geom.DetectorCount]; + + elseif strcmp(geom.type,'parallel3d_vec') || strcmp(geom.type,'cone_vec') + s = [geom.DetectorColCount, size(geom.Vectors,1), geom.DetectorRowCount]; + + end + + if nargin == 2 + s = s(dim); + end + +end + diff --git a/matlab/tools/astra_geom_superresolution.m b/matlab/tools/astra_geom_superresolution.m new file mode 100644 index 0000000..b2b0ebf --- /dev/null +++ b/matlab/tools/astra_geom_superresolution.m @@ -0,0 +1,14 @@ +function proj_geom = astra_geom_superresolution(proj_geom, factor) + + if strcmp(proj_geom.type,'parallel') + proj_geom.DetectorWidth = proj_geom.DetectorWidth/factor; + proj_geom.DetectorCount = proj_geom.DetectorCount * factor; + elseif strcmp(proj_geom.type,'fanflat') + proj_geom.DetectorWidth = proj_geom.DetectorWidth/factor; + proj_geom.DetectorCount = proj_geom.DetectorCount * factor; + elseif strcmp(proj_geom.type,'fanflat_vec') + proj_geom.Vectors(:,5:6) = proj_geom.Vectors(:,5:6) / factor; % DetectorSize + proj_geom.DetectorCount = proj_geom.DetectorCount * factor; + else + error('Projection geometry not suited for super-resolution (or not implemented).') + end diff --git a/matlab/tools/astra_imshow.m b/matlab/tools/astra_imshow.m new file mode 100644 index 0000000..6069674 --- /dev/null +++ b/matlab/tools/astra_imshow.m @@ -0,0 +1,10 @@ +function V = astra_imshow(data, range) + +if numel(data) == 1 + data = astra_mex_data2d('get', data); +end +imshow(data,range); + +if nargout >= 1 + V = data; +end
\ No newline at end of file diff --git a/matlab/tools/astra_mex.m b/matlab/tools/astra_mex.m new file mode 100644 index 0000000..e04cfea --- /dev/null +++ b/matlab/tools/astra_mex.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex' )">astra_mex</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_c(varargin{:}); +end diff --git a/matlab/tools/astra_mex_algorithm.m b/matlab/tools/astra_mex_algorithm.m new file mode 100644 index 0000000..138a43c --- /dev/null +++ b/matlab/tools/astra_mex_algorithm.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex_algorithm(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex_algorithm' )">astra_mex_algorithm</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_algorithm_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_algorithm_c(varargin{:}); +end diff --git a/matlab/tools/astra_mex_data2d.m b/matlab/tools/astra_mex_data2d.m new file mode 100644 index 0000000..eacbcb9 --- /dev/null +++ b/matlab/tools/astra_mex_data2d.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex_data2d(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex_data2d' )">astra_mex_data2d</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_data2d_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_data2d_c(varargin{:}); +end diff --git a/matlab/tools/astra_mex_data3d.m b/matlab/tools/astra_mex_data3d.m new file mode 100644 index 0000000..3bbbd68 --- /dev/null +++ b/matlab/tools/astra_mex_data3d.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex_data3d(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex_data3d' )">astra_mex_data3d</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_data3d_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_data3d_c(varargin{:}); +end diff --git a/matlab/tools/astra_mex_matrix.m b/matlab/tools/astra_mex_matrix.m new file mode 100644 index 0000000..182ab1e --- /dev/null +++ b/matlab/tools/astra_mex_matrix.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex_matrix(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex_matrix' )">astra_mex_matrix</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_matrix_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_matrix_c(varargin{:}); +end diff --git a/matlab/tools/astra_mex_projector.m b/matlab/tools/astra_mex_projector.m new file mode 100644 index 0000000..487da06 --- /dev/null +++ b/matlab/tools/astra_mex_projector.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex_projector(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex_projector' )">astra_mex_projector</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_projector_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_projector_c(varargin{:}); +end diff --git a/matlab/tools/astra_mex_projector3d.m b/matlab/tools/astra_mex_projector3d.m new file mode 100644 index 0000000..3d21ce9 --- /dev/null +++ b/matlab/tools/astra_mex_projector3d.m @@ -0,0 +1,24 @@ +function [varargout] = astra_mex_projector3d(varargin) +%------------------------------------------------------------------------ +% Reference page in Help browser +% <a href="matlab:docsearch('astra_mex_projector3d' )">astra_mex_projector3d</a>. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +if nargout == 0 + astra_mex_projector3d_c(varargin{:}); + if exist('ans','var') + varargout{1} = ans; + end +else + varargout = cell(1,nargout); + [varargout{:}] = astra_mex_projector3d_c(varargin{:}); +end diff --git a/matlab/tools/astra_projector_handle.m b/matlab/tools/astra_projector_handle.m new file mode 100644 index 0000000..72d4c73 --- /dev/null +++ b/matlab/tools/astra_projector_handle.m @@ -0,0 +1,29 @@ +classdef astra_projector_handle < handle + %ASTRA_PROJECTOR_HANDLE Handle class around an astra_mex_projector id + % Automatically deletes the projector when deleted. + + %------------------------------------------------------------------------ + % This file is part of the + % All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") + % + % Copyright: iMinds-Vision Lab, University of Antwerp + % License: Open Source under GPLv3 + % Contact: mailto:astra@ua.ac.be + % Website: http://astra.ua.ac.be + %------------------------------------------------------------------------ + + properties + id + end + + methods + function obj = astra_projector_handle(proj_id) + obj.id = proj_id; + end + function delete(obj) + astra_mex_projector('delete', obj.id); + end + end + +end + diff --git a/matlab/tools/astra_set_directory.m b/matlab/tools/astra_set_directory.m new file mode 100644 index 0000000..1d5a368 --- /dev/null +++ b/matlab/tools/astra_set_directory.m @@ -0,0 +1,27 @@ +function in = astra_set_directory(in) + +%------------------------------------------------------------------------ +% in = astra_set_directory(in) +% +% Creates the directories present in the input path if they do not exist +% already +% +% in: input path. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +a = find(in == '/' | in == '\'); +for i = 1:numel(a) + if ~isdir(in(1:a(i))) + mkdir(in(1:a(i))); + end +end diff --git a/matlab/tools/astra_struct.m b/matlab/tools/astra_struct.m new file mode 100644 index 0000000..f65b2ec --- /dev/null +++ b/matlab/tools/astra_struct.m @@ -0,0 +1,37 @@ +function res = astra_struct(type) + +%------------------------------------------------------------------------ +% res = astra_struct(type) +% +% Create an ASTRA struct +% +% type: type of the struct to be generated. +% res: the generated matlab struct. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ +res = struct(); +res.options = struct(); + + +if nargin >= 1 + % For backward compatibility, transparently accept SIRT_CUDA2 + % for SIRT_CUDA, and FP_CUDA2 for FP_CUDA. + if strcmp(type, 'SIRT_CUDA2') + type = 'SIRT_CUDA'; + warning('SIRT_CUDA2 has been deprecated. Use SIRT_CUDA instead.'); + end + if strcmp(type, 'FP_CUDA2') + type = 'FP_CUDA'; + warning('FP_CUDA2 has been deprecated. Use FP_CUDA instead.'); + end + res.type = type; +end diff --git a/matlab/tools/compute_rnmp.m b/matlab/tools/compute_rnmp.m new file mode 100644 index 0000000..6c00a01 --- /dev/null +++ b/matlab/tools/compute_rnmp.m @@ -0,0 +1,29 @@ +function [rnmp, nmp] = compute_rnmp(phantom, S) + + phantom = double(phantom == max(phantom(:))); + S = double(S == max(S(:))); + + %u1 = sort(unique(phantom)); + %u2 = sort(unique(S)); + %for i = 1:numel(u1) + % phantom_(phantom == u1(i)) = i; + % S_(S == u2(i)) = i; + %end + %phantom = phantom_; + %S = S_; + + if numel(size(phantom)) == 2 + S = imresize(S, size(phantom), 'nearest'); + elseif numel(size(phantom)) == 3 + S2 = zeros(size(phantom)); + for slice = 1:size(phantom,3) + S2(:,:,slice) = imresize(S(:,:,slice), [size(phantom,1) size(phantom,2)], 'nearest'); + end + S = S2; + end + + nmp = sum(abs(phantom(:) ~= S(:))); + rnmp = nmp / sum(phantom(:)); + +end + diff --git a/matlab/tools/createOrderART.m b/matlab/tools/createOrderART.m new file mode 100644 index 0000000..a469d8a --- /dev/null +++ b/matlab/tools/createOrderART.m @@ -0,0 +1,66 @@ +function rayOrder = createOrderART(proj_geom, mode) + +%------------------------------------------------------------------------ +% rayOrder = createOrderART(proj_geom, mode) +% +% Creates an array defining the order in which ART will iterate over the +% projections and projection rays +% +% proj_geom: MATLAB struct containing the projection geometry. +% mode: string defining the wanted ray order, can be either 'sequential', +% 'randomray' or 'randomproj'. +% rayOrder: array of two columns of length angle_count * det_count, with +% the first column being the index of the projection and the second column +% the index of the ray. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +angle_count = length(proj_geom.projection_angles); +det_count = proj_geom.detector_count; + +% create order +rayOrder = zeros(angle_count * det_count, 2); +if strcmp(mode,'sequential') == 1 + index = 1; + for i = 1:angle_count + for j = 1:det_count + rayOrder(index,1) = i; + rayOrder(index,2) = j; + index = index + 1; + end + end +elseif strcmp(mode,'randomray') == 1 + index = 1; + for i = 1:angle_count + for j = 1:det_count + rayOrder(index,1) = i; + rayOrder(index,2) = j; + index = index + 1; + end + end + r = randperm(angle_count * det_count); + rayOrder(:,1) = rayOrder(r,1); + rayOrder(:,2) = rayOrder(r,2); +elseif strcmp(mode,'randomproj') == 1 + index = 1; + r = randperm(angle_count); + for i = 1:angle_count + for j = 1:det_count + rayOrder(index,1) = r(i); + rayOrder(index,2) = j; + index = index + 1; + end + end +else + disp('mode not known'); +end + diff --git a/matlab/tools/downsample_sinogram.m b/matlab/tools/downsample_sinogram.m new file mode 100644 index 0000000..1fb4ec8 --- /dev/null +++ b/matlab/tools/downsample_sinogram.m @@ -0,0 +1,12 @@ +function sinogram_out = downsample_sinogram(sinogram, ds) + + if ds == 1 + sinogram_out = sinogram; + return; + end + + sinogram_out = sinogram(:,1:ds:end,:); + for i = 2:ds + sinogram_out = sinogram_out + sinogram(:,i:ds:end,:); + end + sinogram_out = sinogram_out / (ds*ds);
\ No newline at end of file diff --git a/matlab/tools/imreadgs.m b/matlab/tools/imreadgs.m new file mode 100644 index 0000000..9c27eb4 --- /dev/null +++ b/matlab/tools/imreadgs.m @@ -0,0 +1,26 @@ +function Im = imreadgs(filename) + +%------------------------------------------------------------------------ +% Im = imreadgs(filename) +% +% Reads an image and transforms it into a grayscale image consisting of +% doubles. +% +% filename: name of the image file. +% Im: a grayscale image in double. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +Im = double(imread(filename)); +if size(Im,3) > 1 + Im = Im(:,:,1); +end diff --git a/matlab/tools/imresize3D.m b/matlab/tools/imresize3D.m new file mode 100644 index 0000000..9032cc3 --- /dev/null +++ b/matlab/tools/imresize3D.m @@ -0,0 +1,26 @@ +function out = imresize3D(in, s_out, method) + +%------------------------------------------------------------------------ +% out = imresize3D(in, s_out, method) +% +% Resizes a 3-component image +% +% in: input image. +% s_out: 2 element array with the wanted image size, [rows columns]. +% out: the resized 3-component image. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +out = zeros(s_out); +for i = 1:size(in,3) + out(:,:,i) = imresize(in(:,:,i), s_out(1:2), method); +end diff --git a/matlab/tools/imscale.m b/matlab/tools/imscale.m new file mode 100644 index 0000000..957f11f --- /dev/null +++ b/matlab/tools/imscale.m @@ -0,0 +1,28 @@ +function out = imscale(in) + +%------------------------------------------------------------------------ +% out = imscale(in) +% +% Rescales the image values between zero and one. +% +% in: input image. +% out: scaled output image. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +mi = min(in(:)); +ma = max(in(:)); +if (ma-mi) == 0 + out = zeros(size(in)); +else + out = (in - mi) / (ma - mi); +end diff --git a/matlab/tools/imwritesc.m b/matlab/tools/imwritesc.m new file mode 100644 index 0000000..2f81dc8 --- /dev/null +++ b/matlab/tools/imwritesc.m @@ -0,0 +1,22 @@ +function imwritesc(in, filename) + +%------------------------------------------------------------------------ +% imwritesc(in, filename) +% +% Rescale between zero and one and write image +% +% in: input image. +% filename: name of output image file. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +imwrite(imscale(in),filename); diff --git a/matlab/tools/kaiserBessel.m b/matlab/tools/kaiserBessel.m new file mode 100644 index 0000000..aef7b9d --- /dev/null +++ b/matlab/tools/kaiserBessel.m @@ -0,0 +1,31 @@ +function res = kaiserBessel(m,alpha,a,r) + +%------------------------------------------------------------------------ +% res = kaiserBessel(m,alpha,a,r) +% +% Calculates the Kaiser windowing function +% +% a: length of the sequence. +% m: order. +% alpha: determines shape of window. +% r: input values for which to compute window value. +% res: the window values. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +sq = sqrt(1 - (r./a).^2); + +res1 = 1 ./ besseli(m, alpha); +res2 = sq .^ m; +res3 = besseli(m, alpha .* sq); + +res = res1 .* res2 .* res3; diff --git a/matlab/tools/linspace2.m b/matlab/tools/linspace2.m new file mode 100644 index 0000000..2787fd9 --- /dev/null +++ b/matlab/tools/linspace2.m @@ -0,0 +1,25 @@ +function out = linspace2(a,b,c) + +%------------------------------------------------------------------------ +% out = linspace2(a,b,c) +% +% Generates linearly spaced vectors +% +% a: lower limit. +% b: upper limit (exclusive). +% c: number of elements. +% out: linearly spaced vector. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +out = linspace(a,b,c+1); +out = out(1:end-1); diff --git a/matlab/tools/overlayImage.m b/matlab/tools/overlayImage.m new file mode 100644 index 0000000..7c81e55 --- /dev/null +++ b/matlab/tools/overlayImage.m @@ -0,0 +1,24 @@ +function im = overlayImage(reconstruction, ground_truth) +%------------------------------------------------------------------------ +% im = overlayImage(reconstruction, ground_truth) +% +% Produces an overlay image of two images, useful for image comparison. +% +% reconstruction: first input image matrix. +% ground_truth: second input image matrix. +% im: output 3-component image, third channel is 0. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +im(:,:,1) = reconstruction ./ max(reconstruction(:)); +im(:,:,2) = ground_truth ./ max(ground_truth(:)); +im(:,:,3) = zeros(size(reconstruction)); diff --git a/matlab/tools/rebin_fan2par.m b/matlab/tools/rebin_fan2par.m new file mode 100644 index 0000000..da20932 --- /dev/null +++ b/matlab/tools/rebin_fan2par.m @@ -0,0 +1,82 @@ +function F = rebin_fan2par(RadonData, BetaDeg, D, thetaDeg) + +%------------------------------------------------------------------------ +% F = rebin_fan2par(RadonData, BetaDeg, D, thetaDeg) +% +% Deze functie zet fan beam data om naar parallelle data, door interpolatie +% (fast resorting algorithm, zie Kak en Slaney) +% Radondata zoals altijd: eerste coord gamma , de rijen +% tweede coord beta, de kolommen, beide hoeken in +% radialen +% PixPProj: aantal pixels per projectie (voor skyscan data typisch 1000) +% BetaDeg: vector met alle draaihoeken in graden +% D: afstand bron - rotatiecentrum in pixels, dus afstand +% bron-rotatiecentrum(um) gedeeld door image pixel size (um). +% thetaDeg: vector met gewenste sinogramwaarden voor theta in graden +% de range van thetaDeg moet steeds kleiner zijn dan die van betadeg +% D,gamma,beta, theta zoals gebruikt in Kak & Slaney +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +NpixPProj = size(RadonData,1); % aantal pixels per projectie +%if mod(size(Radondata,1),2)==0 +% NpixPProjNew=NpixPProj+1; +%else + NpixPProjNew = NpixPProj; +%end + +%% FAN-BEAM RAYS + +% flip sinogram, why? +RadonData = flipdim(RadonData,2); % matlab gebruikt tegengestelde draairichting (denkik) als skyscan, of er is een of andere flipdim geweest die gecorrigeerd moet worden)) + +% DetPixPos: distance of each detector to the ray through the origin (theta) +DetPixPos = -(NpixPProj-1)/2:(NpixPProj-1)/2; % posities detectorpixels + +% GammaStralen: alpha's? (result in radians!!) +GammaStralen = atan(DetPixPos/D); % alle met de detectorpixelposities overeenkomstige gammahoeken + +% put beta (theta) and gamma (alpha) for each ray in 2D matrices +[beta gamma] = meshgrid(BetaDeg,GammaStralen); + +% t: minimal distance between each ray and the ray through the origin +t = D*sin(gamma); % t-waarden overeenkomstig met de verschillende gamma's + +theta = gamma*180/pi + beta; % theta-waarden in graden overeenkomstig met verschillende gamma en beta waarden + +%% PARALLEL BEAM RAYS + +% DetPixPos: distance of each detector to the ray through the origin (theta) +DetPixPos = -(NpixPProjNew-1)/2:(NpixPProjNew-1)/2; % posities detectorpixels + +% GammaStralen: alpha's? (result in radians!!) +GammaStralenNew = atan(DetPixPos/D); % alle met de detectorpixelposities overeenkomstige gammahoeken + +% put beta (theta) and gamma (alpha) for each ray in 2D matrices +[~, gamma] = meshgrid(BetaDeg,GammaStralenNew); + +% t: minimal distance between each ray and the ray through the origin +tnew = D * sin(gamma); % t-waarden overeenkomstig met de verschillende gamma's + +% calculate new t +step = (max(tnew)-min(tnew)) / (NpixPProjNew-1); +t_para = min(tnew):step:max(tnew); + +[thetaNewCoord tNewCoord] = meshgrid(thetaDeg, t_para); + +%% Interpolate +Interpolant = TriScatteredInterp(theta(:), t(:), RadonData(:),'nearest'); +F = Interpolant(thetaNewCoord,tNewCoord); + + + + diff --git a/matlab/tools/sliceExtractor.m b/matlab/tools/sliceExtractor.m new file mode 100644 index 0000000..dfc87ee --- /dev/null +++ b/matlab/tools/sliceExtractor.m @@ -0,0 +1,34 @@ +function slice = sliceExtractor(data, dir, slicenr) + +%------------------------------------------------------------------------ +% slice = sliceExtractor(data, dir, slicenr) +% +% Outputs a specified slice from a three dimensional matrix/volume +% +% data: the 3D volume. +% dir: the direction in which the volume is sliced. +% slicenr: the index of the slice to retrieve. +% slice: 2D image matrix containing the slice. +%------------------------------------------------------------------------ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ +% $Id$ + +slicenr = round(slicenr); + +if strcmp(dir,'z') + slice = squeeze(data(:,:,slicenr)); +end +if strcmp(dir,'x') + slice = squeeze(data(:,slicenr,:)); +end +if strcmp(dir,'y') + slice = squeeze(data(slicenr,:,:)); +end diff --git a/samples/s001_sinogram_par2d.m b/samples/s001_sinogram_par2d.m new file mode 100644 index 0000000..9f50c14 --- /dev/null +++ b/samples/s001_sinogram_par2d.m @@ -0,0 +1,33 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +% Create a basic 256x256 square volume geometry +vol_geom = astra_create_vol_geom(256, 256); + +% Create a parallel beam geometry with 180 angles between 0 and pi, and +% 384 detector pixels of width 1. +% For more details on available geometries, see the online help of the +% function astra_create_proj_geom . +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% Create a 256x256 phantom image using matlab's built-in phantom() function +P = phantom(256); + +% Create a sinogram using the GPU. +% Note that the first time the GPU is accessed, there may be a delay +% of up to 10 seconds for initialization. +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); + +figure(1); imshow(P, []); +figure(2); imshow(sinogram, []); + + +% Free memory +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s002_data2d.m b/samples/s002_data2d.m new file mode 100644 index 0000000..37b5549 --- /dev/null +++ b/samples/s002_data2d.m @@ -0,0 +1,60 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); + +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + + +% Create volumes + +% initialized to zero +v0 = astra_mex_data2d('create', '-vol', vol_geom); + +% initialized to 3.0 +v1 = astra_mex_data2d('create', '-vol', vol_geom, 3.0); + +% initialized to a matrix. A may be a single, double or logical (0/1) array. +A = phantom(256); +v2 = astra_mex_data2d('create', '-vol', vol_geom, A); + + +% Projection data +s0 = astra_mex_data2d('create', '-sino', proj_geom); +% Initialization to a scalar or a matrix also works, exactly as with a volume. + + +% Update data + +% set to zero +astra_mex_data2d('store', v0, 0); + +% set to a matrix +astra_mex_data2d('store', v2, A); + + + +% Retrieve data + +R = astra_mex_data2d('get', v2); +imshow(R, []); + + +% Retrieve data as a single array. Since astra internally stores +% data as single precision, this is more efficient: + +R = astra_mex_data2d('get_single', v2); + + +% Free memory +astra_mex_data2d('delete', v0); +astra_mex_data2d('delete', v1); +astra_mex_data2d('delete', v2); +astra_mex_data2d('delete', s0); diff --git a/samples/s003_gpu_reconstruction.m b/samples/s003_gpu_reconstruction.m new file mode 100644 index 0000000..749f91a --- /dev/null +++ b/samples/s003_gpu_reconstruction.m @@ -0,0 +1,52 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% As before, create a sinogram from a phantom +P = phantom(256); +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); +figure(1); imshow(P, []); +figure(2); imshow(sinogram, []); + +astra_mex_data2d('delete', sinogram_id); + +% We now re-create the sinogram data object as we would do when loading +% an external sinogram +sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram); + +% Create a data object for the reconstruction +rec_id = astra_mex_data2d('create', '-vol', vol_geom); + +% Set up the parameters for a reconstruction algorithm using the GPU +cfg = astra_struct('SIRT_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; + +% Available algorithms: +% SIRT_CUDA, SART_CUDA, EM_CUDA, FBP_CUDA (see the FBP sample) + + +% Create the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); + +% Run 150 iterations of the algorithm +astra_mex_algorithm('iterate', alg_id, 150); + +% Get the result +rec = astra_mex_data2d('get', rec_id); +figure(3); imshow(rec, []); + +% Clean up. Note that GPU memory is tied up in the algorithm object, +% and main RAM in the data objects. +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s004_cpu_reconstruction.m b/samples/s004_cpu_reconstruction.m new file mode 100644 index 0000000..69414e2 --- /dev/null +++ b/samples/s004_cpu_reconstruction.m @@ -0,0 +1,60 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% For CPU-based algorithms, a "projector" object specifies the projection +% model used. In this case, we use the "strip" model. +proj_id = astra_create_projector('strip', proj_geom, vol_geom); + +% Create a sinogram from a phantom +P = phantom(256); +[sinogram_id, sinogram] = astra_create_sino(P, proj_id); +figure(1); imshow(P, []); +figure(2); imshow(sinogram, []); + +astra_mex_data2d('delete', sinogram_id); + +% We now re-create the sinogram data object as we would do when loading +% an external sinogram +sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram); + +% Create a data object for the reconstruction +rec_id = astra_mex_data2d('create', '-vol', vol_geom); + +% Set up the parameters for a reconstruction algorithm using the CPU +% The main difference with the configuration of a GPU algorithm is the +% extra ProjectorId setting. +cfg = astra_struct('SIRT'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; +cfg.ProjectorId = proj_id; + +% Available algorithms: +% ART, SART, SIRT, CGLS, FBP + + +% Create the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); + +% Run 20 iterations of the algorithm +% This will have a runtime in the order of 10 seconds. +astra_mex_algorithm('iterate', alg_id, 20); + +% Get the result +rec = astra_mex_data2d('get', rec_id); +figure(3); imshow(rec, []); + +% Clean up. +astra_mex_projector('delete', proj_id); +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s005_3d_geometry.m b/samples/s005_3d_geometry.m new file mode 100644 index 0000000..fa959c9 --- /dev/null +++ b/samples/s005_3d_geometry.m @@ -0,0 +1,98 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(64, 64, 64); + + +% There are two main 3d projection geometry types: cone beam and parallel beam. +% Each has a regular variant, and a 'vec' variant. +% The 'vec' variants are completely free in the placement of source/detector, +% while the regular variants assume circular trajectories around the z-axis. + + +% ------------- +% Parallel beam +% ------------- + + +% Circular + +% Parameters: width of detector column, height of detector row, #rows, #columns +angles = linspace2(0, 2*pi, 48); +proj_geom = astra_create_proj_geom('parallel3d', 1.0, 1.0, 32, 64, angles); + + +% Free + +% We generate the same geometry as the circular one above. +vectors = zeros(numel(angles), 12); +for i = 1:numel(angles) + % ray direction + vectors(i,1) = sin(angles(i)); + vectors(i,2) = -cos(angles(i)); + vectors(i,3) = 0; + + % center of detector + vectors(i,4:6) = 0; + + % vector from detector pixel (0,0) to (0,1) + vectors(i,7) = cos(angles(i)); + vectors(i,8) = sin(angles(i)); + vectors(i,9) = 0; + + % vector from detector pixel (0,0) to (1,0) + vectors(i,10) = 0; + vectors(i,11) = 0; + vectors(i,12) = 1; +end + +% Parameters: #rows, #columns, vectors +proj_geom = astra_create_proj_geom('parallel3d_vec', 32, 64, vectors); + +% ---------- +% Cone beam +% ---------- + + +% Circular + +% Parameters: width of detector column, height of detector row, #rows, #columns, +% angles, distance source-origin, distance origin-detector +angles = linspace2(0, 2*pi, 48); +proj_geom = astra_create_proj_geom('cone', 1.0, 1.0, 32, 64, ... + angles, 1000, 0); + +% Free + +vectors = zeros(numel(angles), 12); +for i = 1:numel(angles) + + % source + vectors(i,1) = sin(angles(i)) * 1000; + vectors(i,2) = -cos(angles(i)) * 1000; + vectors(i,3) = 0; + + % center of detector + vectors(i,4:6) = 0; + + % vector from detector pixel (0,0) to (0,1) + vectors(i,7) = cos(angles(i)); + vectors(i,8) = sin(angles(i)); + vectors(i,9) = 0; + + % vector from detector pixel (0,0) to (1,0) + vectors(i,10) = 0; + vectors(i,11) = 0; + vectors(i,12) = 1; +end + +% Parameters: #rows, #columns, vectors +proj_geom = astra_create_proj_geom('cone_vec', 32, 64, vectors); + diff --git a/samples/s006_3d_data.m b/samples/s006_3d_data.m new file mode 100644 index 0000000..b836198 --- /dev/null +++ b/samples/s006_3d_data.m @@ -0,0 +1,62 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +% Create a 3D volume geometry. +% Parameter order: rows, colums, slices (y, x, z) +vol_geom = astra_create_vol_geom(64, 48, 32); + + +% Create volumes + +% initialized to zero +v0 = astra_mex_data3d('create', '-vol', vol_geom); + +% initialized to 3.0 +v1 = astra_mex_data3d('create', '-vol', vol_geom, 3.0); + +% initialized to a matrix. A may be a single or double array. +% Coordinate order: column, row, slice (x, y, z) +A = zeros(48, 64, 32); +v2 = astra_mex_data3d('create', '-vol', vol_geom, A); + + +% Projection data + +% 2 projection directions, along x and y axis resp. +V = [ 1 0 0 0 0 0 0 1 0 0 0 1 ; ... + 0 1 0 0 0 0 -1 0 0 0 0 1 ]; +% 32 rows (v), 64 columns (u) +proj_geom = astra_create_proj_geom('parallel3d_vec', 32, 64, V); + +s0 = astra_mex_data3d('create', '-proj3d', proj_geom); + +% Initialization to a scalar or zero works exactly as with a volume. + +% Initialized to a matrix: +% Coordinate order: column (u), angle, row (v) +A = zeros(64, 2, 32); +s1 = astra_mex_data3d('create', '-proj3d', proj_geom, A); + + +% Retrieve data: +R = astra_mex_data3d('get', v1); + +% Retrieve data as a single array. Since astra internally stores +% data as single precision, this is more efficient: +R = astra_mex_data3d('get_single', v1); + + + +% Delete all created data objects +astra_mex_data3d('delete', v0); +astra_mex_data3d('delete', v1); +astra_mex_data3d('delete', v2); +astra_mex_data3d('delete', s0); +astra_mex_data3d('delete', s1); diff --git a/samples/s007_3d_reconstruction.m b/samples/s007_3d_reconstruction.m new file mode 100644 index 0000000..1bc9da3 --- /dev/null +++ b/samples/s007_3d_reconstruction.m @@ -0,0 +1,53 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(128, 128, 128); + +angles = linspace2(0, pi, 180); +proj_geom = astra_create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles); + +% Create a simple hollow cube phantom +cube = zeros(128,128,128); +cube(17:112,17:112,17:112) = 1; +cube(33:96,33:96,33:96) = 0; + +% Create projection data from this +[proj_id, proj_data] = astra_create_sino3d_cuda(cube, proj_geom, vol_geom); + +% Display a single projection image +figure, imshow(squeeze(proj_data(:,20,:))',[]) + +% Create a data object for the reconstruction +rec_id = astra_mex_data3d('create', '-vol', vol_geom); + +% Set up the parameters for a reconstruction algorithm using the GPU +cfg = astra_struct('SIRT3D_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = proj_id; + + +% Create the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); + +% Run 150 iterations of the algorithm +% Note that this requires about 750MB of GPU memory, and has a runtime +% in the order of 10 seconds. +astra_mex_algorithm('iterate', alg_id, 150); + +% Get the result +rec = astra_mex_data3d('get', rec_id); +figure, imshow(squeeze(rec(:,:,65)),[]); + + +% Clean up. Note that GPU memory is tied up in the algorithm object, +% and main RAM in the data objects. +astra_mex_algorithm('delete', alg_id); +astra_mex_data3d('delete', rec_id); +astra_mex_data3d('delete', proj_id); diff --git a/samples/s008_gpu_selection.m b/samples/s008_gpu_selection.m new file mode 100644 index 0000000..252ba0c --- /dev/null +++ b/samples/s008_gpu_selection.m @@ -0,0 +1,37 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); +P = phantom(256); + +% Create a sinogram from a phantom, using GPU #1. (The default is #0) +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom, 1); + + +% Set up the parameters for a reconstruction algorithm using the GPU +rec_id = astra_mex_data2d('create', '-vol', vol_geom); +cfg = astra_struct('SIRT_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; + +% Use GPU #1 for the reconstruction. (The default is #0.) +cfg.option.GPUindex = 1; + +% Run 150 iterations of the algorithm +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id, 150); +rec = astra_mex_data2d('get', rec_id); + + +% Clean up. +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s009_projection_matrix.m b/samples/s009_projection_matrix.m new file mode 100644 index 0000000..c0df79e --- /dev/null +++ b/samples/s009_projection_matrix.m @@ -0,0 +1,45 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% For CPU-based algorithms, a "projector" object specifies the projection +% model used. In this case, we use the "strip" model. +proj_id = astra_create_projector('strip', proj_geom, vol_geom); + +% Generate the projection matrix for this projection model. +% This creates a matrix W where entry w_{i,j} corresponds to the +% contribution of volume element j to detector element i. +matrix_id = astra_mex_projector('matrix', proj_id); + +% Get the projection matrix as a Matlab sparse matrix. +W = astra_mex_matrix('get', matrix_id); + + +% Manually use this projection matrix to do a projection: +P = phantom(256)'; +s = W * P(:); +s = reshape(s, [proj_geom.DetectorCount size(proj_geom.ProjectionAngles, 2)])'; +figure(1), imshow(s,[]); + +% Because Matlab's matrices are stored transposed in memory compared to C++, +% reshaping them to a vector doesn't give the right ordering for multiplication +% with W. We have to take the transpose of the input and output to get the same +% results (up to numerical noise) as using the toolbox directly. + +% Each row of the projection matrix corresponds to a detector element. +% Detector t for angle p is for row 1 + t + p*proj_geom.DetectorCount. +% Each column corresponds to a volume pixel. +% Pixel (x,y) corresponds to column 1 + x + y*vol_geom.GridColCount. + + +astra_mex_projector('delete', proj_id); +astra_mex_matrix('delete', matrix_id); diff --git a/samples/s010_supersampling.m b/samples/s010_supersampling.m new file mode 100644 index 0000000..4436625 --- /dev/null +++ b/samples/s010_supersampling.m @@ -0,0 +1,58 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 3.0, 128, linspace2(0,pi,180)); +P = phantom(256); + +% Because the astra_create_sino_gpu wrapper does not have support for +% all possible algorithm options, we manually create a sinogram +phantom_id = astra_mex_data2d('create', '-vol', vol_geom, P); +sinogram_id = astra_mex_data2d('create', '-sino', proj_geom); +cfg = astra_struct('FP_CUDA'); +cfg.VolumeDataId = phantom_id; +cfg.ProjectionDataId = sinogram_id; + +% Set up 3 rays per detector element +cfg.option.DetectorSuperSampling = 3; + +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('run', alg_id); +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', phantom_id); + +sinogram3 = astra_mex_data2d('get', sinogram_id); + +figure(1); imshow(P, []); +figure(2); imshow(sinogram3, []); + + +% Create a reconstruction, also using supersampling +rec_id = astra_mex_data2d('create', '-vol', vol_geom); +cfg = astra_struct('SIRT_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; +% Set up 3 rays per detector element +cfg.option.DetectorSuperSampling = 3; + +% There is also an option for supersampling during the backprojection step. +% This should be used if your detector pixels are smaller than the voxels. + +% Set up 2 rays per image pixel dimension, for 4 rays total per image pixel. +% cfg.option.PixelSuperSampling = 2; + + +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('iterate', alg_id, 150); +astra_mex_algorithm('delete', alg_id); + +rec = astra_mex_data2d('get', rec_id); +figure(3); imshow(rec, []); + diff --git a/samples/s011_object_info.m b/samples/s011_object_info.m new file mode 100644 index 0000000..a3725f3 --- /dev/null +++ b/samples/s011_object_info.m @@ -0,0 +1,36 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +% Create two volume geometries +vol_geom1 = astra_create_vol_geom(256, 256); +vol_geom2 = astra_create_vol_geom(512, 256); + +% Create volumes +v0 = astra_mex_data2d('create', '-vol', vol_geom1); +v1 = astra_mex_data2d('create', '-vol', vol_geom2); +v2 = astra_mex_data2d('create', '-vol', vol_geom2); + +% Show the currently allocated volumes +astra_mex_data2d('info'); + + +astra_mex_data2d('delete', v2); +astra_mex_data2d('info'); + +astra_mex_data2d('clear'); +astra_mex_data2d('info'); + + + +% The same clear and info command also work for other object types: +astra_mex_algorithm('info'); +astra_mex_data3d('info'); +astra_mex_projector('info'); +astra_mex_matrix('info'); diff --git a/samples/s012_masks.m b/samples/s012_masks.m new file mode 100644 index 0000000..b7b8df6 --- /dev/null +++ b/samples/s012_masks.m @@ -0,0 +1,60 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + + +% In this example we will create a reconstruction in a circular region, +% instead of the usual rectangle. + +% This is done by placing a circular mask on the square reconstruction volume: + +c = -127.5:127.5; +[x y] = meshgrid(-127.5:127.5,-127.5:127.5); +mask = (x.^2 + y.^2 < 127.5^2); + +figure(1); imshow(mask, []); + + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,50)); + +% As before, create a sinogram from a phantom +P = phantom(256); +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); +figure(2); imshow(P, []); +figure(3); imshow(sinogram, []); + +% Create a data object for the reconstruction +rec_id = astra_mex_data2d('create', '-vol', vol_geom); + +% Create a data object for the mask +mask_id = astra_mex_data2d('create', '-vol', vol_geom, mask); + +% Set up the parameters for a reconstruction algorithm using the GPU +cfg = astra_struct('SIRT_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; +cfg.option.ReconstructionMaskId = mask_id; + +% Create the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); + +% Run 150 iterations of the algorithm +astra_mex_algorithm('iterate', alg_id, 150); + +% Get the result +rec = astra_mex_data2d('get', rec_id); +figure(4); imshow(rec, []); + +% Clean up. Note that GPU memory is tied up in the algorithm object, +% and main RAM in the data objects. +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', mask_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s013_constraints.m b/samples/s013_constraints.m new file mode 100644 index 0000000..9cb9612 --- /dev/null +++ b/samples/s013_constraints.m @@ -0,0 +1,47 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +% In this example we will create a reconstruction constrained to +% greyvalues between 0 and 1 + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,50)); + +% As before, create a sinogram from a phantom +P = phantom(256); +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); +figure(1); imshow(P, []); +figure(2); imshow(sinogram, []); + +% Create a data object for the reconstruction +rec_id = astra_mex_data2d('create', '-vol', vol_geom); + +% Set up the parameters for a reconstruction algorithm using the GPU +cfg = astra_struct('SIRT_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; +cfg.option.MinConstraint = 0; +cfg.option.MaxConstraint = 1; + +% Create the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); + +% Run 150 iterations of the algorithm +astra_mex_algorithm('iterate', alg_id, 150); + +% Get the result +rec = astra_mex_data2d('get', rec_id); +figure(3); imshow(rec, []); + +% Clean up. Note that GPU memory is tied up in the algorithm object, +% and main RAM in the data objects. +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s014_FBP.m b/samples/s014_FBP.m new file mode 100644 index 0000000..7cce28f --- /dev/null +++ b/samples/s014_FBP.m @@ -0,0 +1,47 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% As before, create a sinogram from a phantom +P = phantom(256); +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); +figure(1); imshow(P, []); +figure(2); imshow(sinogram, []); + +% Create a data object for the reconstruction +rec_id = astra_mex_data2d('create', '-vol', vol_geom); + +% create configuration +cfg = astra_struct('FBP_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; +cfg.FilterType = 'Ram-Lak'; + +% possible values for FilterType: +% none, ram-lak, shepp-logan, cosine, hamming, hann, tukey, lanczos, +% triangular, gaussian, barlett-hann, blackman, nuttall, blackman-harris, +% blackman-nuttall, flat-top, kaiser, parzen + + +% Create and run the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); +astra_mex_algorithm('run', alg_id); + +% Get the result +rec = astra_mex_data2d('get', rec_id); +figure(3); imshow(rec, []); + +% Clean up. Note that GPU memory is tied up in the algorithm object, +% and main RAM in the data objects. +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/samples/s015_fp_bp.m b/samples/s015_fp_bp.m new file mode 100644 index 0000000..815f478 --- /dev/null +++ b/samples/s015_fp_bp.m @@ -0,0 +1,62 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + + +% This example demonstrates using the FP and BP primitives with Matlab's lsqr +% solver. Calls to FP (astra_create_sino_cuda) and +% BP (astra_create_backprojection_cuda) are wrapped in a function astra_wrap, +% and a handle to this function is passed to lsqr. + +% Because in this case the inputs/outputs of FP and BP have to be vectors +% instead of images (matrices), the calls require reshaping to and from vectors. + +function s015_fp_bp + + +% FP/BP wrapper function +function Y = astra_wrap(X,T) + if strcmp(T, 'notransp') + % X is passed as a vector. Reshape it into an image. + [sid, s] = astra_create_sino_cuda(reshape(X,[vol_geom.GridRowCount vol_geom.GridColCount])', proj_geom, vol_geom); + astra_mex_data2d('delete', sid); + % now s is the sinogram. Reshape it back into a vector + Y = reshape(s',[prod(size(s)) 1]); + else + % X is passed as a vector. Reshape it into a sinogram. + v = astra_create_backprojection_cuda(reshape(X, [proj_geom.DetectorCount size(proj_geom.ProjectionAngles,2)])', proj_geom, vol_geom); + % now v is the resulting volume. Reshape it back into a vector + Y = reshape(v',[prod(size(v)) 1]); + end +end + + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% Create a 256x256 phantom image using matlab's built-in phantom() function +P = phantom(256); + +% Create a sinogram using the GPU. +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); + +% Reshape the sinogram into a vector +b = reshape(sinogram',[prod(size(sinogram)) 1]); + +% Call Matlab's lsqr with ASTRA FP and BP +Y = lsqr(@astra_wrap,b,1e-4,25); + +% Reshape the result into an image +Y = reshape(Y,[vol_geom.GridRowCount vol_geom.GridColCount])'; +imshow(Y,[]); + + +astra_mex_data2d('delete', sinogram_id); + +end diff --git a/samples/s016_plots.m b/samples/s016_plots.m new file mode 100644 index 0000000..1eeca58 --- /dev/null +++ b/samples/s016_plots.m @@ -0,0 +1,54 @@ +%------------------------------------------------------------------------ +% This file is part of the +% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") +% +% Copyright: iMinds-Vision Lab, University of Antwerp +% License: Open Source under GPLv3 +% Contact: mailto:astra@ua.ac.be +% Website: http://astra.ua.ac.be +%------------------------------------------------------------------------ + +vol_geom = astra_create_vol_geom(256, 256); +proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180)); + +% As before, create a sinogram from a phantom +P = phantom(256); +[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom); +figure(1); imshow(P, []); +figure(2); imshow(sinogram, []); + +% Create a data object for the reconstruction +rec_id = astra_mex_data2d('create', '-vol', vol_geom); + +% Set up the parameters for a reconstruction algorithm using the GPU +cfg = astra_struct('SIRT_CUDA'); +cfg.ReconstructionDataId = rec_id; +cfg.ProjectionDataId = sinogram_id; + +% Create the algorithm object from the configuration structure +alg_id = astra_mex_algorithm('create', cfg); + +% Run 1500 iterations of the algorithm one at a time, keeping track of errors +nIters = 1500; +phantom_error = zeros(1, nIters); +residual_error = zeros(1, nIters); +for i = 1:nIters; + % Run a single iteration + astra_mex_algorithm('iterate', alg_id, 1); + + residual_error(i) = astra_mex_algorithm('get_res_norm', alg_id); + rec = astra_mex_data2d('get', rec_id); + phantom_error(i) = sqrt(sumsqr(rec - P)); +end + +% Get the result +rec = astra_mex_data2d('get', rec_id); +figure(3); imshow(rec, []); + +figure(4); plot(residual_error) +figure(5); plot(phantom_error) + +% Clean up. +astra_mex_algorithm('delete', alg_id); +astra_mex_data2d('delete', rec_id); +astra_mex_data2d('delete', sinogram_id); diff --git a/src/Algorithm.cpp b/src/Algorithm.cpp new file mode 100644 index 0000000..38ae65d --- /dev/null +++ b/src/Algorithm.cpp @@ -0,0 +1,64 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Algorithm.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CAlgorithm::CAlgorithm() : m_bShouldAbort(false), configCheckData(0) { + +} + +//---------------------------------------------------------------------------------------- +// Destructor +CAlgorithm::~CAlgorithm() { + +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CAlgorithm::getInformation() +{ + map<string, boost::any> result; + result["Initialized"] = getInformation("Initialized"); + return result; +}; + +//---------------------------------------------------------------------------------------- +// Information - Specific +boost::any CAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "Initialized") { return m_bIsInitialized ? "yes" : "no"; } + return std::string("not found"); +} + +} // namespace astra diff --git a/src/ArtAlgorithm.cpp b/src/ArtAlgorithm.cpp new file mode 100644 index 0000000..77ab5ab --- /dev/null +++ b/src/ArtAlgorithm.cpp @@ -0,0 +1,331 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ArtAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CArtAlgorithm::type = "ART"; + +//---------------------------------------------------------------------------------------- +// Constructor +CArtAlgorithm::CArtAlgorithm() + : CReconstructionAlgorithm2D() +{ + m_fLambda = 1.0f; + m_iRayCount = 0; + m_iCurrentRay = 0; + m_piProjectionOrder = NULL; + m_piDetectorOrder = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CArtAlgorithm::~CArtAlgorithm() +{ + if (m_piProjectionOrder != NULL) + delete[] m_piProjectionOrder; + if (m_piDetectorOrder != NULL) + delete[] m_piDetectorOrder; +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CArtAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_piDetectorOrder = NULL; + m_piProjectionOrder = NULL; + m_iRayCount = 0; + m_iCurrentRay = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CArtAlgorithm::clear() +{ + CReconstructionAlgorithm2D::clear(); + if (m_piDetectorOrder) { + delete[] m_piDetectorOrder; + m_piDetectorOrder = NULL; + } + if (m_piProjectionOrder) { + delete[] m_piProjectionOrder; + m_piProjectionOrder = NULL; + } + m_fLambda = 1.0f; + m_iRayCount = 0; + m_iCurrentRay = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CArtAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "ART", "Error in ReconstructionAlgorithm2D initialization"); + + // check ray order list + for (int i = 0; i < m_iRayCount; i++) { + if (m_piProjectionOrder[i] < 0 || m_piProjectionOrder[i] > m_pSinogram->getAngleCount()-1) { + ASTRA_CONFIG_CHECK(false, "ART", "Invalid value in ray order list."); + } + if (m_piDetectorOrder[i] < 0 || m_piDetectorOrder[i] > m_pSinogram->getDetectorCount()-1) { + ASTRA_CONFIG_CHECK(false, "ART", "Invalid value in ray order list."); + } + } + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CArtAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ArtAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // ray order + string projOrder = _cfg.self->getOption("RayOrder", "sequential"); + CC.markOptionParsed("RayOrder"); + m_iCurrentRay = 0; + m_iRayCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount() * + m_pProjector->getProjectionGeometry()->getDetectorCount(); + if (projOrder == "sequential") { + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = (int)floor((float)i / m_pProjector->getProjectionGeometry()->getDetectorCount()); + m_piDetectorOrder[i] = i % m_pProjector->getProjectionGeometry()->getDetectorCount(); + } + } else if (projOrder == "custom") { + vector<float32> rayOrderList = _cfg.self->getOptionNumericalArray("RayOrderList"); + m_iRayCount = rayOrderList.size() / 2; + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = static_cast<int>(rayOrderList[2*i]); + m_piDetectorOrder[i] = static_cast<int>(rayOrderList[2*i+1]); + } + CC.markOptionParsed("RayOrderList"); + } else { + return false; + } + + m_fLambda = _cfg.self->getOptionNumerical("Lambda", 1.0f); + CC.markOptionParsed("Lambda"); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CArtAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // ray order + m_iCurrentRay = 0; + m_iRayCount = _pProjector->getProjectionGeometry()->getDetectorCount() * + _pProjector->getProjectionGeometry()->getProjectionAngleCount(); + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = (int)floor((float)i / _pProjector->getProjectionGeometry()->getDetectorCount()); + m_piDetectorOrder[i] = i % _pProjector->getProjectionGeometry()->getDetectorCount(); + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Set the relaxation factor. +void CArtAlgorithm::setLambda(float32 _fLambda) +{ + m_fLambda = _fLambda; +} + +//---------------------------------------------------------------------------------------- +// Set the order in which the rays will be selected +void CArtAlgorithm::setRayOrder(int* _piProjectionOrder, int* _piDetectorOrder, int _iRayCount) +{ + if (m_piDetectorOrder) { + delete[] m_piDetectorOrder; + m_piDetectorOrder = NULL; + } + if (m_piProjectionOrder) { + delete[] m_piProjectionOrder; + m_piProjectionOrder = NULL; + } + + m_iCurrentRay = 0; + m_iRayCount = _iRayCount; + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = _piProjectionOrder[i]; + m_piDetectorOrder[i] = _piDetectorOrder[i]; + } +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CArtAlgorithm::getInformation() +{ + map<string, boost::any> res; + res["RayOrder"] = getInformation("RayOrder"); + res["Lambda"] = getInformation("Lambda"); + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CArtAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "Lambda") { return m_fLambda; } + if (_sIdentifier == "RayOrder") { + vector<float32> res; + for (int i = 0; i < m_iRayCount; i++) { + res.push_back(m_piProjectionOrder[i]); + } + for (int i = 0; i < m_iRayCount; i++) { + res.push_back(m_piDetectorOrder[i]); + } + return res; + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CArtAlgorithm::run(int _iNrIterations) +{ + // check initialized + assert(m_bIsInitialized); + + // variables + int iIteration, iPixel; + int iUsedPixels, iProjection, iDetector; + float32 fRayForwardProj, fSumSquaredWeights; + float32 fProjectionDifference, fBackProjectionFactor; + + // create a pixel buffer + int iPixelBufferSize = m_pProjector->getProjectionWeightsCount(0); + SPixelWeight* pPixels = new SPixelWeight[iPixelBufferSize]; + + // start iterations + for (iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) { + + // step0: compute single weight rays + iProjection = m_piProjectionOrder[m_iCurrentRay]; + iDetector = m_piDetectorOrder[m_iCurrentRay]; + m_iCurrentRay = (m_iCurrentRay + 1) % m_iRayCount; + + if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue; + + m_pProjector->computeSingleRayWeights(iProjection, iDetector, pPixels, iPixelBufferSize, iUsedPixels); + + // step1: forward projections + fRayForwardProj = 0.0f; + fSumSquaredWeights = 0.0f; + for (iPixel = iUsedPixels-1; iPixel >= 0; --iPixel) { + if (m_bUseReconstructionMask && m_pReconstructionMask->getDataConst()[pPixels[iPixel].m_iIndex] == 0) continue; + + fRayForwardProj += pPixels[iPixel].m_fWeight * m_pReconstruction->getDataConst()[pPixels[iPixel].m_iIndex]; + fSumSquaredWeights += pPixels[iPixel].m_fWeight * pPixels[iPixel].m_fWeight; + } + if (fSumSquaredWeights == 0) continue; + + // step2: difference + fProjectionDifference = m_pSinogram->getData2D()[iProjection][iDetector] - fRayForwardProj; + + // step3: back projection + fBackProjectionFactor = m_fLambda * fProjectionDifference / fSumSquaredWeights; + for (iPixel = iUsedPixels-1; iPixel >= 0; --iPixel) { + + // pixel must be loose + if (m_bUseReconstructionMask && m_pReconstructionMask->getDataConst()[pPixels[iPixel].m_iIndex] == 0) continue; + + // update + m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] += fBackProjectionFactor * pPixels[iPixel].m_fWeight; + + // constraints + if (m_bUseMinConstraint && m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] < m_fMinValue) { + m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] = m_fMinValue; + } + if (m_bUseMaxConstraint && m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] > m_fMaxValue) { + m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] = m_fMaxValue; + } + } + + } + delete[] pPixels; + + // update statistics + m_pReconstruction->updateStatistics(); +} + + +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/AstraObjectFactory.cpp b/src/AstraObjectFactory.cpp new file mode 100644 index 0000000..195c431 --- /dev/null +++ b/src/AstraObjectFactory.cpp @@ -0,0 +1,39 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/AstraObjectFactory.h" + +using namespace std; + +namespace astra { + +DEFINE_SINGLETON2(CAstraObjectFactory<CAlgorithm, AlgorithmTypeList>); +DEFINE_SINGLETON2(CAstraObjectFactory<CProjector2D, Projector2DTypeList>); +DEFINE_SINGLETON2(CAstraObjectFactory<CProjector3D, Projector3DTypeList>); + +} // end namespace diff --git a/src/AstraObjectManager.cpp b/src/AstraObjectManager.cpp new file mode 100644 index 0000000..597119d --- /dev/null +++ b/src/AstraObjectManager.cpp @@ -0,0 +1,43 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/AstraObjectManager.h" + + +namespace astra { + +int CAstraIndexManager::m_iPreviousIndex = 0; + +DEFINE_SINGLETON(CAstraObjectManager<CProjector2D>); +DEFINE_SINGLETON(CAstraObjectManager<CProjector3D>); +DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data2D>); +DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data3D>); +DEFINE_SINGLETON(CAstraObjectManager<CAlgorithm>); +DEFINE_SINGLETON(CAstraObjectManager<CSparseMatrix>); + +} // end namespace diff --git a/src/AsyncAlgorithm.cpp b/src/AsyncAlgorithm.cpp new file mode 100644 index 0000000..431dbbc --- /dev/null +++ b/src/AsyncAlgorithm.cpp @@ -0,0 +1,195 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/AsyncAlgorithm.h" +#include "astra/AstraObjectFactory.h" + +#ifndef USE_PTHREAD +#include <boost/bind.hpp> +#endif + +namespace astra { + +CAsyncAlgorithm::CAsyncAlgorithm() +{ + m_bInitialized = false; +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; +} + +CAsyncAlgorithm::CAsyncAlgorithm(CAlgorithm* _pAlg) +{ + m_pAlg = _pAlg; + m_bInitialized = (m_pAlg != 0); +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + m_bDone = false; + m_bAutoFree = false; +} + +bool CAsyncAlgorithm::initialize(const Config& _cfg) +{ + if (m_bInitialized && m_bThreadStarted) { +#ifndef USE_PTHREADS + m_pThread->join(); + delete m_pThread; +#else + pthread_join(m_thread, 0); +#endif + } +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + m_pAlg = 0; + m_bDone = false; + + m_pAlg = CAlgorithmFactory::getSingleton().create(_cfg); + if (m_pAlg && !m_pAlg->isInitialized()) { + if (m_bAutoFree) + delete m_pAlg; + m_pAlg = 0; + } + m_bInitialized = (m_pAlg != 0); + m_bAutoFree = true; + return m_bInitialized; +} + +bool CAsyncAlgorithm::initialize(CAlgorithm* _pAlg) +{ + if (m_bInitialized && m_bThreadStarted) { +#ifndef USE_PTHREADS + m_pThread->join(); + delete m_pThread; +#else + pthread_join(m_thread, 0); +#endif + } +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + m_bDone = false; + + m_pAlg = _pAlg; + m_bInitialized = (m_pAlg != 0); + m_bAutoFree = false; + return m_bInitialized; +} + +CAsyncAlgorithm::~CAsyncAlgorithm() +{ + if (m_bInitialized && m_bThreadStarted) { +#ifndef USE_PTHREADS + m_pThread->join(); + delete m_pThread; +#else + pthread_join(m_thread, 0); +#endif + } +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + + if (m_bInitialized && m_bAutoFree) { + delete m_pAlg; + m_pAlg = 0; + } +} + +#ifdef USE_PTHREADS +void* runAsync_pthreads(void* data) +{ + CAsyncAlgorithm::AsyncThreadInfo *info = (CAsyncAlgorithm::AsyncThreadInfo*)data; + info->m_pAlg->run(info->m_iIterations); + *info->m_pDone = true; + return 0; +} +#endif + +void CAsyncAlgorithm::run(int _iNrIterations) +{ + if (!m_bInitialized) + return; + +#ifndef USE_PTHREADS + m_pThread = new boost::thread( + boost::bind(&CAsyncAlgorithm::runWrapped, + this, _iNrIterations)); +#else + m_ThreadInfo.m_iIterations = _iNrIterations; + m_ThreadInfo.m_pAlg = m_pAlg; + m_ThreadInfo.m_pDone = &this->m_bDone; + pthread_create(&m_thread, 0, runAsync_pthreads, &this->m_ThreadInfo); +#endif +} + +void CAsyncAlgorithm::runWrapped(int _iNrIterations) +{ + m_pAlg->run(_iNrIterations); + m_bDone = true; +} + +void CAsyncAlgorithm::timedJoin(int _milliseconds) +{ +#ifndef USE_PTHREADS + if (m_pThread) { + boost::posix_time::milliseconds rel(_milliseconds); + bool res = m_pThread->timed_join(rel); + if (res) { + delete m_pThread; + m_pThread = 0; + m_bThreadStarted = false; + } + } +#else + if (m_bThreadStarted) { + struct timespec abstime; + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += _milliseconds / 1000; + abstime.tv_nsec += (_milliseconds % 1000) * 1000000L; + int err = pthread_timedjoin_np(m_thread, 0, &abstime); + if (err == 0) { + m_bThreadStarted = false; + } + } +#endif +} + +void CAsyncAlgorithm::signalAbort() +{ + if (m_pAlg) + m_pAlg->signalAbort(); +} + +} diff --git a/src/BackProjectionAlgorithm.cpp b/src/BackProjectionAlgorithm.cpp new file mode 100644 index 0000000..cf8c9ca --- /dev/null +++ b/src/BackProjectionAlgorithm.cpp @@ -0,0 +1,192 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/BackProjectionAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CBackProjectionAlgorithm::type = "BP"; + +//---------------------------------------------------------------------------------------- +// Constructor +CBackProjectionAlgorithm::CBackProjectionAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CBackProjectionAlgorithm::CBackProjectionAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CBackProjectionAlgorithm::~CBackProjectionAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CBackProjectionAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CBackProjectionAlgorithm::clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CBackProjectionAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "BP", "Error in ReconstructionAlgorithm2D initialization"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("BackProjectionAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CBackProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CBackProjectionAlgorithm::_init() +{ + +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CBackProjectionAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CBackProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CBackProjectionAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_bShouldAbort = false; + + CDataProjectorInterface* pBackProjector; + + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultBPPolicy(m_pReconstruction, m_pSinogram), // backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + m_pReconstruction->setData(0.0f); + pBackProjector->project(); + + ASTRA_DELETE(pBackProjector); +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/CglsAlgorithm.cpp b/src/CglsAlgorithm.cpp new file mode 100644 index 0000000..f3e1be1 --- /dev/null +++ b/src/CglsAlgorithm.cpp @@ -0,0 +1,297 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CglsAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCglsAlgorithm::type = "CGLS"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCglsAlgorithm::CCglsAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CCglsAlgorithm::CCglsAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCglsAlgorithm::~CCglsAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CCglsAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + r = NULL; + w = NULL; + z = NULL; + p = NULL; + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + m_iIteration = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CCglsAlgorithm::clear() +{ + CReconstructionAlgorithm2D::_clear(); + ASTRA_DELETE(r); + ASTRA_DELETE(w); + ASTRA_DELETE(z); + ASTRA_DELETE(p); + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + m_iIteration = 0; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCglsAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "CGLS", "Error in ReconstructionAlgorithm2D initialization"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCglsAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CglsAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // member variables + r = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + w = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + z = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + p = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCglsAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // member variables + r = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + w = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + z = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + p = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCglsAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCglsAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCglsAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + // data projectors + CDataProjectorInterface* pForwardProjector; + CDataProjectorInterface* pBackProjector; + + // forward projection data projector + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultFPPolicy(p, w), // forward projection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // backprojection data projector + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultBPPolicy(z, r), // backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + + + int i; + + if (m_iIteration == 0) { + // r = b; + r->copyData(m_pSinogram->getData()); + + // z = A'*b; + z->setData(0.0f); + pBackProjector->project(); + if (m_bUseMinConstraint) + z->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + z->clampMax(m_fMaxValue); + + // p = z; + p->copyData(z->getData()); + + // gamma = dot(z,z); + gamma = 0.0f; + for (i = 0; i < z->getSize(); ++i) { + gamma += z->getData()[i] * z->getData()[i]; + } + m_iIteration++; + } + + + // start iterations + for (int iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) { + + // w = A*p; + pForwardProjector->project(); + + // alpha = gamma/dot(w,w); + float32 tmp = 0; + for (i = 0; i < w->getSize(); ++i) { + tmp += w->getData()[i] * w->getData()[i]; + } + alpha = gamma / tmp; + + // x = x + alpha*p; + for (i = 0; i < m_pReconstruction->getSize(); ++i) { + m_pReconstruction->getData()[i] += alpha * p->getData()[i]; + } + + // r = r - alpha*w; + for (i = 0; i < r->getSize(); ++i) { + r->getData()[i] -= alpha * w->getData()[i]; + } + + // z = A'*r; + z->setData(0.0f); + pBackProjector->project(); + + // CHECKME: should these be here? + if (m_bUseMinConstraint) + z->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + z->clampMax(m_fMaxValue); + + // beta = 1/gamma; + beta = 1.0f / gamma; + + // gamma = dot(z,z); + gamma = 0; + for (i = 0; i < z->getSize(); ++i) { + gamma += z->getData()[i] * z->getData()[i]; + } + + // beta = gamma*beta; + beta *= gamma; + + // p = z + beta*p; + for (i = 0; i < z->getSize(); ++i) { + p->getData()[i] = z->getData()[i] + beta * p->getData()[i]; + } + + m_iIteration++; + } + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ConeProjectionGeometry3D.cpp b/src/ConeProjectionGeometry3D.cpp new file mode 100644 index 0000000..129e675 --- /dev/null +++ b/src/ConeProjectionGeometry3D.cpp @@ -0,0 +1,228 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ConeProjectionGeometry3D.h" + +#include <boost/lexical_cast.hpp> +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CConeProjectionGeometry3D::CConeProjectionGeometry3D() : + CProjectionGeometry3D() +{ + m_fOriginSourceDistance = 0.0f; + m_fOriginDetectorDistance = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CConeProjectionGeometry3D::CConeProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles, + _fOriginSourceDistance, + _fOriginDetectorDistance); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CConeProjectionGeometry3D::~CConeProjectionGeometry3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CConeProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ConeProjectionGeometry3D", this, _cfg); + + // initialization of parent class + CProjectionGeometry3D::initialize(_cfg); + + // Required: DistanceOriginDetector + XMLNode* node = _cfg.self->getSingleNode("DistanceOriginDetector"); + ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginDetector tag specified."); + m_fOriginDetectorDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginDetector"); + + // Required: DetectorOriginSource + node = _cfg.self->getSingleNode("DistanceOriginSource"); + ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginSource tag specified."); + m_fOriginSourceDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginSource"); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CConeProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) +{ + _initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles); + + m_fOriginSourceDistance = _fOriginSourceDistance; + m_fOriginDetectorDistance = _fOriginDetectorDistance; + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CConeProjectionGeometry3D::clone() const +{ + CConeProjectionGeometry3D* res = new CConeProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfProjectionAngles, m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + res->m_fOriginSourceDistance = m_fOriginSourceDistance; + res->m_fOriginDetectorDistance = m_fOriginDetectorDistance; + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CConeProjectionGeometry3D::isEqual(const CProjectionGeometry3D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry3D + const CConeProjectionGeometry3D* pGeom2 = dynamic_cast<const CConeProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + if (m_fOriginSourceDistance != pGeom2->m_fOriginSourceDistance) return false; + if (m_fOriginDetectorDistance != pGeom2->m_fOriginDetectorDistance) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CConeProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "cone"); +} + +//---------------------------------------------------------------------------------------- +void CConeProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type", "cone"); + _sNode->addChildNode("DetectorSpacingX", m_fDetectorSpacingX); + _sNode->addChildNode("DetectorSpacingY", m_fDetectorSpacingY); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + _sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); + _sNode->addChildNode("DistanceOriginDetector", m_fOriginDetectorDistance); + _sNode->addChildNode("DistanceOriginSource", m_fOriginSourceDistance); +} +//---------------------------------------------------------------------------------------- + +CVector3D CConeProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + float32 fSrcX = -m_fOriginSourceDistance; + float32 fSrcY = 0.0f; + float32 fSrcZ = 0.0f; + + float32 fDetX = m_fOriginDetectorDistance; + float32 fDetY = 0.0f; + float32 fDetZ = 0.0f; + + fDetY += indexToDetectorOffsetX(_iDetectorIndex); + fDetZ += indexToDetectorOffsetY(_iDetectorIndex); + + float32 angle = m_pfProjectionAngles[_iProjectionIndex]; + + #define ROTATE(name,alpha) do { float32 tX = f##name##X * cos(alpha) - f##name##Y * sin(alpha); f##name##Y = f##name##X * sin(alpha) + f##name##Y * cos(alpha); f##name##X = tX; } while(0) + + ROTATE(Src, angle); + ROTATE(Det, angle); + + #undef ROTATE + + CVector3D ret(fDetX - fSrcX, fDetY - fSrcY, fDetZ - fDetZ); + return ret; +} + +} // end namespace astra diff --git a/src/ConeVecProjectionGeometry3D.cpp b/src/ConeVecProjectionGeometry3D.cpp new file mode 100644 index 0000000..875a2c7 --- /dev/null +++ b/src/ConeVecProjectionGeometry3D.cpp @@ -0,0 +1,232 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ConeVecProjectionGeometry3D.h" + +#include <cstring> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CConeVecProjectionGeometry3D::CConeVecProjectionGeometry3D() : + CProjectionGeometry3D() +{ + m_pProjectionAngles = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CConeVecProjectionGeometry3D::CConeVecProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SConeProjection* _pProjectionAngles + ) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CConeVecProjectionGeometry3D::~CConeVecProjectionGeometry3D() +{ + delete[] m_pProjectionAngles; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CConeVecProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ConeVecProjectionGeometry3D", this, _cfg); + + XMLNode* node; + + // TODO: Fix up class hierarchy... this class doesn't fit very well. + // initialization of parent class + //CProjectionGeometry3D::initialize(_cfg); + + // Required: DetectorRowCount + node = _cfg.self->getSingleNode("DetectorRowCount"); + ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorRowCount"); + + // Required: DetectorColCount + node = _cfg.self->getSingleNode("DetectorColCount"); + ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorColCount tag specified."); + m_iDetectorColCount = boost::lexical_cast<int>(node->getContent()); + m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount; + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorColCount"); + + // Required: Vectors + node = _cfg.self->getSingleNode("Vectors"); + ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No Vectors tag specified."); + vector<double> data = node->getContentNumericalArrayDouble(); + CC.markNodeParsed("Vectors"); + ASTRA_DELETE(node); + ASTRA_CONFIG_CHECK(data.size() % 12 == 0, "ConeVecProjectionGeometry3D", "Vectors doesn't consist of 12-tuples."); + m_iProjectionAngleCount = data.size() / 12; + m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount]; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + SConeProjection& p = m_pProjectionAngles[i]; + p.fSrcX = data[12*i + 0]; + p.fSrcY = data[12*i + 1]; + p.fSrcZ = data[12*i + 2]; + p.fDetUX = data[12*i + 6]; + p.fDetUY = data[12*i + 7]; + p.fDetUZ = data[12*i + 8]; + p.fDetVX = data[12*i + 9]; + p.fDetVY = data[12*i + 10]; + p.fDetVZ = data[12*i + 11]; + + // The backend code currently expects the corner of the detector, while + // the matlab interface supplies the center + p.fDetSX = data[12*i + 3] - 0.5f * m_iDetectorRowCount * p.fDetVX - 0.5f * m_iDetectorColCount * p.fDetUX; + p.fDetSY = data[12*i + 4] - 0.5f * m_iDetectorRowCount * p.fDetVY - 0.5f * m_iDetectorColCount * p.fDetUY; + p.fDetSZ = data[12*i + 5] - 0.5f * m_iDetectorRowCount * p.fDetVZ - 0.5f * m_iDetectorColCount * p.fDetUZ; + } + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CConeVecProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SConeProjection* _pProjectionAngles) +{ + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorRowCount = _iDetectorRowCount; + m_iDetectorColCount = _iDetectorColCount; + m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pProjectionAngles[i] = _pProjectionAngles[i]; + + // TODO: check? + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CConeVecProjectionGeometry3D::clone() const +{ + CConeVecProjectionGeometry3D* res = new CConeVecProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount]; + memcpy(res->m_pProjectionAngles, m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount); + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CConeVecProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CConeProjectionGeometry3D + const CConeVecProjectionGeometry3D* pGeom2 = dynamic_cast<const CConeVecProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + //if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + //if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CConeVecProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "cone3d_vec"); +} + +//---------------------------------------------------------------------------------------- +void CConeVecProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type","cone3d_vec"); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + // TODO: + //_sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); +} + +CVector3D CConeVecProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + const SConeProjection& p = m_pProjectionAngles[_iProjectionIndex]; + int u = _iDetectorIndex % m_iDetectorColCount; + int v = _iDetectorIndex / m_iDetectorColCount; + + return CVector3D(p.fDetSX + (u+0.5)*p.fDetUX + (v+0.5)*p.fDetVX - p.fSrcX, p.fDetSY + (u+0.5)*p.fDetUY + (v+0.5)*p.fDetVY - p.fSrcY, p.fDetSZ + (u+0.5)*p.fDetUZ + (v+0.5)*p.fDetVZ - p.fSrcZ); +} + + +//---------------------------------------------------------------------------------------- + +bool CConeVecProjectionGeometry3D::_check() +{ + // TODO + return true; +} + +} // end namespace astra diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..8c5cbf5 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,166 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Config.h" + +// For explicit ConfigStackCheck instantiations +#include "astra/Algorithm.h" +#include "astra/VolumeGeometry2D.h" +#include "astra/VolumeGeometry3D.h" +#include "astra/ProjectionGeometry2D.h" +#include "astra/ProjectionGeometry3D.h" +#include "astra/Projector2D.h" +#include "astra/Projector3D.h" + +using namespace astra; +using namespace std; + +//----------------------------------------------------------------------------- +// default constructor +Config::Config() +{ + self = 0; +} + +//----------------------------------------------------------------------------- +// not so default constructor +Config::Config(XMLNode* _self) +{ + self = _self; +} + +Config::~Config() +{ + delete self; + self = 0; +} + +template <class T> +ConfigStackCheck<T>::ConfigStackCheck(const char *_name, T* _obj, const Config& _cfg) + : object(_obj), cfg(&_cfg), name(_name) +{ + assert(object); + assert(cfg); + if (!object->configCheckData) { + object->configCheckData = new ConfigCheckData; + object->configCheckData->parseDepth = 0; + } + + object->configCheckData->parseDepth++; +} + +template <class T> +ConfigStackCheck<T>::~ConfigStackCheck() +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + + + if (object->configCheckData->parseDepth == 1) { + // Entirely done with parsing this Config object + + if (object->isInitialized()) + stopParsing(); + + delete object->configCheckData; + object->configCheckData = 0; + } else { + object->configCheckData->parseDepth--; + } +} + + +// returns true if no unused nodes/options +template <class T> +bool ConfigStackCheck<T>::stopParsing() +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + + if (object->configCheckData->parseDepth > 1) + return true; + + // If this was the top-level parse function, check + + std::string errors; + + std::list<XMLNode*> nodes = cfg->self->getNodes(); + for (std::list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) + { + std::string nodeName = (*i)->getName(); + + if (nodeName == "Option") { + nodeName = (*i)->getAttribute("key", ""); + if (object->configCheckData->parsedOptions.find(nodeName) == object->configCheckData->parsedOptions.end()) { + if (!errors.empty()) errors += ", "; + errors += nodeName; + } + } else { + if (object->configCheckData->parsedNodes.find(nodeName) == object->configCheckData->parsedNodes.end()) { + if (!errors.empty()) errors += ", "; + errors += nodeName; + } + } + } + for (std::list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) + delete (*i); + nodes.clear(); + + if (!errors.empty()) { + cout << "Warning: " << name << ": unused configuration options: " << errors << std::endl; + return false; + } + + return true; +} + +template <class T> +void ConfigStackCheck<T>::markNodeParsed(const std::string& nodeName) +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + object->configCheckData->parsedNodes.insert(nodeName); +} + +template <class T> +void ConfigStackCheck<T>::markOptionParsed(const std::string& nodeName) +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + object->configCheckData->parsedOptions.insert(nodeName); +} + + +template class ConfigStackCheck<CAlgorithm>; +template class ConfigStackCheck<CProjectionGeometry2D>; +template class ConfigStackCheck<CProjectionGeometry3D>; +template class ConfigStackCheck<CVolumeGeometry2D>; +template class ConfigStackCheck<CVolumeGeometry3D>; +template class ConfigStackCheck<CProjector2D>; +template class ConfigStackCheck<CProjector3D>; + diff --git a/src/ConvexHullAlgorithm.cpp b/src/ConvexHullAlgorithm.cpp new file mode 100644 index 0000000..e769420 --- /dev/null +++ b/src/ConvexHullAlgorithm.cpp @@ -0,0 +1,239 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ConvexHullAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CConvexHullAlgorithm::type = "ConvexHull"; + +//---------------------------------------------------------------------------------------- +// Constructor +CConvexHullAlgorithm::CConvexHullAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CConvexHullAlgorithm::CConvexHullAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstructionMask) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstructionMask); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CConvexHullAlgorithm::~CConvexHullAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CConvexHullAlgorithm::_clear() +{ + m_bIsInitialized = false; + + m_pProjectionPixelWeight = NULL; + m_pReconstructionMask = NULL; + m_pSinogram = NULL; + + m_pProjector = NULL; + m_pDataProjector = NULL; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CConvexHullAlgorithm::clear() +{ + m_bIsInitialized = false; + + ASTRA_DELETE(m_pProjectionPixelWeight); + m_pReconstructionMask = NULL; + m_pSinogram = NULL; + + m_pProjector = NULL; + ASTRA_DELETE(m_pDataProjector); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CConvexHullAlgorithm::_check() +{ + ASTRA_CONFIG_CHECK(m_pReconstructionMask, "ConvexHull", "Invalid ReconstructionMask Object"); + ASTRA_CONFIG_CHECK(m_pReconstructionMask->isInitialized(), "ConvexHull", "Invalid ReconstructionMask Object"); + ASTRA_CONFIG_CHECK(m_pProjectionPixelWeight, "ConvexHull", "Invalid ProjectionPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pProjectionPixelWeight->isInitialized(), "ConvexHull", "Invalid ProjectionPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pSinogram, "ConvexHull", "Invalid Sinogram Object"); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "ConvexHull", "Invalid Sinogram Object"); + + ASTRA_CONFIG_CHECK(m_pDataProjector, "ConvexHull", "Invalid Data Projector Policy"); + ASTRA_CONFIG_CHECK(m_pProjector, "ConvexHull", "Invalid Projector Object"); + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ConvexHull", "Invalid Projector Object"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CConvexHullAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // reconstruction mask + node = _cfg.self->getSingleNode("ConvexHullDataId"); + ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CConvexHullAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstructionMask) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstructionMask = _pReconstructionMask; + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CConvexHullAlgorithm::_init() +{ + // create data objects + m_pProjectionPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pProjectionPixelWeight->setData(0); + + // forward projection data projector + m_pDataProjector = dispatchDataProjector( + m_pProjector, + //SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + TotalPixelWeightBySinogramPolicy(m_pSinogram, m_pProjectionPixelWeight) // pixel weight * sinogram + ); +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CConvexHullAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CConvexHullAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CConvexHullAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_pReconstructionMask->setData(1.0f); + + // loop angles + for (int iProjection = 0; iProjection < m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); ++iProjection) { + + m_pProjectionPixelWeight->setData(0.0f); + + // project + m_pDataProjector->projectSingleProjection(iProjection); + + // loop values and set to zero + for (int iPixel = 0; iPixel < m_pReconstructionMask->getSize(); ++iPixel) { + if (m_pProjectionPixelWeight->getData()[iPixel] == 0) { + m_pReconstructionMask->getData()[iPixel] = 0; + } + } + + } + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/CudaBackProjectionAlgorithm.cpp b/src/CudaBackProjectionAlgorithm.cpp new file mode 100644 index 0000000..7d597b8 --- /dev/null +++ b/src/CudaBackProjectionAlgorithm.cpp @@ -0,0 +1,96 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaBackProjectionAlgorithm.h" + +#include "../cuda/2d/astra.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaBackProjectionAlgorithm::type = "BP_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaBackProjectionAlgorithm::CCudaBackProjectionAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaBackProjectionAlgorithm::~CCudaBackProjectionAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new BPalgo(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaBackProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, 1, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new BPalgo(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaBackProjectionAlgorithm3D.cpp b/src/CudaBackProjectionAlgorithm3D.cpp new file mode 100644 index 0000000..b60adf1 --- /dev/null +++ b/src/CudaBackProjectionAlgorithm3D.cpp @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaBackProjectionAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaBackProjectionAlgorithm3D::type = "BP3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D() +{ + m_bIsInitialized = false; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaBackProjectionAlgorithm3D::~CCudaBackProjectionAlgorithm3D() +{ + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaBackProjectionAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "BP3D_CUDA", "Error in ReconstructionAlgorithm3D initialization"); + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm3D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaBackProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaBackProjectionAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaBackProjectionAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaBackProjectionAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + + const CProjectionGeometry3D* projgeom = pSinoMem->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *pReconMem->getGeometry(); + + if (conegeom) { + astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else if (par3dgeom) { + astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + par3dgeom->getProjectionCount(), + par3dgeom->getDetectorColCount(), + par3dgeom->getDetectorRowCount(), + par3dgeom->getDetectorSpacingX(), + par3dgeom->getDetectorSpacingY(), + par3dgeom->getProjectionAngles(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else if (parvec3dgeom) { + astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else if (conevecgeom) { + astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conevecgeom->getProjectionCount(), + conevecgeom->getDetectorColCount(), + conevecgeom->getDetectorRowCount(), + conevecgeom->getProjectionVectors(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else { + ASTRA_ASSERT(false); + } + +} + + +} // namespace astra diff --git a/src/CudaCglsAlgorithm.cpp b/src/CudaCglsAlgorithm.cpp new file mode 100644 index 0000000..c408638 --- /dev/null +++ b/src/CudaCglsAlgorithm.cpp @@ -0,0 +1,98 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaCglsAlgorithm.h" + +#include "../cuda/2d/cgls.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaCglsAlgorithm::type = "CGLS_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaCglsAlgorithm::CCudaCglsAlgorithm() +{ + m_bIsInitialized = false; + CReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaCglsAlgorithm::~CCudaCglsAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaCglsAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaCglsAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::CGLS(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaCglsAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::CGLS(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaCglsAlgorithm3D.cpp b/src/CudaCglsAlgorithm3D.cpp new file mode 100644 index 0000000..07569a2 --- /dev/null +++ b/src/CudaCglsAlgorithm3D.cpp @@ -0,0 +1,314 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaCglsAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaCglsAlgorithm3D::type = "CGLS3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaCglsAlgorithm3D::CCudaCglsAlgorithm3D() +{ + m_bIsInitialized = false; + m_pCgls = 0; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; + m_iDetectorSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaCglsAlgorithm3D::CCudaCglsAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaCglsAlgorithm3D::~CCudaCglsAlgorithm3D() +{ + delete m_pCgls; + m_pCgls = 0; + + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaCglsAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "CGLS3D", "Error in ReconstructionAlgorithm3D initialization"); + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaCglsAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaCglsAlgorithm3D", this, _cfg); + + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + m_pCgls = new AstraCGLS3d(); + + m_bAstraCGLSInit = false; + + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaCglsAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + m_pCgls = new AstraCGLS3d; + + m_bAstraCGLSInit = false; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaCglsAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaCglsAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaCglsAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry(); + + bool ok = true; + + if (!m_bAstraCGLSInit) { + + ok &= m_pCgls->setGPUIndex(m_iGPUIndex); + + ok &= m_pCgls->setReconstructionGeometry(volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount()); +/* + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles) +*/ + fprintf(stderr, "01: %d\n", ok); + + if (conegeom) { + ok &= m_pCgls->setConeGeometry(conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles()); + } else if (parvec3dgeom) { + ok &= m_pCgls->setPar3DGeometry(parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors()); + } else if (conevec3dgeom) { + ok &= m_pCgls->setConeGeometry(conevec3dgeom->getProjectionCount(), + conevec3dgeom->getDetectorColCount(), + conevec3dgeom->getDetectorRowCount(), + conevec3dgeom->getProjectionVectors()); + } else { + ASTRA_ASSERT(false); + } + fprintf(stderr, "02: %d\n", ok); + + ok &= m_pCgls->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling); + + if (m_bUseReconstructionMask) + ok &= m_pCgls->enableVolumeMask(); +#if 0 + if (m_bUseSinogramMask) + ok &= m_pCgls->enableSinogramMask(); +#endif + + ASTRA_ASSERT(ok); + fprintf(stderr, "03: %d\n", ok); + + ok &= m_pCgls->init(); + fprintf(stderr, "04: %d\n", ok); + + ASTRA_ASSERT(ok); + + m_bAstraCGLSInit = true; + + } + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + + ok = m_pCgls->setSinogram(pSinoMem->getDataConst(), m_pSinogram->getGeometry()->getDetectorColCount()); + + fprintf(stderr, "1: %d\n", ok); + ASTRA_ASSERT(ok); + + if (m_bUseReconstructionMask) { + CFloat32VolumeData3DMemory* pRMaskMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstructionMask); + ASTRA_ASSERT(pRMaskMem); + ok &= m_pCgls->setVolumeMask(pRMaskMem->getDataConst(), volgeom.getGridColCount()); + } +#if 0 + if (m_bUseSinogramMask) { + CFloat32ProjectionData3DMemory* pSMaskMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogramMask); + ASTRA_ASSERT(pSMaskMem); + ok &= m_pCgls->setSinogramMask(pSMaskMem->getDataConst(), m_pSinogramMask->getGeometry()->getDetectorColCount()); + } +#endif + fprintf(stderr, "2: %d\n", ok); + + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + ok &= m_pCgls->setStartReconstruction(pReconMem->getDataConst(), + volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); + fprintf(stderr, "3: %d\n", ok); + +#if 0 + if (m_bUseMinConstraint) + ok &= m_pCgls->setMinConstraint(m_fMinValue); + if (m_bUseMaxConstraint) + ok &= m_pCgls->setMaxConstraint(m_fMaxValue); +#endif + fprintf(stderr, "4: %d\n", ok); + + ok &= m_pCgls->iterate(_iNrIterations); + ASTRA_ASSERT(ok); + fprintf(stderr, "5: %d\n", ok); + + ok &= m_pCgls->getReconstruction(pReconMem->getData(), + volgeom.getGridColCount()); + fprintf(stderr, "6: %d\n", ok); + ASTRA_ASSERT(ok); + + +} +//---------------------------------------------------------------------------------------- +void CCudaCglsAlgorithm3D::signalAbort() +{ + if (m_bIsInitialized && m_pCgls) { + m_pCgls->signalAbort(); + } +} + +bool CCudaCglsAlgorithm3D::getResidualNorm(float32& _fNorm) +{ + if (!m_bIsInitialized || !m_pCgls) + return false; + + _fNorm = m_pCgls->computeDiffNorm(); + + return true; +} + + + +} // namespace astra diff --git a/src/CudaDartMaskAlgorithm.cpp b/src/CudaDartMaskAlgorithm.cpp new file mode 100644 index 0000000..9c9b83f --- /dev/null +++ b/src/CudaDartMaskAlgorithm.cpp @@ -0,0 +1,166 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartMaskAlgorithm.h" + +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/algo.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartMaskAlgorithm::type = "DARTMASK_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartMaskAlgorithm::CCudaDartMaskAlgorithm() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartMaskAlgorithm::~CCudaDartMaskAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartMaskAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("SegmentationDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSegmentation = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("SegmentationDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("MaskDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("MaskDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Connectivity + m_iConn = (unsigned int)_cfg.self->getOptionNumerical("Connectivity", 8); + CC.markOptionParsed("Connectivity"); + + // Option: Threshold + m_iThreshold = (unsigned int)_cfg.self->getOptionNumerical("Threshold", 1); + CC.markOptionParsed("Threshold"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartMaskAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry2D& volgeom = *m_pSegmentation->getGeometry(); + unsigned int width = volgeom.getGridColCount(); + unsigned int height = volgeom.getGridRowCount(); + + astraCUDA::setGPUIndex(m_iGPUIndex); + astraCUDA::dartMask(m_pMask->getData(), m_pSegmentation->getDataConst(), m_iConn, m_iRadius, m_iThreshold, width, height); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartMaskAlgorithm::_check() +{ + + // connectivity: 4 of 8 + + // gpuindex >= 0 + + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartMaskAlgorithm::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartMaskAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDartMaskAlgorithm3D.cpp b/src/CudaDartMaskAlgorithm3D.cpp new file mode 100644 index 0000000..7965587 --- /dev/null +++ b/src/CudaDartMaskAlgorithm3D.cpp @@ -0,0 +1,168 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartMaskAlgorithm3D.h" + +#include "../cuda/3d/darthelper3d.h" +#include "../cuda/3d/dims3d.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartMaskAlgorithm3D::type = "DARTMASK3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartMaskAlgorithm3D::CCudaDartMaskAlgorithm3D() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartMaskAlgorithm3D::~CCudaDartMaskAlgorithm3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartMaskAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("SegmentationDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSegmentation = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("SegmentationDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("MaskDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pMask = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("MaskDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Connectivity + m_iConn = (unsigned int)_cfg.self->getOptionNumerical("Connectivity", 8); + CC.markOptionParsed("Connectivity"); + + // Option: Threshold + m_iThreshold = (unsigned int)_cfg.self->getOptionNumerical("Threshold", 1); + CC.markOptionParsed("Threshold"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm3D::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartMaskAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry3D& volgeom = *m_pSegmentation->getGeometry(); + astraCUDA3d::SDimensions3D dims; + dims.iVolX = volgeom.getGridColCount(); + dims.iVolY = volgeom.getGridRowCount(); + dims.iVolZ = volgeom.getGridSliceCount(); + + astraCUDA3d::setGPUIndex(m_iGPUIndex); + astraCUDA3d::dartMasking(m_pMask->getData(), m_pSegmentation->getDataConst(), m_iConn, m_iRadius, m_iThreshold, dims); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartMaskAlgorithm3D::_check() +{ + + // connectivity: 4 of 8 + + // gpuindex >= 0 + + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartMaskAlgorithm3D::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartMaskAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDartSmoothingAlgorithm.cpp b/src/CudaDartSmoothingAlgorithm.cpp new file mode 100644 index 0000000..91cde6d --- /dev/null +++ b/src/CudaDartSmoothingAlgorithm.cpp @@ -0,0 +1,158 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartSmoothingAlgorithm.h" + +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/algo.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartSmoothingAlgorithm::type = "DARTSMOOTHING_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartSmoothingAlgorithm::CCudaDartSmoothingAlgorithm() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartSmoothingAlgorithm::~CCudaDartSmoothingAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartSmoothingAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartSmoothingAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("InDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pIn = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("InDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("OutDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pOut = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("OutDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Radius + m_fB = (float)_cfg.self->getOptionNumerical("Intensity", 0.3f); + CC.markOptionParsed("Intensity"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartSmoothingAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry2D& volgeom = *m_pIn->getGeometry(); + unsigned int width = volgeom.getGridColCount(); + unsigned int height = volgeom.getGridRowCount(); + + astraCUDA::setGPUIndex(m_iGPUIndex); + + astraCUDA::dartSmoothing(m_pOut->getData(), m_pIn->getDataConst(), m_fB, m_iRadius, width, height); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartSmoothingAlgorithm::_check() +{ + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartSmoothingAlgorithm::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartSmoothingAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDartSmoothingAlgorithm3D.cpp b/src/CudaDartSmoothingAlgorithm3D.cpp new file mode 100644 index 0000000..50ef847 --- /dev/null +++ b/src/CudaDartSmoothingAlgorithm3D.cpp @@ -0,0 +1,160 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartSmoothingAlgorithm3D.h" + +#include "../cuda/3d/darthelper3d.h" +#include "../cuda/3d/dims3d.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartSmoothingAlgorithm3D::type = "DARTSMOOTHING3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartSmoothingAlgorithm3D::CCudaDartSmoothingAlgorithm3D() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartSmoothingAlgorithm3D::~CCudaDartSmoothingAlgorithm3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartSmoothingAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartSmoothingAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("InDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pIn = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("InDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("OutDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pOut = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("OutDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Intensity + m_fB = (float)_cfg.self->getOptionNumerical("Intensity", 0.3f); + CC.markOptionParsed("Intensity"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartSmoothingAlgorithm3D::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartSmoothingAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry3D& volgeom = *m_pIn->getGeometry(); + astraCUDA3d::SDimensions3D dims; + dims.iVolX = volgeom.getGridColCount(); + dims.iVolY = volgeom.getGridRowCount(); + dims.iVolZ = volgeom.getGridSliceCount(); + + astraCUDA3d::setGPUIndex(m_iGPUIndex); + astraCUDA3d::dartSmoothing(m_pOut->getData(), m_pIn->getDataConst(), m_fB, m_iRadius, dims); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartSmoothingAlgorithm3D::_check() +{ + // geometry of inData must match that of outData + + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartSmoothingAlgorithm3D::getInformation() +{ + map<string,boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartSmoothingAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDataOperationAlgorithm.cpp b/src/CudaDataOperationAlgorithm.cpp new file mode 100644 index 0000000..ed2ac94 --- /dev/null +++ b/src/CudaDataOperationAlgorithm.cpp @@ -0,0 +1,208 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDataOperationAlgorithm.h" + +#include "../cuda/2d/dataop.h" +#include "../cuda/2d/algo.h" +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/arith.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDataOperationAlgorithm::type = "DataOperation_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDataOperationAlgorithm::CCudaDataOperationAlgorithm() +{ + m_pMask = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDataOperationAlgorithm::~CCudaDataOperationAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDataOperationAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CCudaDataOperationAlgorithm", this, _cfg); + + // operation + XMLNode* node = _cfg.self->getSingleNode("Operation"); + ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No Operation tag specified."); + m_sOperation = node->getContent(); + m_sOperation.erase(std::remove(m_sOperation.begin(), m_sOperation.end(), ' '), m_sOperation.end()); + ASTRA_DELETE(node); + CC.markNodeParsed("Operation"); + + // data + node = _cfg.self->getSingleNode("DataId"); + ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No DataId tag specified."); + vector<string> data = node->getContentArray(); + for (vector<string>::iterator it = data.begin(); it != data.end(); it++){ + int id = boost::lexical_cast<int>(*it); + m_pData.push_back(dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id))); + } + ASTRA_DELETE(node); + CC.markNodeParsed("DataId"); + + // scalar + node = _cfg.self->getSingleNode("Scalar"); + ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No Scalar tag specified."); + m_fScalar = node->getContentNumericalArray(); + ASTRA_DELETE(node); + CC.markNodeParsed("Scalar"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + if (_cfg.self->hasOption("MaskId")) { + int id = boost::lexical_cast<int>(_cfg.self->getOption("MaskId")); + m_pMask = dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("MaskId"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDataOperationAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + astraCUDA::setGPUIndex(m_iGPUIndex); + + if (m_sOperation == "$1*s1" || m_sOperation == "$1.*s1") // data * scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + if (m_pMask == NULL) + astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), m_fScalar[0], width, height); + else + astraCUDA::processVolCopy<astraCUDA::opMulMask,astraCUDA::VOL>(m_pData[0]->getData(), m_pMask->getDataConst(), m_fScalar[0], width, height); + } + else if (m_sOperation == "$1/s1" || m_sOperation == "$1./s1") // data / scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + if (m_pMask == NULL) + astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), 1.0f/m_fScalar[0], width, height); + else + astraCUDA::processVolCopy<astraCUDA::opMulMask,astraCUDA::VOL>(m_pData[0]->getData(), m_pMask->getDataConst(), 1.0f/m_fScalar[0], width, height); + } + else if (m_sOperation == "$1+s1") // data + scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), m_fScalar[0], width, height); + } + else if (m_sOperation == "$1-s1") // data - scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), -m_fScalar[0], width, height); + } + else if (m_sOperation == "$1.*$2") // data .* data + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), m_pData[1]->getDataConst(), width, height); + } + else if (m_sOperation == "$1+$2") // data + data + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), m_pData[1]->getDataConst(), width, height); + } + +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDataOperationAlgorithm::_check() +{ + // s*: 1 data + 1 scalar + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDataOperationAlgorithm::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDataOperationAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaEMAlgorithm.cpp b/src/CudaEMAlgorithm.cpp new file mode 100644 index 0000000..44dd0fd --- /dev/null +++ b/src/CudaEMAlgorithm.cpp @@ -0,0 +1,97 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaEMAlgorithm.h" + +#include "../cuda/2d/em.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaEMAlgorithm::type = "EM_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaEMAlgorithm::CCudaEMAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaEMAlgorithm::~CCudaEMAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaEMAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaEMAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::EM(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaEMAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::EM(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaFDKAlgorithm3D.cpp b/src/CudaFDKAlgorithm3D.cpp new file mode 100644 index 0000000..8f9e7b8 --- /dev/null +++ b/src/CudaFDKAlgorithm3D.cpp @@ -0,0 +1,192 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaFDKAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaFDKAlgorithm3D::type = "FDK_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D() +{ + m_bIsInitialized = false; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaFDKAlgorithm3D::~CCudaFDKAlgorithm3D() +{ + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaFDKAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "CUDA_FDK", "Error in ReconstructionAlgorithm3D initialization"); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + ASTRA_CONFIG_CHECK(dynamic_cast<const CConeProjectionGeometry3D*>(projgeom), "CUDA_FDK", "Error setting FDK geometry"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaFDKAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaFDKAlgorithm3D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + m_bShortScan = _cfg.self->getOptionBool("ShortScan", false); + CC.markOptionParsed("ShortScan"); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaFDKAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaFDKAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaFDKAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaFDKAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry(); + + ASTRA_ASSERT(conegeom); + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + + + bool ok = true; + + ok = astraCudaFDK(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles(), + m_bShortScan, m_iGPUIndex, m_iVoxelSuperSampling); + + ASTRA_ASSERT(ok); + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/CudaFilteredBackProjectionAlgorithm.cpp b/src/CudaFilteredBackProjectionAlgorithm.cpp new file mode 100644 index 0000000..75a1534 --- /dev/null +++ b/src/CudaFilteredBackProjectionAlgorithm.cpp @@ -0,0 +1,442 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <astra/CudaFilteredBackProjectionAlgorithm.h> +#include <boost/lexical_cast.hpp> +#include <cstring> + +#include "astra/AstraObjectManager.h" + +#include <astra/Logger.h> + +using namespace std; +using namespace astra; + +string CCudaFilteredBackProjectionAlgorithm::type = "FBP_CUDA"; + +CCudaFilteredBackProjectionAlgorithm::CCudaFilteredBackProjectionAlgorithm() +{ + m_bIsInitialized = false; + CReconstructionAlgorithm2D::_clear(); + m_pFBP = 0; + m_pfFilter = NULL; + m_fFilterParameter = -1.0f; + m_fFilterD = 1.0f; +} + +CCudaFilteredBackProjectionAlgorithm::~CCudaFilteredBackProjectionAlgorithm() +{ + if(m_pfFilter != NULL) + { + delete [] m_pfFilter; + m_pfFilter = NULL; + } + + if(m_pFBP != NULL) + { + delete m_pFBP; + m_pFBP = NULL; + } +} + +bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaFilteredBackProjectionAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) + { + clear(); + } + + // sinogram data + XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ProjectionDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // filter type + node = _cfg.self->getSingleNode("FilterType"); + if(node != NULL) + { + m_eFilter = _convertStringToFilter(node->getContent().c_str()); + } + else + { + m_eFilter = FILTER_RAMLAK; + } + CC.markNodeParsed("FilterType"); + ASTRA_DELETE(node); + + // filter + node = _cfg.self->getSingleNode("FilterSinogramId"); + if(node != NULL) + { + int id = boost::lexical_cast<int>(node->getContent()); + const CFloat32ProjectionData2D * pFilterData = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + m_iFilterWidth = pFilterData->getGeometry()->getDetectorCount(); + int iFilterProjectionCount = pFilterData->getGeometry()->getProjectionAngleCount(); + + m_pfFilter = new float[m_iFilterWidth * iFilterProjectionCount]; + memcpy(m_pfFilter, pFilterData->getDataConst(), sizeof(float) * m_iFilterWidth * iFilterProjectionCount); + } + else + { + m_iFilterWidth = 0; + m_pfFilter = NULL; + } + CC.markNodeParsed("FilterSinogramId"); // TODO: Only for some types! + ASTRA_DELETE(node); + + // filter parameter + node = _cfg.self->getSingleNode("FilterParameter"); + if(node != NULL) + { + float fParameter = boost::lexical_cast<float>(node->getContent()); + m_fFilterParameter = fParameter; + } + else + { + m_fFilterParameter = -1.0f; + } + CC.markNodeParsed("FilterParameter"); // TODO: Only for some types! + ASTRA_DELETE(node); + + // D value + node = _cfg.self->getSingleNode("FilterD"); + if(node != NULL) + { + float fD = boost::lexical_cast<float>(node->getContent()); + m_fFilterD = fD; + } + else + { + m_fFilterD = 1.0f; + } + CC.markNodeParsed("FilterD"); // TODO: Only for some types! + ASTRA_DELETE(node); + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + + // Pixel supersampling factor + m_iPixelSuperSampling = (int)_cfg.self->getOptionNumerical("PixelSuperSampling", 1); + CC.markOptionParsed("PixelSuperSampling"); + + + m_pFBP = new AstraFBP; + m_bAstraFBPInit = false; + + // success + m_bIsInitialized = true; + return m_bIsInitialized; +} + +bool CCudaFilteredBackProjectionAlgorithm::initialize(CFloat32ProjectionData2D * _pSinogram, CFloat32VolumeData2D * _pReconstruction, E_FBPFILTER _eFilter, const float * _pfFilter /* = NULL */, int _iFilterWidth /* = 0 */, int _iGPUIndex /* = 0 */, float _fFilterParameter /* = -1.0f */) +{ + // if already initialized, clear first + if (m_bIsInitialized) + { + clear(); + } + + // required classes + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + m_iGPUIndex = _iGPUIndex; + + m_eFilter = _eFilter; + m_iFilterWidth = _iFilterWidth; + + // success + m_bIsInitialized = true; + + m_pFBP = new AstraFBP; + + m_bAstraFBPInit = false; + + if(_pfFilter != NULL) + { + int iFilterElementCount = 0; + + if((_eFilter != FILTER_SINOGRAM) && (_eFilter != FILTER_RSINOGRAM)) + { + iFilterElementCount = _iFilterWidth; + } + else + { + iFilterElementCount = m_pSinogram->getAngleCount(); + } + + m_pfFilter = new float[iFilterElementCount]; + memcpy(m_pfFilter, _pfFilter, iFilterElementCount * sizeof(float)); + } + else + { + m_pfFilter = NULL; + } + + m_fFilterParameter = _fFilterParameter; + + return m_bIsInitialized; +} + +void CCudaFilteredBackProjectionAlgorithm::run(int _iNrIterations /* = 0 */) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + if (!m_bAstraFBPInit) { + + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + const CParallelProjectionGeometry2D& projgeom = *dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry()); + + bool ok = true; + + // TODO: off-center geometry, non-square pixels + ok &= m_pFBP->setReconstructionGeometry(volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getPixelLengthX()); + // TODO: off-center geometry + ok &= m_pFBP->setProjectionGeometry(projgeom.getProjectionAngleCount(), + projgeom.getDetectorCount(), + projgeom.getProjectionAngles(), + projgeom.getDetectorWidth()); + + ok &= m_pFBP->setPixelSuperSampling(m_iPixelSuperSampling); + + ASTRA_ASSERT(ok); + + const float *pfTOffsets = m_pSinogram->getGeometry()->getExtraDetectorOffset(); + if (pfTOffsets) + ok &= m_pFBP->setTOffsets(pfTOffsets); + ASTRA_ASSERT(ok); + + ok &= m_pFBP->init(m_iGPUIndex); + ASTRA_ASSERT(ok); + + ok &= m_pFBP->setSinogram(m_pSinogram->getDataConst(), projgeom.getDetectorCount()); + ASTRA_ASSERT(ok); + + ok &= m_pFBP->setFilter(m_eFilter, m_pfFilter, m_iFilterWidth, m_fFilterD, m_fFilterParameter); + ASTRA_ASSERT(ok); + + m_bAstraFBPInit = true; + } + + bool ok = m_pFBP->run(); + ASTRA_ASSERT(ok); + + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + ok &= m_pFBP->getReconstruction(m_pReconstruction->getData(), volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); +} + +bool CCudaFilteredBackProjectionAlgorithm::check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pSinogram, "FBP_CUDA", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "FBP_CUDA", "Invalid Reconstruction Data Object."); + + if((m_eFilter == FILTER_PROJECTION) || (m_eFilter == FILTER_SINOGRAM) || (m_eFilter == FILTER_RPROJECTION) || (m_eFilter == FILTER_RSINOGRAM)) + { + ASTRA_CONFIG_CHECK(m_pfFilter, "FBP_CUDA", "Invalid filter pointer."); + } + + // check initializations + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "FBP_CUDA", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "FBP_CUDA", "Reconstruction Data Object Not Initialized."); + + // check gpu index + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FBP_CUDA", "GPUIndex must be a non-negative integer."); + // check pixel supersampling + ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 0, "FBP_CUDA", "PixelSuperSampling must be a non-negative integer."); + + + // success + m_bIsInitialized = true; + return true; +} + +static int calcNextPowerOfTwo(int _iValue) +{ + int iOutput = 1; + + while(iOutput < _iValue) + { + iOutput *= 2; + } + + return iOutput; +} + +int CCudaFilteredBackProjectionAlgorithm::calcIdealRealFilterWidth(int _iDetectorCount) +{ + return calcNextPowerOfTwo(_iDetectorCount); +} + +int CCudaFilteredBackProjectionAlgorithm::calcIdealFourierFilterWidth(int _iDetectorCount) +{ + return (calcNextPowerOfTwo(_iDetectorCount) / 2 + 1); +} + +static bool stringCompareLowerCase(const char * _stringA, const char * _stringB) +{ + int iCmpReturn = 0; + +#ifdef _MSC_VER + iCmpReturn = _stricmp(_stringA, _stringB); +#else + iCmpReturn = strcasecmp(_stringA, _stringB); +#endif + + return (iCmpReturn == 0); +} + +E_FBPFILTER CCudaFilteredBackProjectionAlgorithm::_convertStringToFilter(const char * _filterType) +{ + E_FBPFILTER output = FILTER_NONE; + + if(stringCompareLowerCase(_filterType, "ram-lak")) + { + output = FILTER_RAMLAK; + } + else if(stringCompareLowerCase(_filterType, "shepp-logan")) + { + output = FILTER_SHEPPLOGAN; + } + else if(stringCompareLowerCase(_filterType, "cosine")) + { + output = FILTER_COSINE; + } + else if(stringCompareLowerCase(_filterType, "hamming")) + { + output = FILTER_HAMMING; + } + else if(stringCompareLowerCase(_filterType, "hann")) + { + output = FILTER_HANN; + } + else if(stringCompareLowerCase(_filterType, "none")) + { + output = FILTER_NONE; + } + else if(stringCompareLowerCase(_filterType, "tukey")) + { + output = FILTER_TUKEY; + } + else if(stringCompareLowerCase(_filterType, "lanczos")) + { + output = FILTER_LANCZOS; + } + else if(stringCompareLowerCase(_filterType, "triangular")) + { + output = FILTER_TRIANGULAR; + } + else if(stringCompareLowerCase(_filterType, "gaussian")) + { + output = FILTER_GAUSSIAN; + } + else if(stringCompareLowerCase(_filterType, "barlett-hann")) + { + output = FILTER_BARTLETTHANN; + } + else if(stringCompareLowerCase(_filterType, "blackman")) + { + output = FILTER_BLACKMAN; + } + else if(stringCompareLowerCase(_filterType, "nuttall")) + { + output = FILTER_NUTTALL; + } + else if(stringCompareLowerCase(_filterType, "blackman-harris")) + { + output = FILTER_BLACKMANHARRIS; + } + else if(stringCompareLowerCase(_filterType, "blackman-nuttall")) + { + output = FILTER_BLACKMANNUTTALL; + } + else if(stringCompareLowerCase(_filterType, "flat-top")) + { + output = FILTER_FLATTOP; + } + else if(stringCompareLowerCase(_filterType, "kaiser")) + { + output = FILTER_KAISER; + } + else if(stringCompareLowerCase(_filterType, "parzen")) + { + output = FILTER_PARZEN; + } + else if(stringCompareLowerCase(_filterType, "projection")) + { + output = FILTER_PROJECTION; + } + else if(stringCompareLowerCase(_filterType, "sinogram")) + { + output = FILTER_SINOGRAM; + } + else if(stringCompareLowerCase(_filterType, "rprojection")) + { + output = FILTER_RPROJECTION; + } + else if(stringCompareLowerCase(_filterType, "rsinogram")) + { + output = FILTER_RSINOGRAM; + } + else + { + cerr << "Failed to convert \"" << _filterType << "\" into a filter." << endl; + } + + return output; +} + +void CCudaFilteredBackProjectionAlgorithm::testGenFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, cufftComplex * _pFilter, int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount) +{ + genFilter(_eFilter, _fD, _iProjectionCount, _pFilter, _iFFTRealDetectorCount, _iFFTFourierDetectorCount); +} + +int CCudaFilteredBackProjectionAlgorithm::getGPUCount() +{ + return 0; +} diff --git a/src/CudaForwardProjectionAlgorithm.cpp b/src/CudaForwardProjectionAlgorithm.cpp new file mode 100644 index 0000000..965c4af --- /dev/null +++ b/src/CudaForwardProjectionAlgorithm.cpp @@ -0,0 +1,276 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaForwardProjectionAlgorithm.h" + +#ifdef ASTRA_CUDA + +#include "../cuda/2d/astra.h" + +#include <driver_types.h> +#include <cuda_runtime_api.h> + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/CudaProjector2D.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaForwardProjectionAlgorithm::type = "FP_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaForwardProjectionAlgorithm::CCudaForwardProjectionAlgorithm() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaForwardProjectionAlgorithm::~CCudaForwardProjectionAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaForwardProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm", this, _cfg); + + // sinogram data + XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No ProjectionDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // volume data + node = _cfg.self->getSingleNode("VolumeDataId"); + ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No VolumeDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("VolumeDataId"); + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Detector supersampling factor + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + + + // This isn't used yet, but passing it is not something to warn about + node = _cfg.self->getSingleNode("ProjectorId"); + if (node) { + id = boost::lexical_cast<int>(node->getContent()); + CProjector2D *projector = CProjector2DManager::getSingleton().get(id); + if (!dynamic_cast<CCudaProjector2D*>(projector)) { + cout << "Warning: non-CUDA Projector2D passed to FP_CUDA" << std::endl; + } + delete node; + } + CC.markNodeParsed("ProjectorId"); + + + + // return success + return check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaForwardProjectionAlgorithm::initialize(CProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram, + int _iGPUindex, int _iDetectorSuperSampling) +{ + // store classes + //m_pProjectionGeometry = _pProjectionGeometry; + //m_pReconstructionGeometry = _pReconstructionGeometry; + m_pVolume = _pVolume; + m_pSinogram = _pSinogram; + + m_iDetectorSuperSampling = _iDetectorSuperSampling; + m_iGPUIndex = _iGPUindex; + + // return success + return check(); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaForwardProjectionAlgorithm::check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pSinogram, "FP_CUDA", "No valid projection data object found."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "FP_CUDA", "Projection data not initialized."); + ASTRA_CONFIG_CHECK(m_pVolume, "FP_CUDA", "No valid volume data object found."); + ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "FP_CUDA", "Volume data not initialized."); + + // check restrictions + //int iImageSideBlocks = m_pReconstructionGeometry->getGridColCount() / G_BLOCKIMAGESIZE; + //ASTRA_CONFIG_CHECK((iImageSideBlocks * G_BLOCKIMAGESIZE) == m_pVolume->getWidth(), "FP_CUDA", "Volume Width must be a multiple of G_BLOCKIMAGESIZE"); + //ASTRA_CONFIG_CHECK((iImageSideBlocks * G_BLOCKIMAGESIZE) == m_pVolume->getHeight(), "FP_CUDA", "Volume Height must be a multiple of G_BLOCKIMAGESIZE"); + //ASTRA_CONFIG_CHECK(m_pProjectionGeometry->getDetectorCount() == (m_pVolume->getWidth() * 3 / 2), "SIRT_CUDA", "Number of detectors must be 1.5 times the width of the image"); + + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FP_CUDA", "GPUIndex must be a non-negative integer."); + + // success + m_bIsInitialized = true; + return true; +} + +void CCudaForwardProjectionAlgorithm::setGPUIndex(int _iGPUIndex) +{ + m_iGPUIndex = _iGPUIndex; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaForwardProjectionAlgorithm::getInformation() +{ + map<string, boost::any> res; + res["ProjectionGeometry"] = getInformation("ProjectionGeometry"); + res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["VolumeDataId"] = getInformation("VolumeDataId"); + res["GPUindex"] = getInformation("GPUindex"); + res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaForwardProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); } + if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); } + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "VolumeDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pVolume); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "GPUindex") { return m_iGPUIndex; } + if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Run +void CCudaForwardProjectionAlgorithm::run(int) +{ + // check initialized + assert(m_bIsInitialized); + + CVolumeGeometry2D* pVolGeom = m_pVolume->getGeometry(); + const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry()); + + bool ok = false; + if (parProjGeom) { + ok = astraCudaFP(m_pVolume->getDataConst(), m_pSinogram->getData(), + pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(), + parProjGeom->getProjectionAngleCount(), + parProjGeom->getDetectorCount(), + parProjGeom->getProjectionAngles(), + parProjGeom->getExtraDetectorOffset(), parProjGeom->getDetectorWidth() / pVolGeom->getPixelLengthX(), + m_iDetectorSuperSampling, m_iGPUIndex); + + } else if (fanProjGeom) { + + ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(), + pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(), + fanProjGeom->getProjectionAngleCount(), + fanProjGeom->getDetectorCount(), + fanProjGeom->getProjectionAngles(), + fanProjGeom->getOriginSourceDistance(), + fanProjGeom->getOriginDetectorDistance(), + pVolGeom->getPixelLengthX(), + fanProjGeom->getDetectorWidth(), + m_iDetectorSuperSampling, m_iGPUIndex); + + } else if (fanVecProjGeom) { + + // Rescale projs to fPixelSize == 1 + float fPixelSize = pVolGeom->getPixelLengthX(); + const astraCUDA::SFanProjection* projs; + projs = fanVecProjGeom->getProjectionVectors(); + + astraCUDA::SFanProjection* scaledProjs = new astraCUDA::SFanProjection[fanVecProjGeom->getProjectionAngleCount()]; +#define SCALE(name,i,alpha) do { scaledProjs[i].f##name##X = projs[i].f##name##X * alpha; scaledProjs[i].f##name##Y = projs[i].f##name##Y * alpha; } while (0) + for (unsigned int i = 0; i < fanVecProjGeom->getProjectionAngleCount(); ++i) { + SCALE(Src,i,1.0f/fPixelSize); + SCALE(DetS,i,1.0f/fPixelSize); + SCALE(DetU,i,1.0f/fPixelSize); + } + + + ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(), + pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(), + fanVecProjGeom->getProjectionAngleCount(), + fanVecProjGeom->getDetectorCount(), + scaledProjs, + /* 1.0f / pVolGeom->getPixelLengthX(), */ + m_iDetectorSuperSampling, m_iGPUIndex); + + delete[] scaledProjs; + + } else { + + ASTRA_ASSERT(false); + + } + + ASTRA_ASSERT(ok); + +} + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaForwardProjectionAlgorithm3D.cpp b/src/CudaForwardProjectionAlgorithm3D.cpp new file mode 100644 index 0000000..e9289f1 --- /dev/null +++ b/src/CudaForwardProjectionAlgorithm3D.cpp @@ -0,0 +1,311 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaForwardProjectionAlgorithm3D.h" + +#ifdef ASTRA_CUDA + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/CudaProjector3D.h" +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaForwardProjectionAlgorithm3D::type = "FP3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaForwardProjectionAlgorithm3D::CCudaForwardProjectionAlgorithm3D() +{ + m_bIsInitialized = false; + m_iGPUIndex = 0; + m_iDetectorSuperSampling = 1; + m_pProjector = 0; + m_pProjections = 0; + m_pVolume = 0; + +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaForwardProjectionAlgorithm3D::~CCudaForwardProjectionAlgorithm3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm3D", this, _cfg); + + XMLNode* node; + int id; + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pProjections = dynamic_cast<CFloat32ProjectionData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("VolumeDataId"); + ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No VolumeDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pVolume = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("VolumeDataId"); + + // optional: projector + node = _cfg.self->getSingleNode("ProjectorId"); + if (node) { + id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector3DManager::getSingleton().get(id); + ASTRA_DELETE(node); + } else { + m_pProjector = 0; // TODO: or manually construct default projector? + } + CC.markNodeParsed("ProjectorId"); + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + + // success + m_bIsInitialized = check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + + +bool CCudaForwardProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjections, + CFloat32VolumeData3DMemory* _pVolume, + int _iGPUindex, int _iDetectorSuperSampling) +{ + m_pProjector = _pProjector; + + // required classes + m_pProjections = _pProjections; + m_pVolume = _pVolume; + + m_iDetectorSuperSampling = _iDetectorSuperSampling; + m_iGPUIndex = _iGPUindex; + + // success + m_bIsInitialized = check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaForwardProjectionAlgorithm3D::check() +{ + // check pointers + //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pProjections, "FP3D_CUDA", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pVolume, "FP3D_CUDA", "Invalid Volume Data Object."); + + // check initializations + //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pProjections->isInitialized(), "FP3D_CUDA", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "FP3D_CUDA", "Volume Data Object Not Initialized."); + + ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "FP3D_CUDA", "DetectorSuperSampling must be a positive integer."); + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FP3D_CUDA", "GPUIndex must be a non-negative integer."); + + // check compatibility between projector and data classes +// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector."); +// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector."); + + // todo: turn some of these back on + +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized."); + + // check dimensions + //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + + // check restrictions + // TODO: check restrictions built into cuda code + + // success + m_bIsInitialized = true; + return true; +} + + +void CCudaForwardProjectionAlgorithm3D::setGPUIndex(int _iGPUIndex) +{ + m_iGPUIndex = _iGPUIndex; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaForwardProjectionAlgorithm3D::getInformation() +{ + map<string,boost::any> res; + res["ProjectionGeometry"] = getInformation("ProjectionGeometry"); + res["VolumeGeometry"] = getInformation("VolumeGeometry"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["VolumeDataId"] = getInformation("VolumeDataId"); + res["GPUindex"] = getInformation("GPUindex"); + res["GPUindex"] = getInformation("GPUindex"); + res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaForwardProjectionAlgorithm3D::getInformation(std::string _sIdentifier) +{ + // TODO: store these so we can return them? + if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); } + if (_sIdentifier == "VolumeGeometry") { return string("not implemented"); } + if (_sIdentifier == "GPUindex") { return m_iGPUIndex; } + if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; } + + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pProjections); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "VolumeDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pVolume); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +} + +//---------------------------------------------------------------------------------------- +// Run +void CCudaForwardProjectionAlgorithm3D::run(int) +{ + // check initialized + assert(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pProjections->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pVolume->getGeometry(); + + Cuda3DProjectionKernel projKernel = ker3d_default; + if (m_pProjector) { + CCudaProjector3D* projector = dynamic_cast<CCudaProjector3D*>(m_pProjector); + projKernel = projector->getProjectionKernel(); + } + + if (conegeom) { + astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles(), + m_iGPUIndex, m_iDetectorSuperSampling); + } else if (par3dgeom) { + astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + par3dgeom->getProjectionCount(), + par3dgeom->getDetectorColCount(), + par3dgeom->getDetectorRowCount(), + par3dgeom->getDetectorSpacingX(), + par3dgeom->getDetectorSpacingY(), + par3dgeom->getProjectionAngles(), + m_iGPUIndex, m_iDetectorSuperSampling, + projKernel); + } else if (parvec3dgeom) { + astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors(), + m_iGPUIndex, m_iDetectorSuperSampling, + projKernel); + } else if (conevecgeom) { + astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conevecgeom->getProjectionCount(), + conevecgeom->getDetectorColCount(), + conevecgeom->getDetectorRowCount(), + conevecgeom->getProjectionVectors(), + m_iGPUIndex, m_iDetectorSuperSampling); + } else { + ASTRA_ASSERT(false); + } + +} + + +} + +#endif diff --git a/src/CudaProjector2D.cpp b/src/CudaProjector2D.cpp new file mode 100644 index 0000000..731a3e1 --- /dev/null +++ b/src/CudaProjector2D.cpp @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------- +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") + +Copyright: IBBT-Vision Lab, University of Antwerp +Contact: mailto:wim.vanaarle@ua.ac.be +Website: http://astra.ua.ac.be +----------------------------------------------------------------------- +$Id$ +*/ +#include "astra/CudaProjector2D.h" + + +namespace astra +{ + +// type of the projector, needed to register with CProjectorFactory +std::string CCudaProjector2D::type = "cuda"; + + +//---------------------------------------------------------------------------------------- +// Default constructor +CCudaProjector2D::CCudaProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaProjector2D::~CCudaProjector2D() +{ + if (m_bIsInitialized) clear(); +} + +//---------------------------------------------------------------------------------------- +// Clear for constructors +void CCudaProjector2D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; + + m_projectionKernel = ker2d_default; +} + +//---------------------------------------------------------------------------------------- +// Clear +void CCudaProjector2D::clear() +{ + ASTRA_DELETE(m_pProjectionGeometry); + ASTRA_DELETE(m_pVolumeGeometry); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaProjector2D::_check() +{ + // projection geometry + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "CudaProjector2D", "ProjectionGeometry2D not initialized."); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "CudaProjector2D", "ProjectionGeometry2D not initialized."); + + // volume geometry + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "CudaProjector2D", "VolumeGeometry2D not initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "CudaProjector2D", "VolumeGeometry2D not initialized."); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CCudaProjector2D::initialize(const Config& _cfg) +{ + assert(_cfg.self); + ConfigStackCheck<CProjector2D> CC("CudaProjector2D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // TODO: Check the projection geometry is a supported type + + XMLNode* node = _cfg.self->getSingleNode("ProjectionKernel"); + m_projectionKernel = ker2d_default; + if (node) { + std::string sProjKernel = node->getContent(); + + if (sProjKernel == "default") { + + } else { + return false; + } + } + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionKernel"); + + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +/* +bool CProjector2D::initialize(astra::CProjectionGeometry2D *, astra::CVolumeGeometry2D *) +{ + ASTRA_ASSERT(false); + + return false; +} +*/ + +std::string CCudaProjector2D::description() const +{ + return ""; +} + +} // end namespace diff --git a/src/CudaProjector3D.cpp b/src/CudaProjector3D.cpp new file mode 100644 index 0000000..4687825 --- /dev/null +++ b/src/CudaProjector3D.cpp @@ -0,0 +1,153 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaProjector3D.h" + + +namespace astra +{ + +// type of the projector, needed to register with CProjectorFactory +std::string CCudaProjector3D::type = "cuda3d"; + + +//---------------------------------------------------------------------------------------- +// Default constructor +CCudaProjector3D::CCudaProjector3D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaProjector3D::~CCudaProjector3D() +{ + if (m_bIsInitialized) clear(); +} + +//---------------------------------------------------------------------------------------- +// Clear for constructors +void CCudaProjector3D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; + + m_projectionKernel = ker3d_default; +} + +//---------------------------------------------------------------------------------------- +// Clear +void CCudaProjector3D::clear() +{ + ASTRA_DELETE(m_pProjectionGeometry); + ASTRA_DELETE(m_pVolumeGeometry); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaProjector3D::_check() +{ + // projection geometry + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "CudaProjector3D", "ProjectionGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "CudaProjector3D", "ProjectionGeometry3D not initialized."); + + // volume geometry + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "CudaProjector3D", "VolumeGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "CudaProjector3D", "VolumeGeometry3D not initialized."); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CCudaProjector3D::initialize(const Config& _cfg) +{ + assert(_cfg.self); + ConfigStackCheck<CProjector3D> CC("CudaProjector3D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector3D::initialize(_cfg)) { + return false; + } + + // TODO: These should go to the parent. + + // ProjectionGeometry + XMLNode* node = _cfg.self->getSingleNode("ProjectionGeometry"); + // TODO: Implement + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionGeometry"); + + // ReconstructionGeometry + node = _cfg.self->getSingleNode("VolumeGeometry"); + // TODO: Implement + ASTRA_DELETE(node); + CC.markNodeParsed("VolumeGeometry"); + + node = _cfg.self->getSingleNode("ProjectionKernel"); + m_projectionKernel = ker3d_default; + if (node) { + std::string sProjKernel = node->getContent(); + + if (sProjKernel == "default") { + + } else if (sProjKernel == "sum_square_weights") { + m_projectionKernel = ker3d_sum_square_weights; + } else { + return false; + } + } + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionKernel"); + + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +/* +bool CProjector3D::initialize(astra::CProjectionGeometry3D *, astra::CVolumeGeometry3D *) +{ + ASTRA_ASSERT(false); + + return false; +} +*/ + +std::string CCudaProjector3D::description() const +{ + return ""; +} + +} // end namespace diff --git a/src/CudaReconstructionAlgorithm2D.cpp b/src/CudaReconstructionAlgorithm2D.cpp new file mode 100644 index 0000000..d567158 --- /dev/null +++ b/src/CudaReconstructionAlgorithm2D.cpp @@ -0,0 +1,518 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaReconstructionAlgorithm2D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/CudaProjector2D.h" + +#include "../cuda/2d/algo.h" + +#include <ctime> + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaReconstructionAlgorithm2D::CCudaReconstructionAlgorithm2D() +{ + _clear(); +} + + + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaReconstructionAlgorithm2D::~CCudaReconstructionAlgorithm2D() +{ + delete m_pAlgo; + m_pAlgo = 0; + m_bAlgoInit = false; +} + +void CCudaReconstructionAlgorithm2D::clear() +{ + delete m_pAlgo; + _clear(); +} + +void CCudaReconstructionAlgorithm2D::_clear() +{ + m_bIsInitialized = false; + m_pAlgo = 0; + m_bAlgoInit = false; + CReconstructionAlgorithm2D::_clear(); + + m_iGPUIndex = 0; + m_iDetectorSuperSampling = 1; + m_iPixelSuperSampling = 1; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaReconstructionAlgorithm2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaReconstructionAlgorithm2D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // sinogram data + XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ProjectionDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // fixed mask + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + // fixed mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("SinogramMaskId"); + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Detector supersampling factor + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + + // Pixel supersampling factor + m_iPixelSuperSampling = (int)_cfg.self->getOptionNumerical("PixelSuperSampling", 1); + CC.markOptionParsed("PixelSuperSampling"); + + + // This isn't used yet, but passing it is not something to warn about + node = _cfg.self->getSingleNode("ProjectorId"); + if (node) { + id = boost::lexical_cast<int>(node->getContent()); + CProjector2D *projector = CProjector2DManager::getSingleton().get(id); + if (!dynamic_cast<CCudaProjector2D*>(projector)) { + cout << "Warning: non-CUDA Projector2D passed to FP_CUDA" << std::endl; + } + delete node; + } + CC.markNodeParsed("ProjectorId"); + + + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + return initialize(_pProjector, _pSinogram, _pReconstruction, 0, 1); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, + int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + m_pProjector = 0; + + // required classes + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + m_iDetectorSuperSampling = _iDetectorSuperSampling; + m_iPixelSuperSampling = _iPixelSuperSampling; + m_iGPUIndex = _iGPUindex; + + return _check(); +} + + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaReconstructionAlgorithm2D::_check() +{ + // TODO: CLEAN UP + + + // check pointers + //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pSinogram, "SIRT_CUDA", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "SIRT_CUDA", "Invalid Reconstruction Data Object."); + + // check initializations + //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "SIRT_CUDA", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "SIRT_CUDA", "Reconstruction Data Object Not Initialized."); + + ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "SIRT_CUDA", "DetectorSuperSampling must be a positive integer."); + ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 1, "SIRT_CUDA", "PixelSuperSampling must be a positive integer."); + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "SIRT_CUDA", "GPUIndex must be a non-negative integer."); + + // check compatibility between projector and data classes +// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector."); +// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector."); + + // todo: turn some of these back on + +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized."); + + // check dimensions + //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + + // check restrictions + // TODO: check restrictions built into cuda code + + + // success + m_bIsInitialized = true; + return true; +} + +void CCudaReconstructionAlgorithm2D::setGPUIndex(int _iGPUIndex) +{ + m_iGPUIndex = _iGPUIndex; +} + + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaReconstructionAlgorithm2D::getInformation() +{ + // TODO: Verify and clean up + + map<string,boost::any> res; + res["ProjectionGeometry"] = getInformation("ProjectionGeometry"); + res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + res["GPUindex"] = getInformation("GPUindex"); + res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling"); + res["PixelSuperSampling"] = getInformation("PixelSuperSampling"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaReconstructionAlgorithm2D::getInformation(std::string _sIdentifier) +{ + // TODO: Verify and clean up + + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } + + // TODO: store these so we can return them? + if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); } + if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); } + if (_sIdentifier == "GPUindex") { return m_iGPUIndex; } + if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; } + if (_sIdentifier == "PixelSuperSampling") { return m_iPixelSuperSampling; } + + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CReconstructionAlgorithm2D::getInformation(_sIdentifier); +} + +bool CCudaReconstructionAlgorithm2D::setupGeometry() +{ + ASTRA_ASSERT(m_bIsInitialized); + ASTRA_ASSERT(!m_bAlgoInit); + + bool ok; + + // TODO: Probably not the best place for this... + ok = m_pAlgo->setGPUIndex(m_iGPUIndex); + if (!ok) return false; + + astraCUDA::SDimensions dims; + + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + + // TODO: off-center geometry, non-square pixels + dims.iVolWidth = volgeom.getGridColCount(); + dims.iVolHeight = volgeom.getGridRowCount(); + float fPixelSize = volgeom.getPixelLengthX(); + + dims.iRaysPerDet = m_iDetectorSuperSampling; + dims.iRaysPerPixelDim = m_iPixelSuperSampling; + + + const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry()); + + if (parProjGeom) { + + dims.iProjAngles = parProjGeom->getProjectionAngleCount(); + dims.iProjDets = parProjGeom->getDetectorCount(); + dims.fDetScale = parProjGeom->getDetectorWidth() / fPixelSize; + + ok = m_pAlgo->setGeometry(dims, parProjGeom->getProjectionAngles()); + + } else if (fanProjGeom) { + + dims.iProjAngles = fanProjGeom->getProjectionAngleCount(); + dims.iProjDets = fanProjGeom->getDetectorCount(); + dims.fDetScale = fanProjGeom->getDetectorWidth() / fPixelSize; + float fOriginSourceDistance = fanProjGeom->getOriginSourceDistance(); + float fOriginDetectorDistance = fanProjGeom->getOriginDetectorDistance(); + + const float* angles = fanProjGeom->getProjectionAngles(); + + astraCUDA::SFanProjection* projs; + projs = new astraCUDA::SFanProjection[dims.iProjAngles]; + + float fSrcX0 = 0.0f; + float fSrcY0 = -fOriginSourceDistance / fPixelSize; + float fDetUX0 = dims.fDetScale; + float fDetUY0 = 0.0f; + float fDetSX0 = dims.iProjDets * fDetUX0 / -2.0f; + float fDetSY0 = fOriginDetectorDistance / fPixelSize; + +#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = f##name##X0 * cos(alpha) - f##name##Y0 * sin(alpha); projs[i].f##name##Y = f##name##X0 * sin(alpha) + f##name##Y0 * cos(alpha); } while(0) + for (unsigned int i = 0; i < dims.iProjAngles; ++i) { + ROTATE0(Src, i, angles[i]); + ROTATE0(DetS, i, angles[i]); + ROTATE0(DetU, i, angles[i]); + } + +#undef ROTATE0 + + ok = m_pAlgo->setFanGeometry(dims, projs); + delete[] projs; + + } else if (fanVecProjGeom) { + + dims.iProjAngles = fanVecProjGeom->getProjectionAngleCount(); + dims.iProjDets = fanVecProjGeom->getDetectorCount(); + dims.fDetScale = fanVecProjGeom->getDetectorWidth() / fPixelSize; + + const astraCUDA::SFanProjection* projs; + projs = fanVecProjGeom->getProjectionVectors(); + + // Rescale projs to fPixelSize == 1 + + astraCUDA::SFanProjection* scaledProjs = new astraCUDA::SFanProjection[dims.iProjAngles]; +#define SCALE(name,i,alpha) do { scaledProjs[i].f##name##X = projs[i].f##name##X * alpha; scaledProjs[i].f##name##Y = projs[i].f##name##Y * alpha; } while (0) + for (unsigned int i = 0; i < dims.iProjAngles; ++i) { + SCALE(Src,i,1.0f/fPixelSize); + SCALE(DetS,i,1.0f/fPixelSize); + SCALE(DetU,i,1.0f/fPixelSize); + } + + ok = m_pAlgo->setFanGeometry(dims, scaledProjs); + + delete[] scaledProjs; + + } else { + + ASTRA_ASSERT(false); + + } + if (!ok) return false; + + + if (m_bUseReconstructionMask) + ok &= m_pAlgo->enableVolumeMask(); + if (!ok) return false; + if (m_bUseSinogramMask) + ok &= m_pAlgo->enableSinogramMask(); + if (!ok) return false; + + const float *pfTOffsets = m_pSinogram->getGeometry()->getExtraDetectorOffset(); + if (pfTOffsets) + ok &= m_pAlgo->setTOffsets(pfTOffsets); + if (!ok) return false; + + ok &= m_pAlgo->init(); + if (!ok) return false; + + + return true; +} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaReconstructionAlgorithm2D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + bool ok = true; + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + + if (!m_bAlgoInit) { + + ok = setupGeometry(); + ASTRA_ASSERT(ok); + + ok = m_pAlgo->allocateBuffers(); + ASTRA_ASSERT(ok); + + m_bAlgoInit = true; + } + + float fPixelSize = volgeom.getPixelLengthX(); + float fSinogramScale = 1.0f/(fPixelSize*fPixelSize); + + ok = m_pAlgo->copyDataToGPU(m_pSinogram->getDataConst(), m_pSinogram->getGeometry()->getDetectorCount(), fSinogramScale, + m_pReconstruction->getDataConst(), volgeom.getGridColCount(), + m_bUseReconstructionMask ? m_pReconstructionMask->getDataConst() : 0, volgeom.getGridColCount(), + m_bUseSinogramMask ? m_pSinogramMask->getDataConst() : 0, m_pSinogram->getGeometry()->getDetectorCount()); + + ASTRA_ASSERT(ok); + + if (m_bUseMinConstraint) + ok &= m_pAlgo->setMinConstraint(m_fMinValue); + if (m_bUseMaxConstraint) + ok &= m_pAlgo->setMaxConstraint(m_fMaxValue); + + ok &= m_pAlgo->iterate(_iNrIterations); + ASTRA_ASSERT(ok); + + ok &= m_pAlgo->getReconstruction(m_pReconstruction->getData(), + volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); +} + +void CCudaReconstructionAlgorithm2D::signalAbort() +{ + if (m_bIsInitialized && m_pAlgo) { + m_pAlgo->signalAbort(); + } +} + +bool CCudaReconstructionAlgorithm2D::getResidualNorm(float32& _fNorm) +{ + if (!m_bIsInitialized || !m_pAlgo) + return false; + + _fNorm = m_pAlgo->computeDiffNorm(); + + return true; +} + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaRoiSelectAlgorithm.cpp b/src/CudaRoiSelectAlgorithm.cpp new file mode 100644 index 0000000..f835c59 --- /dev/null +++ b/src/CudaRoiSelectAlgorithm.cpp @@ -0,0 +1,149 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaRoiSelectAlgorithm.h" + +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/algo.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaRoiSelectAlgorithm::type = "RoiSelect_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaRoiSelectAlgorithm::CCudaRoiSelectAlgorithm() +{ + m_fRadius = 0.0f; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaRoiSelectAlgorithm::~CCudaRoiSelectAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaRoiSelectAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("DataId"); + ASTRA_CONFIG_CHECK(node, "CudaRoiSelect", "No DataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pData = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("DataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Radius + m_fRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 0.0f); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaRoiSelectAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry2D& volgeom = *m_pData->getGeometry(); + unsigned int width = volgeom.getGridColCount(); + unsigned int height = volgeom.getGridRowCount(); + + if (m_fRadius == 0){ + m_fRadius = (width < height) ? width : height; + } + + astraCUDA::setGPUIndex(m_iGPUIndex); + astraCUDA::roiSelect(m_pData->getData(), m_fRadius, width, height); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaRoiSelectAlgorithm::_check() +{ + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaRoiSelectAlgorithm::getInformation() +{ + map<string,boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaRoiSelectAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaSartAlgorithm.cpp b/src/CudaSartAlgorithm.cpp new file mode 100644 index 0000000..610793f --- /dev/null +++ b/src/CudaSartAlgorithm.cpp @@ -0,0 +1,136 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaSartAlgorithm.h" + +#include "../cuda/2d/sart.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaSartAlgorithm::type = "SART_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaSartAlgorithm::CCudaSartAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaSartAlgorithm::~CCudaSartAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaSartAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaSartAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + astraCUDA::SART *sart = new astraCUDA::SART(); + + m_pAlgo = sart; + m_bAlgoInit = false; + + // projection order + int projectionCount = m_pSinogram->getGeometry()->getProjectionAngleCount(); + int* projectionOrder = NULL; + string projOrder = _cfg.self->getOption("ProjectionOrder", "random"); + CC.markOptionParsed("ProjectionOrder"); + if (projOrder == "sequential") { + projectionOrder = new int[projectionCount]; + for (int i = 0; i < projectionCount; i++) { + projectionOrder[i] = i; + } + sart->setProjectionOrder(projectionOrder, projectionCount); + delete[] projectionOrder; + } else if (projOrder == "random") { + projectionOrder = new int[projectionCount]; + for (int i = 0; i < projectionCount; i++) { + projectionOrder[i] = i; + } + for (int i = 0; i < projectionCount-1; i++) { + int k = (rand() % (projectionCount - i)); + int t = projectionOrder[i]; + projectionOrder[i] = projectionOrder[i + k]; + projectionOrder[i + k] = t; + } + sart->setProjectionOrder(projectionOrder, projectionCount); + delete[] projectionOrder; + } else if (projOrder == "custom") { + vector<float32> projOrderList = _cfg.self->getOptionNumericalArray("ProjectionOrderList"); + projectionOrder = new int[projOrderList.size()]; + for (int i = 0; i < projOrderList.size(); i++) { + projectionOrder[i] = static_cast<int>(projOrderList[i]); + } + sart->setProjectionOrder(projectionOrder, projectionCount); + delete[] projectionOrder; + CC.markOptionParsed("ProjectionOrderList"); + } + + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaSartAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, 1); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::SART(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaSirtAlgorithm.cpp b/src/CudaSirtAlgorithm.cpp new file mode 100644 index 0000000..a2a30eb --- /dev/null +++ b/src/CudaSirtAlgorithm.cpp @@ -0,0 +1,154 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaSirtAlgorithm.h" + +#include <boost/lexical_cast.hpp> +#include "astra/AstraObjectManager.h" + +#include "../cuda/2d/sirt.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaSirtAlgorithm::type = "SIRT_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaSirtAlgorithm::CCudaSirtAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); + + m_pMinMask = 0; + m_pMaxMask = 0; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaSirtAlgorithm::~CCudaSirtAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D + + m_pMinMask = 0; + m_pMaxMask = 0; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaSirtAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaSirtAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + // min/max masks + if (_cfg.self->hasOption("MinMaskId")) { + int id = boost::lexical_cast<int>(_cfg.self->getOption("MinMaskId")); + m_pMinMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("MinMaskId"); + if (_cfg.self->hasOption("MaxMaskId")) { + int id = boost::lexical_cast<int>(_cfg.self->getOption("MaxMaskId")); + m_pMaxMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("MaxMaskId"); + + + m_pAlgo = new astraCUDA::SIRT(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaSirtAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + + + m_pAlgo = new astraCUDA::SIRT(); + m_bAlgoInit = false; + + return true; +} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaSirtAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + if (!m_bAlgoInit) { + // We only override the initialisation step to copy the min/max masks + + bool ok = setupGeometry(); + ASTRA_ASSERT(ok); + + ok = m_pAlgo->allocateBuffers(); + ASTRA_ASSERT(ok); + + if (m_pMinMask || m_pMaxMask) { + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + astraCUDA::SIRT* pSirt = dynamic_cast<astraCUDA::SIRT*>(m_pAlgo); + const float *pfMinMaskData = 0; + const float *pfMaxMaskData = 0; + if (m_pMinMask) pfMinMaskData = m_pMinMask->getDataConst(); + if (m_pMaxMask) pfMaxMaskData = m_pMaxMask->getDataConst(); + ok = pSirt->uploadMinMaxMasks(pfMinMaskData, pfMaxMaskData, volgeom.getGridColCount()); + ASTRA_ASSERT(ok); + } + + m_bAlgoInit = true; + } + + CCudaReconstructionAlgorithm2D::run(_iNrIterations); +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaSirtAlgorithm3D.cpp b/src/CudaSirtAlgorithm3D.cpp new file mode 100644 index 0000000..f23d0f6 --- /dev/null +++ b/src/CudaSirtAlgorithm3D.cpp @@ -0,0 +1,306 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaSirtAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaSirtAlgorithm3D::type = "SIRT3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D() +{ + m_bIsInitialized = false; + m_pSirt = 0; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; + m_iDetectorSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaSirtAlgorithm3D::~CCudaSirtAlgorithm3D() +{ + delete m_pSirt; + m_pSirt = 0; + + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaSirtAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "SIRT3D", "Error in ReconstructionAlgorithm3D initialization"); + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaSirtAlgorithm3D", this, _cfg); + + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + m_pSirt = new AstraSIRT3d(); + + m_bAstraSIRTInit = false; + + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaSirtAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + m_pSirt = new AstraSIRT3d; + + m_bAstraSIRTInit = false; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaSirtAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaSirtAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaSirtAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry(); + + bool ok = true; + + if (!m_bAstraSIRTInit) { + + ok &= m_pSirt->setGPUIndex(m_iGPUIndex); + + ok &= m_pSirt->setReconstructionGeometry(volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount()); + fprintf(stderr, "01: %d\n", ok); + + if (conegeom) { + ok &= m_pSirt->setConeGeometry(conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles()); + } else if (par3dgeom) { + ok &= m_pSirt->setPar3DGeometry(par3dgeom->getProjectionCount(), + par3dgeom->getDetectorColCount(), + par3dgeom->getDetectorRowCount(), + par3dgeom->getDetectorSpacingX(), + par3dgeom->getDetectorSpacingY(), + par3dgeom->getProjectionAngles()); + } else if (parvec3dgeom) { + ok &= m_pSirt->setPar3DGeometry(parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors()); + } else if (conevec3dgeom) { + ok &= m_pSirt->setConeGeometry(conevec3dgeom->getProjectionCount(), + conevec3dgeom->getDetectorColCount(), + conevec3dgeom->getDetectorRowCount(), + conevec3dgeom->getProjectionVectors()); + } else { + ASTRA_ASSERT(false); + } + fprintf(stderr, "02: %d\n", ok); + + ok &= m_pSirt->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling); + + if (m_bUseReconstructionMask) + ok &= m_pSirt->enableVolumeMask(); + if (m_bUseSinogramMask) + ok &= m_pSirt->enableSinogramMask(); + + ASTRA_ASSERT(ok); + fprintf(stderr, "03: %d\n", ok); + + ok &= m_pSirt->init(); + fprintf(stderr, "04: %d\n", ok); + + ASTRA_ASSERT(ok); + + m_bAstraSIRTInit = true; + + } + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + + ok = m_pSirt->setSinogram(pSinoMem->getDataConst(), m_pSinogram->getGeometry()->getDetectorColCount()); + + fprintf(stderr, "1: %d\n", ok); + ASTRA_ASSERT(ok); + + if (m_bUseReconstructionMask) { + CFloat32VolumeData3DMemory* pRMaskMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstructionMask); + ASTRA_ASSERT(pRMaskMem); + ok &= m_pSirt->setVolumeMask(pRMaskMem->getDataConst(), volgeom.getGridColCount()); + } + if (m_bUseSinogramMask) { + CFloat32ProjectionData3DMemory* pSMaskMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogramMask); + ASTRA_ASSERT(pSMaskMem); + ok &= m_pSirt->setSinogramMask(pSMaskMem->getDataConst(), m_pSinogramMask->getGeometry()->getDetectorColCount()); + } + fprintf(stderr, "2: %d\n", ok); + + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + ok &= m_pSirt->setStartReconstruction(pReconMem->getDataConst(), + volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); + fprintf(stderr, "3: %d\n", ok); + + if (m_bUseMinConstraint) + ok &= m_pSirt->setMinConstraint(m_fMinValue); + if (m_bUseMaxConstraint) + ok &= m_pSirt->setMaxConstraint(m_fMaxValue); + fprintf(stderr, "4: %d\n", ok); + + ok &= m_pSirt->iterate(_iNrIterations); + ASTRA_ASSERT(ok); + fprintf(stderr, "5: %d\n", ok); + + ok &= m_pSirt->getReconstruction(pReconMem->getData(), + volgeom.getGridColCount()); + fprintf(stderr, "6: %d\n", ok); + ASTRA_ASSERT(ok); + + +} +//---------------------------------------------------------------------------------------- +void CCudaSirtAlgorithm3D::signalAbort() +{ + if (m_bIsInitialized && m_pSirt) { + m_pSirt->signalAbort(); + } +} + +bool CCudaSirtAlgorithm3D::getResidualNorm(float32& _fNorm) +{ + if (!m_bIsInitialized || !m_pSirt) + return false; + + _fNorm = m_pSirt->computeDiffNorm(); + + return true; +} + + +} // namespace astra diff --git a/src/DataProjector.cpp b/src/DataProjector.cpp new file mode 100644 index 0000000..d4b2f84 --- /dev/null +++ b/src/DataProjector.cpp @@ -0,0 +1,36 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/DataProjector.h" + +namespace astra { + + // EMPTY + + +} // end namespace astra diff --git a/src/DataProjectorPolicies.cpp b/src/DataProjectorPolicies.cpp new file mode 100644 index 0000000..2535706 --- /dev/null +++ b/src/DataProjectorPolicies.cpp @@ -0,0 +1,36 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/DataProjectorPolicies.h" + +namespace astra { + + // EMPTY + + +} // end namespace astra diff --git a/src/FanFlatBeamLineKernelProjector2D.cpp b/src/FanFlatBeamLineKernelProjector2D.cpp new file mode 100644 index 0000000..0891801 --- /dev/null +++ b/src/FanFlatBeamLineKernelProjector2D.cpp @@ -0,0 +1,179 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatBeamLineKernelProjector2D.h" + +#include <cmath> +#include <cstring> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/FanFlatBeamLineKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CFanFlatBeamLineKernelProjector2D::type = "line_fanflat"; + + +//---------------------------------------------------------------------------------------- +// default constructor +CFanFlatBeamLineKernelProjector2D::CFanFlatBeamLineKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CFanFlatBeamLineKernelProjector2D::CFanFlatBeamLineKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CFanFlatBeamLineKernelProjector2D::~CFanFlatBeamLineKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CFanFlatBeamLineKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CFanFlatBeamLineKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CFanFlatBeamLineKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "FanFlatBeamLineKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry) || dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry), "FanFlatBeamLineKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "FanFlatBeamLineKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CFanFlatBeamLineKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CFanFlatBeamLineKernelProjector2D::initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CFanFlatBeamLineKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 2 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CFanFlatBeamLineKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CFanFlatBeamLineKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + std::vector<SDetector2D> res; + return res; +} + +//---------------------------------------------------------------------------------------- +//Result is always in [-PI/2; PI/2] +float32 CFanFlatBeamLineKernelProjector2D::angleBetweenVectors(float32 _fAX, float32 _fAY, float32 _fBX, float32 _fBY) +{ + float32 sinAB = (_fAX*_fBY - _fAY*_fBX)/sqrt((_fAX*_fAX + _fAY*_fAY)*(_fBX*_fBX + _fBY*_fBY)); + return asin(sinAB); +} + +//---------------------------------------------------------------------------------------- diff --git a/src/FanFlatBeamStripKernelProjector2D.cpp b/src/FanFlatBeamStripKernelProjector2D.cpp new file mode 100644 index 0000000..87ae8d6 --- /dev/null +++ b/src/FanFlatBeamStripKernelProjector2D.cpp @@ -0,0 +1,223 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatBeamStripKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/FanFlatBeamStripKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CFanFlatBeamStripKernelProjector2D::type = "strip_fanflat"; + +//---------------------------------------------------------------------------------------- +// default constructor +CFanFlatBeamStripKernelProjector2D::CFanFlatBeamStripKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CFanFlatBeamStripKernelProjector2D::CFanFlatBeamStripKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CFanFlatBeamStripKernelProjector2D::~CFanFlatBeamStripKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CFanFlatBeamStripKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CFanFlatBeamStripKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CFanFlatBeamStripKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "FanFlatBeamStripKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry), "FanFlatBeamLineKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "FanFlatBeamStripKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CFanFlatBeamStripKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CFanFlatBeamStripKernelProjector2D::initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CFanFlatBeamStripKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 10 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CFanFlatBeamStripKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CFanFlatBeamStripKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + //float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + //float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + //float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + //float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + + std::vector<SDetector2D> res; + //// loop projectors and detectors + //for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // // get projection angle + // float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + // if (theta >= 7*PIdiv4) theta -= 2*PI; + // bool inverse = false; + // if (theta >= 3*PIdiv4) { + // theta -= PI; + // inverse = true; + // } + + // // calculate distance from the center of the voxel to the ray though the origin + // float32 tUL = xUL * cos(theta) + yUL * sin(theta); + // float32 tUR = xUR * cos(theta) + yUR * sin(theta); + // float32 tLL = xLL * cos(theta) + yLL * sin(theta); + // float32 tLR = xLR * cos(theta) + yLR * sin(theta); + // if (inverse) { + // tUL *= -1.0f; + // tUR *= -1.0f; + // tLL *= -1.0f; + // tLR *= -1.0f; + // } + // float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + // float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // // calculate the offset on the detectorarray (in indices) + // int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + // int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // // add affected detectors to the list + // for (int i = dmin; i <= dmax; ++i) { + // if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + // SDetector2D det; + // det.m_iAngleIndex = iProjection; + // det.m_iDetectorIndex = i; + // det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + // res.push_back(det); + // } + // } + //} + + //// return result vector + return res; + +} + +//---------------------------------------------------------------------------------------- diff --git a/src/FanFlatProjectionGeometry2D.cpp b/src/FanFlatProjectionGeometry2D.cpp new file mode 100644 index 0000000..b74536a --- /dev/null +++ b/src/FanFlatProjectionGeometry2D.cpp @@ -0,0 +1,209 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatProjectionGeometry2D.h" + +#include <cstring> +#include <sstream> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. Sets all variables to zero. +CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D() +{ + _clear(); + m_fOriginSourceDistance = 0.0f; + m_fOriginDetectorDistance = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) +{ + this->initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles, + _fOriginSourceDistance, + _fOriginDetectorDistance); +} + +//---------------------------------------------------------------------------------------- +// Copy Constructor +CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D(const CFanFlatProjectionGeometry2D& _projGeom) +{ + _clear(); + this->initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_fDetectorWidth, + _projGeom.m_pfProjectionAngles, + _projGeom.m_fOriginSourceDistance, + _projGeom.m_fOriginDetectorDistance); +} + +//---------------------------------------------------------------------------------------- +// Assignment operator. +CFanFlatProjectionGeometry2D& CFanFlatProjectionGeometry2D::operator=(const CFanFlatProjectionGeometry2D& _other) +{ + if (m_bInitialized) + delete[] m_pfProjectionAngles; + m_bInitialized = _other.m_bInitialized; + if (m_bInitialized) { + m_iProjectionAngleCount = _other.m_iProjectionAngleCount; + m_iDetectorCount = _other.m_iDetectorCount; + m_fDetectorWidth = _other.m_fDetectorWidth; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(m_pfProjectionAngles, _other.m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + m_fOriginSourceDistance = _other.m_fOriginSourceDistance; + m_fOriginDetectorDistance = _other.m_fOriginDetectorDistance; + } + return *this; +} +//---------------------------------------------------------------------------------------- +// Destructor. +CFanFlatProjectionGeometry2D::~CFanFlatProjectionGeometry2D() +{ + +} + + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CFanFlatProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) +{ + m_fOriginSourceDistance = _fOriginSourceDistance; + m_fOriginDetectorDistance = _fOriginDetectorDistance; + _initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CFanFlatProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("FanFlatProjectionGeometry2D", this, _cfg); + + // initialization of parent class + CProjectionGeometry2D::initialize(_cfg); + + // Required: DistanceOriginDetector + XMLNode* node = _cfg.self->getSingleNode("DistanceOriginDetector"); + ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginDetector tag specified."); + m_fOriginDetectorDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginDetector"); + + // Required: DetectorOriginSource + node = _cfg.self->getSingleNode("DistanceOriginSource"); + ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginSource tag specified."); + m_fOriginSourceDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginSource"); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CFanFlatProjectionGeometry2D::clone() +{ + return new CFanFlatProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CFanFlatProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CFanFlatProjectionGeometry2D + CFanFlatProjectionGeometry2D* pGeom2 = dynamic_cast<CFanFlatProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false; + if (m_fOriginSourceDistance != pGeom2->m_fOriginSourceDistance) return false; + if (m_fOriginDetectorDistance != pGeom2->m_fOriginDetectorDistance) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// Is of type +bool CFanFlatProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "fanflat"); +} + +CVector3D CFanFlatProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */) +{ + CVector3D vOutput(0.0f, 0.0f, 0.0f); + + // not implemented + ASTRA_ASSERT(false); + + return vOutput; +} + +//---------------------------------------------------------------------------------------- + + +} // namespace astra diff --git a/src/FanFlatVecProjectionGeometry2D.cpp b/src/FanFlatVecProjectionGeometry2D.cpp new file mode 100644 index 0000000..e42a4f1 --- /dev/null +++ b/src/FanFlatVecProjectionGeometry2D.cpp @@ -0,0 +1,232 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatVecProjectionGeometry2D.h" + +#include <cstring> +#include <sstream> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. Sets all variables to zero. +CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D() +{ + _clear(); + m_pProjectionAngles = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + const SFanProjection* _pProjectionAngles) +{ + this->initialize(_iProjectionAngleCount, + _iDetectorCount, + _pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Copy Constructor +CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D(const CFanFlatVecProjectionGeometry2D& _projGeom) +{ + _clear(); + this->initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Assignment operator. +CFanFlatVecProjectionGeometry2D& CFanFlatVecProjectionGeometry2D::operator=(const CFanFlatVecProjectionGeometry2D& _other) +{ + if (m_bInitialized) + delete[] m_pProjectionAngles; + m_bInitialized = _other.m_bInitialized; + if (m_bInitialized) { + m_iProjectionAngleCount = _other.m_iProjectionAngleCount; + m_iDetectorCount = _other.m_iDetectorCount; + m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount]; + memcpy(m_pProjectionAngles, _other.m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount); + } + return *this; +} +//---------------------------------------------------------------------------------------- +// Destructor. +CFanFlatVecProjectionGeometry2D::~CFanFlatVecProjectionGeometry2D() +{ + // TODO + delete[] m_pProjectionAngles; +} + + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CFanFlatVecProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + const SFanProjection* _pProjectionAngles) +{ + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorCount = _iDetectorCount; + m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pProjectionAngles[i] = _pProjectionAngles[i]; + + // TODO: check? + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CFanFlatVecProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("FanFlatVecProjectionGeometry2D", this, _cfg); + + XMLNode* node; + + // TODO: Fix up class hierarchy... this class doesn't fit very well. + // initialization of parent class + //CProjectionGeometry2D::initialize(_cfg); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorCount"); + ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorCount"); + + // Required: Vectors + node = _cfg.self->getSingleNode("Vectors"); + ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No Vectors tag specified."); + vector<float32> data = node->getContentNumericalArray(); + CC.markNodeParsed("Vectors"); + ASTRA_DELETE(node); + ASTRA_CONFIG_CHECK(data.size() % 6 == 0, "FanFlatVecProjectionGeometry3D", "Vectors doesn't consist of 6-tuples."); + m_iProjectionAngleCount = data.size() / 6; + m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount]; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + SFanProjection& p = m_pProjectionAngles[i]; + p.fSrcX = data[6*i + 0]; + p.fSrcY = data[6*i + 1]; + p.fDetUX = data[6*i + 4]; + p.fDetUY = data[6*i + 5]; + + // The backend code currently expects the corner of the detector, while + // the matlab interface supplies the center + p.fDetSX = data[6*i + 2] - 0.5f * m_iDetectorCount * p.fDetUX; + p.fDetSY = data[6*i + 3] - 0.5f * m_iDetectorCount * p.fDetUY; + } + + + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CFanFlatVecProjectionGeometry2D::clone() +{ + return new CFanFlatVecProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CFanFlatVecProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CFanFlatVecProjectionGeometry2D + CFanFlatVecProjectionGeometry2D* pGeom2 = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// Is of type +bool CFanFlatVecProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "fanflat_vec"); +} + +//---------------------------------------------------------------------------------------- + +CVector3D CFanFlatVecProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */) +{ + CVector3D vOutput(0.0f, 0.0f, 0.0f); + + // not implemented + ASTRA_ASSERT(false); + + return vOutput; +} + +//---------------------------------------------------------------------------------------- + +void CFanFlatVecProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const +{ + // not implemented + ASTRA_ASSERT(false); +} + +//---------------------------------------------------------------------------------------- + +bool CFanFlatVecProjectionGeometry2D::_check() +{ + // TODO + return true; +} + + +//---------------------------------------------------------------------------------------- + + +} // namespace astra diff --git a/src/FilteredBackProjectionAlgorithm.cpp b/src/FilteredBackProjectionAlgorithm.cpp new file mode 100644 index 0000000..8063f7b --- /dev/null +++ b/src/FilteredBackProjectionAlgorithm.cpp @@ -0,0 +1,336 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FilteredBackProjectionAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include <iostream> +#include <iomanip> +#include <math.h> + +#include "astra/AstraObjectManager.h" +#include "astra/ParallelBeamLineKernelProjector2D.h" +#include "astra/Fourier.h" +#include "astra/DataProjector.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CFilteredBackProjectionAlgorithm::type = "FBP"; +const int FFT = 1; +const int IFFT = -1; + +//---------------------------------------------------------------------------------------- +// Constructor +CFilteredBackProjectionAlgorithm::CFilteredBackProjectionAlgorithm() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFilteredBackProjectionAlgorithm::~CFilteredBackProjectionAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CFilteredBackProjectionAlgorithm::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CFilteredBackProjectionAlgorithm::clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bIsInitialized = false; +} + + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // volume data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + node = _cfg.self->getSingleNode("ProjectionIndex"); + if (node) + { + vector<float32> projectionIndex = node->getContentNumericalArray(); + + int angleCount = projectionIndex.size(); + int detectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount(); + + float32 * sinogramData2D = new float32[angleCount* detectorCount]; + float32 ** sinogramData = new float32*[angleCount]; + for (int i = 0; i < angleCount; i++) + { + sinogramData[i] = &(sinogramData2D[i * detectorCount]); + } + + float32 * projectionAngles = new float32[angleCount]; + float32 detectorWidth = m_pProjector->getProjectionGeometry()->getDetectorWidth(); + + for (int i = 0; i < angleCount; i ++) { + if (projectionIndex[i] > m_pProjector->getProjectionGeometry()->getProjectionAngleCount() -1 ) + { + cout << "Invalid Projection Index" << endl; + return false; + } else { + int orgIndex = (int)projectionIndex[i]; + + for (int iDetector=0; iDetector < detectorCount; iDetector++) + { + sinogramData2D[i*detectorCount+ iDetector] = m_pSinogram->getData2D()[orgIndex][iDetector]; + } +// sinogramData[i] = m_pSinogram->getSingleProjectionData(projectionIndex[i]); + projectionAngles[i] = m_pProjector->getProjectionGeometry()->getProjectionAngle((int)projectionIndex[i] ); + + } + } + + CParallelProjectionGeometry2D * pg = new CParallelProjectionGeometry2D(angleCount, detectorCount,detectorWidth,projectionAngles); + m_pProjector = new CParallelBeamLineKernelProjector2D(pg,m_pReconstruction->getGeometry()); + m_pSinogram = new CFloat32ProjectionData2D(pg, sinogramData2D); + } + ASTRA_DELETE(node); + + // TODO: check that the angles are linearly spaced between 0 and pi + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Get Information - all +map<string,boost::any> CFilteredBackProjectionAlgorithm::getInformation() +{ + map<string, boost::any> result; + result["ProjectorId"] = getInformation("ProjectorId"); + result["ProjectionDataId"] = getInformation("ProjectionDataId"); + result["VolumeDataId"] = getInformation("VolumeDataId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), result); +}; + +//--------------------------------------------------------------------------------------- +// Get Information - specific +boost::any CFilteredBackProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "VolumeDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Initialize +bool CFilteredBackProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram) +{ + // store classes + m_pProjector = _pProjector; + m_pReconstruction = _pVolume; + m_pSinogram = _pSinogram; + + + // TODO: check that the angles are linearly spaced between 0 and pi + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CFilteredBackProjectionAlgorithm::_check() +{ + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "FBP", "Error in ReconstructionAlgorithm2D initialization"); + + // success + return true; +} + + +//---------------------------------------------------------------------------------------- +// Iterate +void CFilteredBackProjectionAlgorithm::run(int _iNrIterations) +{ + ASTRA_ASSERT(m_bIsInitialized); + + // Filter sinogram + CFloat32ProjectionData2D filteredSinogram(m_pSinogram->getGeometry(), m_pSinogram->getData()); + performFiltering(&filteredSinogram); + + // Back project + m_pReconstruction->setData(0.0f); + projectData(m_pProjector, + DefaultBPPolicy(m_pReconstruction, &filteredSinogram)); + + // Scale data + int iAngleCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); + (*m_pReconstruction) *= (PI/2)/iAngleCount; + + m_pReconstruction->updateStatistics(); +} + + +//---------------------------------------------------------------------------------------- +void CFilteredBackProjectionAlgorithm::performFiltering(CFloat32ProjectionData2D * _pFilteredSinogram) +{ + ASTRA_ASSERT(_pFilteredSinogram != NULL); + ASTRA_ASSERT(_pFilteredSinogram->getAngleCount() == m_pSinogram->getAngleCount()); + ASTRA_ASSERT(_pFilteredSinogram->getDetectorCount() == m_pSinogram->getDetectorCount()); + + + int iAngleCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); + int iDetectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount(); + + + // We'll zero-pad to the smallest power of two at least 64 and + // at least 2*iDetectorCount + int zpDetector = 64; + int nextPow2 = 5; + while (zpDetector < iDetectorCount*2) { + zpDetector *= 2; + nextPow2++; + } + + // Create filter + float32* filter = new float32[zpDetector]; + + for (int iDetector = 0; iDetector <= zpDetector/2; iDetector++) + filter[iDetector] = (2.0f * iDetector)/zpDetector; + + for (int iDetector = zpDetector/2+1; iDetector < zpDetector; iDetector++) + filter[iDetector] = (2.0f * (zpDetector - iDetector)) / zpDetector; + + + float32* pfRe = new float32[iAngleCount * zpDetector]; + float32* pfIm = new float32[iAngleCount * zpDetector]; + + // Copy and zero-pad data + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount; + for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector) { + pfReRow[iDetector] = pfDataRow[iDetector]; + pfImRow[iDetector] = 0.0f; + } + for (int iDetector = iDetectorCount; iDetector < zpDetector; ++iDetector) { + pfReRow[iDetector] = 0.0f; + pfImRow[iDetector] = 0.0f; + } + } + + // in-place FFT + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + + fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, false); + } + + // Filter + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + for (int iDetector = 0; iDetector < zpDetector; ++iDetector) { + pfReRow[iDetector] *= filter[iDetector]; + pfImRow[iDetector] *= filter[iDetector]; + } + } + + // in-place inverse FFT + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + + fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, true); + } + + // Copy data back + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount; + for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector) + pfDataRow[iDetector] = pfReRow[iDetector]; + } + + delete[] pfRe; + delete[] pfIm; + delete[] filter; +} + +} diff --git a/src/Float32Data.cpp b/src/Float32Data.cpp new file mode 100644 index 0000000..47bbcc9 --- /dev/null +++ b/src/Float32Data.cpp @@ -0,0 +1,50 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data::CFloat32Data() +{ + +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CFloat32Data::~CFloat32Data() +{ + +} + + +} // end namespace diff --git a/src/Float32Data2D.cpp b/src/Float32Data2D.cpp new file mode 100644 index 0000000..e51935f --- /dev/null +++ b/src/Float32Data2D.cpp @@ -0,0 +1,523 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data2D.h" +#include <iostream> +#include <cstring> + +#ifdef _MSC_VER +#include <malloc.h> +#else +#include <cstdlib> +#endif + +namespace astra { + + + //---------------------------------------------------------------------------------------- + // Constructors +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data2D::CFloat32Data2D() +{ + _clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32Data2D class, allocating (but not initializing) the data block. +CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight) +{ + m_bInitialized = false; + _initialize(_iWidth, _iHeight); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32Data2D class with initialization of the data block. +CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, const float32* _pfData) +{ + m_bInitialized = false; + _initialize(_iWidth, _iHeight, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32Data2D class with initialization of the data block. +CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, float32 _fScalar) +{ + m_bInitialized = false; + _initialize(_iWidth, _iHeight, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Copy constructor +CFloat32Data2D::CFloat32Data2D(const CFloat32Data2D& _other) +{ + m_bInitialized = false; + *this = _other; +} + +//---------------------------------------------------------------------------------------- +// Assignment operator +CFloat32Data2D& CFloat32Data2D::operator=(const CFloat32Data2D& _dataIn) +{ + ASTRA_ASSERT(_dataIn.m_bInitialized); + + if (m_bInitialized) { + if (m_iWidth == _dataIn.m_iWidth && m_iHeight == _dataIn.m_iHeight) { + // Same dimensions, so no need to re-allocate memory + + m_fGlobalMin = _dataIn.m_fGlobalMin; + m_fGlobalMax = _dataIn.m_fGlobalMax; + m_fGlobalMean = _dataIn.m_fGlobalMean; + + ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight); + ASTRA_ASSERT(m_pfData); + + memcpy(m_pfData, _dataIn.m_pfData, m_iSize * sizeof(float32)); + } else { + // Re-allocate data + _unInit(); + _initialize(_dataIn.getWidth(), _dataIn.getHeight(), _dataIn.getDataConst()); + } + } else { + _initialize(_dataIn.getWidth(), _dataIn.getHeight(), _dataIn.getDataConst()); + } + + return (*this); +} + +//---------------------------------------------------------------------------------------- +// Destructor. Free allocated memory +CFloat32Data2D::~CFloat32Data2D() +{ + if (m_bInitialized) + { + _unInit(); + } +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class, allocating (but not initializing) the data block. +bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + + if (m_bInitialized) + { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iSize = (size_t)m_iWidth * m_iHeight; + + // allocate memory for the data, but do not fill it + m_pfData = 0; + m_ppfData2D = 0; + _allocateData(); + + // set minmax to default values + m_fGlobalMin = 0.0; + m_fGlobalMax = 0.0; + m_fGlobalMean = 0.0; + + // initialization complete + return true; + +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with initialization of the data block. +bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, const float32 *_pfData) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_pfData != NULL); + + if (m_bInitialized) + { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iSize = (size_t)m_iWidth * m_iHeight; + + // allocate memory for the data + m_pfData = 0; + m_ppfData2D = 0; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = _pfData[i]; + } + + // initialization complete + return true; +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with a scalar initialization of the data block. +bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + + if (m_bInitialized) { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iSize = (size_t)m_iWidth * m_iHeight; + + // allocate memory for the data + m_pfData = 0; + m_ppfData2D = 0; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } + + // initialization complete + return true; +} + + + //---------------------------------------------------------------------------------------- + // Memory Allocation +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Allocate memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data2D::_allocateData() +{ + // basic checks + ASTRA_ASSERT(!m_bInitialized); + + ASTRA_ASSERT(m_iSize > 0); + ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight); + ASTRA_ASSERT(m_pfData == NULL); + ASTRA_ASSERT(m_ppfData2D == NULL); + + // allocate contiguous block +#ifdef _MSC_VER + m_pfData = (float32*)_aligned_malloc(m_iSize * sizeof(float32), 16); +#else + int ret = posix_memalign((void**)&m_pfData, 16, m_iSize * sizeof(float32)); + ASTRA_ASSERT(ret == 0); +#endif + + // create array of pointers to each row of the data block + m_ppfData2D = new float32*[m_iHeight]; + for (int iy = 0; iy < m_iHeight; iy++) + { + m_ppfData2D[iy] = &(m_pfData[iy * m_iWidth]); + } +} + +//---------------------------------------------------------------------------------------- +// Free memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data2D::_freeData() +{ + // basic checks + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_ppfData2D != NULL); + + // free memory for index table + delete[] m_ppfData2D; + // free memory for data block +#ifdef _MSC_VER + _aligned_free(m_pfData); +#else + free(m_pfData); +#endif +} + + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CFloat32Data2D::_clear() +{ + m_iWidth = 0; + m_iHeight = 0; + m_iSize = 0; + + m_pfData = NULL; + m_ppfData2D = NULL; + + m_fGlobalMin = 0.0f; + m_fGlobalMax = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Un-initialize the object, bringing it back in the unitialized state. +void CFloat32Data2D::_unInit() +{ + ASTRA_ASSERT(m_bInitialized); + + _freeData(); + _clear(); + m_bInitialized = false; +} +//---------------------------------------------------------------------------------------- + + + + //---------------------------------------------------------------------------------------- + // Data Operations +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. +void CFloat32Data2D::copyData(const float32* _pfData) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_pfData != NULL); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = _pfData[i]; + } +} + +//---------------------------------------------------------------------------------------- +// scale m_pfData from 0 to 255. + +void CFloat32Data2D::scale() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + _computeGlobalMinMax(); + for (size_t i = 0; i < m_iSize; i++) + { + // do checks + m_pfData[i]= (m_pfData[i] - m_fGlobalMin) / (m_fGlobalMax - m_fGlobalMin) * 255; ; + } + + +} + +//---------------------------------------------------------------------------------------- +// Set each element of the data to a specific scalar value +void CFloat32Data2D::setData(float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } +} + +//---------------------------------------------------------------------------------------- +// Clear Data +void CFloat32Data2D::clearData() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // set data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = 0.0f; + } +} +//---------------------------------------------------------------------------------------- + + + + //---------------------------------------------------------------------------------------- + // Statistics Operations +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Update data statistics, such as minimum and maximum value, after the data has been modified. +void CFloat32Data2D::updateStatistics() +{ + _computeGlobalMinMax(); +} + +//---------------------------------------------------------------------------------------- +// Find the minimum and maximum data value. +void CFloat32Data2D::_computeGlobalMinMax() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // initial values + m_fGlobalMin = m_pfData[0]; + m_fGlobalMax = m_pfData[0]; + m_fGlobalMean = 0.0f; + + // loop + for (size_t i = 0; i < m_iSize; i++) + { + // do checks + float32 v = m_pfData[i]; + if (v < m_fGlobalMin) { + m_fGlobalMin = v; + } + if (v > m_fGlobalMax) { + m_fGlobalMax = v; + } + m_fGlobalMean +=v; + } + m_fGlobalMean /= m_iSize; +} +//---------------------------------------------------------------------------------------- + + +CFloat32Data2D& CFloat32Data2D::clampMin(float32& _fMin) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] < _fMin) + m_pfData[i] = _fMin; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::clampMax(float32& _fMax) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] > _fMax) + m_pfData[i] = _fMax; + } + return (*this); +} + + +//---------------------------------------------------------------------------------------- +// Operator Overloading +//---------------------------------------------------------------------------------------- +CFloat32Data2D& CFloat32Data2D::operator+=(const CFloat32Data2D& v) +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(v.m_bInitialized); + ASTRA_ASSERT(getSize() == v.getSize()); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] += v.m_pfData[i]; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator-=(const CFloat32Data2D& v) +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(v.m_bInitialized); + ASTRA_ASSERT(getSize() == v.getSize()); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] -= v.m_pfData[i]; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator*=(const CFloat32Data2D& v) +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(v.m_bInitialized); + ASTRA_ASSERT(getSize() == v.getSize()); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] *= v.m_pfData[i]; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator*=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] *= f; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator/=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] /= f; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator+=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] += f; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator-=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] -= f; + } + return (*this); +} + + + + +} // end namespace astra diff --git a/src/Float32Data3D.cpp b/src/Float32Data3D.cpp new file mode 100644 index 0000000..4280b3b --- /dev/null +++ b/src/Float32Data3D.cpp @@ -0,0 +1,55 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data3D.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data3D::CFloat32Data3D() +{ + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CFloat32Data3D::~CFloat32Data3D() +{ + +} +//---------------------------------------------------------------------------------------- + +bool CFloat32Data3D::_data3DSizesEqual(const CFloat32Data3D * _pA, const CFloat32Data3D * _pB) +{ + return ((_pA->m_iWidth == _pB->m_iWidth) && (_pA->m_iHeight == _pB->m_iHeight) && (_pA->m_iDepth == _pB->m_iDepth)); +} + +} // end namespace astra diff --git a/src/Float32Data3DMemory.cpp b/src/Float32Data3DMemory.cpp new file mode 100644 index 0000000..386770c --- /dev/null +++ b/src/Float32Data3DMemory.cpp @@ -0,0 +1,356 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data3DMemory.h" +#include <iostream> + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data3DMemory::CFloat32Data3DMemory() +{ + _clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor. Free allocated memory +CFloat32Data3DMemory::~CFloat32Data3DMemory() +{ + if (m_bInitialized) + { + _unInit(); + } +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class, allocating (but not initializing) the data block. +bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_iDepth > 0); + + if (m_bInitialized) + { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iDepth = _iDepth; + m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth; + + // allocate memory for the data, but do not fill it + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + _allocateData(); + + // set minmax to default values + m_fGlobalMin = 0.0; + m_fGlobalMax = 0.0; + + // initialization complete + return true; + +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with initialization of the data block. +bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, const float32* _pfData) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_iDepth > 0); + ASTRA_ASSERT(_pfData != NULL); + + if (m_bInitialized) { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iDepth = _iDepth; + m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth; + + // allocate memory for the data, but do not fill it + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _pfData[i]; + } + + // initialization complete + return true; +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with initialization of the data block. +bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_iDepth > 0); + + if (m_bInitialized) { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iDepth = _iDepth; + m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth; + + // allocate memory for the data, but do not fill it + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } + + // initialization complete + return true; +} +//---------------------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------------------- +// Allocate memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data3DMemory::_allocateData() +{ + // basic checks + ASTRA_ASSERT(!m_bInitialized); + + ASTRA_ASSERT(m_iSize > 0); + ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight * m_iDepth); + ASTRA_ASSERT(m_pfData == NULL); + ASTRA_ASSERT(m_ppfDataRowInd == NULL); + ASTRA_ASSERT(m_pppfDataSliceInd == NULL); + + // allocate contiguous block +#ifdef _MSC_VER + m_pfData = (float32*)_aligned_malloc(m_iSize * sizeof(float32), 16); +#else + int ret = posix_memalign((void**)&m_pfData, 16, m_iSize * sizeof(float32)); + ASTRA_ASSERT(ret == 0); +#endif + ASTRA_ASSERT(((size_t)m_pfData & 15) == 0); + + // create array of pointers to each row of the data block + m_ppfDataRowInd = new float32*[m_iHeight*m_iDepth]; + for (int iy = 0; iy < m_iHeight*m_iDepth; iy++) + { + m_ppfDataRowInd[iy] = &(m_pfData[iy * m_iWidth]); + } + + // create array of pointers to each row of the data block + m_pppfDataSliceInd = new float32**[m_iDepth]; + for (int iy = 0; iy < m_iDepth; iy++) + { + m_pppfDataSliceInd[iy] = &(m_ppfDataRowInd[iy * m_iHeight]); + } +} + +//---------------------------------------------------------------------------------------- +// Free memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data3DMemory::_freeData() +{ + // basic checks + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_ppfDataRowInd != NULL); + ASTRA_ASSERT(m_pppfDataSliceInd != NULL); + + // free memory for index table + delete[] m_pppfDataSliceInd; + // free memory for index table + delete[] m_ppfDataRowInd; + // free memory for data block +#ifdef _MSC_VER + _aligned_free(m_pfData); +#else + free(m_pfData); +#endif +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CFloat32Data3DMemory::_clear() +{ + m_iWidth = 0; + m_iHeight = 0; + m_iDepth = 0; + m_iSize = 0; + + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + + //m_fGlobalMin = 0.0f; + //m_fGlobalMax = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Un-initialize the object, bringing it back in the unitialized state. +void CFloat32Data3DMemory::_unInit() +{ + ASTRA_ASSERT(m_bInitialized); + + _freeData(); + _clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Update data statistics, such as minimum and maximum value, after the data has been modified. +void CFloat32Data3DMemory::updateStatistics() +{ + _computeGlobalMinMax(); +} + +//---------------------------------------------------------------------------------------- +// Find the minimum and maximum data value. +void CFloat32Data3DMemory::_computeGlobalMinMax() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // initial values + m_fGlobalMin = m_pfData[0]; + m_fGlobalMax = m_pfData[0]; + + // loop + size_t i; + float32 v; + for (i = 0; i < m_iSize; ++i) + { + v = m_pfData[i]; + if (v < m_fGlobalMin) m_fGlobalMin = v; + if (v > m_fGlobalMax) m_fGlobalMax = v; + } +} + +//---------------------------------------------------------------------------------------- +// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. +void CFloat32Data3DMemory::copyData(const float32* _pfData, size_t _iSize) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_pfData != NULL); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + ASTRA_ASSERT(m_iSize == _iSize); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _pfData[i]; + } +} + +//---------------------------------------------------------------------------------------- +// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. +void CFloat32Data3DMemory::setData(float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } +} + +//---------------------------------------------------------------------------------------- +// Clear Data +void CFloat32Data3DMemory::clearData() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // set data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = 0.0f; + } +} + +//---------------------------------------------------------------------------------------- + +CFloat32Data3D& CFloat32Data3DMemory::clampMin(float32& _fMin) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] < _fMin) + m_pfData[i] = _fMin; + } + return (*this); +} + +CFloat32Data3D& CFloat32Data3DMemory::clampMax(float32& _fMax) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] > _fMax) + m_pfData[i] = _fMax; + } + return (*this); +} + + + + +} // end namespace astra diff --git a/src/Float32ProjectionData2D.cpp b/src/Float32ProjectionData2D.cpp new file mode 100644 index 0000000..a74fc14 --- /dev/null +++ b/src/Float32ProjectionData2D.cpp @@ -0,0 +1,139 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32ProjectionData2D.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32ProjectionData2D::CFloat32ProjectionData2D() : + CFloat32Data2D() +{ + m_bInitialized = false; + m_pGeometry = NULL; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class, allocating (but not initializing) the data block. +CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry) +{ + m_bInitialized = false; + initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with initialization of the data. +CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with scalar initialization of the data. +CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + + +//---------------------------------------------------------------------------------------- +// Copy constructor +CFloat32ProjectionData2D::CFloat32ProjectionData2D(const CFloat32ProjectionData2D& _other) : CFloat32Data2D(_other) +{ + // Data is copied by parent constructor + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; +} + +// Assignment operator + +CFloat32ProjectionData2D& CFloat32ProjectionData2D::operator=(const CFloat32ProjectionData2D& _other) +{ + ASTRA_ASSERT(_other.m_bInitialized); + + if (m_bInitialized) + delete m_pGeometry; + *((CFloat32Data2D*)this) = _other; + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; + + return *this; +} + + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount()); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount(), _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount(), _fScalar); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32ProjectionData2D::~CFloat32ProjectionData2D() +{ + if (m_bInitialized) + delete m_pGeometry; + m_pGeometry = 0; +} + +//---------------------------------------------------------------------------------------- +void CFloat32ProjectionData2D::changeGeometry(CProjectionGeometry2D* _pGeometry) +{ + if (!m_bInitialized) return; + + delete m_pGeometry; + m_pGeometry = _pGeometry->clone(); +} + +} // end namespace astra diff --git a/src/Float32ProjectionData3D.cpp b/src/Float32ProjectionData3D.cpp new file mode 100644 index 0000000..66bb5e3 --- /dev/null +++ b/src/Float32ProjectionData3D.cpp @@ -0,0 +1,273 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32ProjectionData3D.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructors +//---------------------------------------------------------------------------------------- + + +// Default constructor +CFloat32ProjectionData3D::CFloat32ProjectionData3D() : + CFloat32Data3D() { +} + +// Destructor +CFloat32ProjectionData3D::~CFloat32ProjectionData3D() { + delete m_pGeometry; + m_pGeometry = 0; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const CFloat32ProjectionData3D& _data) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); +#ifdef _DEBUG + CProjectionGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount(); + int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount(); + + ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount()); + ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount); +#endif + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue += fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const CFloat32ProjectionData3D& _data) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); +#ifdef _DEBUG + CProjectionGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount(); + int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount(); + + ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount()); + ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount); +#endif + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue -= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const CFloat32ProjectionData3D& _data) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); +#ifdef _DEBUG + CProjectionGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount(); + int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount(); + + ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount()); + ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount); +#endif + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue *= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue *= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator/=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue /= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue += _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue -= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +} // end namespace astra diff --git a/src/Float32ProjectionData3DMemory.cpp b/src/Float32ProjectionData3DMemory.cpp new file mode 100644 index 0000000..4d23688 --- /dev/null +++ b/src/Float32ProjectionData3DMemory.cpp @@ -0,0 +1,221 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32ProjectionData3DMemory.h" +#include "astra/ParallelProjectionGeometry3D.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory() : + CFloat32Data3DMemory() +{ + m_bInitialized = false; + m_pGeometry = NULL; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class, allocating (but not initializing) the data block. +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry) +{ + m_bInitialized = false; + initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with initialization of the data. +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with initialization of the data. +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width + m_pGeometry->getProjectionCount(), // height + m_pGeometry->getDetectorRowCount()); // depth + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width + m_pGeometry->getProjectionCount(), // height + m_pGeometry->getDetectorRowCount(), // depth + _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width + m_pGeometry->getProjectionCount(), // height + m_pGeometry->getDetectorRowCount(), // depth + _fScalar); + return m_bInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32ProjectionData3DMemory::~CFloat32ProjectionData3DMemory() +{ + //delete m_pGeometry; //delete geom inherited from CFloat32ProjectionData3D + //_unInit(); //delete stuff inherited from CFloat32Data3DMemory +} + +//---------------------------------------------------------------------------------------- +// Fetch a projection +CFloat32VolumeData2D* CFloat32ProjectionData3DMemory::fetchProjection(int _iProjectionNr) const +{ + // fetch slice of the geometry + CVolumeGeometry2D volGeom(m_pGeometry->getDetectorColCount(), m_pGeometry->getDetectorRowCount()); + // create new volume data + CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom); + // copy data + int row, col; + for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) { + res->getData()[row*m_pGeometry->getDetectorColCount() + col] = + m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col]; + } + } + // return + return res; +} + +//---------------------------------------------------------------------------------------- +// Return a projection +void CFloat32ProjectionData3DMemory::returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection) +{ + /// TODO: check geometry + // copy data + int row, col; + for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) { + m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col] = + _pProjection->getData()[row*m_pGeometry->getDetectorColCount() + col]; + } + } +} + +//---------------------------------------------------------------------------------------- +// Fetch a sinogram +CFloat32ProjectionData2D* CFloat32ProjectionData3DMemory::fetchSinogram(int _iSliceNr) const +{ + CParallelProjectionGeometry3D * pParallelProjGeo = (CParallelProjectionGeometry3D *)m_pGeometry; + CParallelProjectionGeometry2D * pProjGeo2D = pParallelProjGeo->createProjectionGeometry2D(); + + // create new projection data + CFloat32ProjectionData2D* res = new CFloat32ProjectionData2D(pProjGeo2D); + // copy data + int row, col; + + int iDetectorColumnCount = m_pGeometry->getDetectorColCount(); + int iProjectionAngleCount = m_pGeometry->getProjectionCount(); + + for (row = 0; row < m_pGeometry->getProjectionCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) + { + int iTargetIndex = row * iDetectorColumnCount + col; + int iSourceIndex = _iSliceNr * iDetectorColumnCount * iProjectionAngleCount + row * iDetectorColumnCount + col; + + float32 fStoredValue = m_pfData[iSourceIndex]; + + res->getData()[iTargetIndex] = fStoredValue; + } + } + + delete pProjGeo2D; + + // return + return res; +} + +//---------------------------------------------------------------------------------------- +// Return a sinogram +void CFloat32ProjectionData3DMemory::returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D) +{ + /// TODO: check geometry + // copy data + int row, col; + for (row = 0; row < m_pGeometry->getProjectionCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) { + m_pfData[_iSliceNr*m_pGeometry->getDetectorColCount()*m_pGeometry->getProjectionCount() + row*m_pGeometry->getDetectorColCount() + col] = + _pSinogram2D->getData()[row*m_pGeometry->getDetectorColCount() + col]; + } + } +} + +//---------------------------------------------------------------------------------------- +// Returns a specific value +float32 CFloat32ProjectionData3DMemory::getDetectorValue(int _iIndex) +{ + return m_pfData[_iIndex]; +} + +//---------------------------------------------------------------------------------------- +// Sets a specific value +void CFloat32ProjectionData3DMemory::setDetectorValue(int _iIndex, float32 _fValue) +{ + m_pfData[_iIndex] = _fValue; +} +//---------------------------------------------------------------------------------------- + +CFloat32ProjectionData3DMemory& CFloat32ProjectionData3DMemory::operator=(const CFloat32ProjectionData3DMemory& _dataIn) +{ + memcpy(m_pfData, _dataIn.m_pfData, sizeof(float32) * _dataIn.m_pGeometry->getDetectorTotCount()); + + return *this; +} + +} // end namespace astra diff --git a/src/Float32VolumeData2D.cpp b/src/Float32VolumeData2D.cpp new file mode 100644 index 0000000..f07fd71 --- /dev/null +++ b/src/Float32VolumeData2D.cpp @@ -0,0 +1,135 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32VolumeData2D.h" + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32VolumeData2D::CFloat32VolumeData2D() : + CFloat32Data2D() +{ + m_pGeometry = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class, allocating (but not initializing) the data block. +CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Copy constructor +CFloat32VolumeData2D::CFloat32VolumeData2D(const CFloat32VolumeData2D& _other) : CFloat32Data2D(_other) +{ + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; +} + +// Assignment operator + +CFloat32VolumeData2D& CFloat32VolumeData2D::operator=(const CFloat32VolumeData2D& _other) +{ + ASTRA_ASSERT(_other.m_bInitialized); + + if (m_bInitialized) + delete m_pGeometry; + *((CFloat32Data2D*)this) = _other; + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; + + return *this; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32VolumeData2D::~CFloat32VolumeData2D() +{ + if (m_bInitialized) + delete m_pGeometry; + m_pGeometry = 0; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount()); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), _fScalar); + return m_bInitialized; +} +//---------------------------------------------------------------------------------------- +void CFloat32VolumeData2D::changeGeometry(CVolumeGeometry2D* _pGeometry) +{ + if (!m_bInitialized) return; + + delete m_pGeometry; + m_pGeometry = _pGeometry->clone(); +} + + +} // end namespace astra diff --git a/src/Float32VolumeData3D.cpp b/src/Float32VolumeData3D.cpp new file mode 100644 index 0000000..d269aa8 --- /dev/null +++ b/src/Float32VolumeData3D.cpp @@ -0,0 +1,269 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32VolumeData3D.h" + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32VolumeData3D::CFloat32VolumeData3D() : + CFloat32Data3D() { + +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32VolumeData3D::~CFloat32VolumeData3D() { + +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator+=(const CFloat32VolumeData3D& _data) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); +#ifdef _DEBUG + CVolumeGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount(); + int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount(); + + ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount()); + ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount); +#endif + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue += fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const CFloat32VolumeData3D& _data) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); +#ifdef _DEBUG + CVolumeGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount(); + int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount(); + + ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount()); + ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount); +#endif + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue -= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator*=(const CFloat32VolumeData3D& _data) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); +#ifdef _DEBUG + CVolumeGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount(); + int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount(); + + ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount()); + ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount); +#endif + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue *= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator*=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue *= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator/=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue /= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator+=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue += _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue -= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +} // end namespace astra diff --git a/src/Float32VolumeData3DMemory.cpp b/src/Float32VolumeData3DMemory.cpp new file mode 100644 index 0000000..aa3832b --- /dev/null +++ b/src/Float32VolumeData3DMemory.cpp @@ -0,0 +1,208 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32VolumeData3DMemory.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory() : + CFloat32Data3DMemory() +{ + m_pGeometry = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class, allocating (but not initializing) the data block. +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, const float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32VolumeData3DMemory::~CFloat32VolumeData3DMemory() +{ + if(m_pGeometry){ + delete m_pGeometry; + } + m_pGeometry = 0; + +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount()); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _fScalar); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Fetch a slice +CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceZ(int _iSliceIndex) const +{ + // fetch slice of the geometry + int iRowCount = m_pGeometry->getGridRowCount(); + int iColumnCount = m_pGeometry->getGridColCount(); + CVolumeGeometry2D volGeom(iColumnCount, iRowCount); + + // create new volume data + CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom); + + // copy data + int iSliceCount = m_pGeometry->getGridSliceCount(); + float * pfTargetData = res->getData(); + for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++) + { + for(int iColumnIndex = 0; iColumnIndex < iColumnCount; iColumnIndex++) + { + int iSourceIndex = _iSliceIndex * iColumnCount * iRowCount + iRowIndex * iColumnCount + iColumnIndex; + int iTargetIndex = iRowIndex * iColumnCount + iColumnIndex; + float fStoredValue = m_pfData[iSourceIndex]; + pfTargetData[iTargetIndex] = fStoredValue; + } + } + // return + return res; +} + +//---------------------------------------------------------------------------------------- +// Return a slice +void CFloat32VolumeData3DMemory::returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSlice) +{ + int iRowCount = _pSlice->getGeometry()->getGridRowCount(); + int iColumnCount = _pSlice->getGeometry()->getGridColCount(); + + assert(iRowCount == m_pGeometry->getGridRowCount()); + assert(iColumnCount == m_pGeometry->getGridColCount()); + + for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++) + { + for(int iColumnIndex = 0; iColumnIndex < iColumnCount; iColumnIndex++) + { + int iSourceIndex = iRowIndex * iColumnCount + iColumnIndex; + int iTargetIndex = _iSliceIndex * iColumnCount * iRowCount + iRowIndex * iColumnCount + iColumnIndex; + float fStoredValue = _pSlice->getDataConst()[iSourceIndex]; + m_pfData[iTargetIndex] = fStoredValue; + } + } +} + +CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceX(int _iColumnIndex) const +{ + // TODO: + assert(false); + return NULL; +} + +CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceY(int _iRowIndex) const +{ + // TODO: + assert(false); + return NULL; +} + +void CFloat32VolumeData3DMemory::returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSliceData) +{ + // TODO: + assert(false); +} + +void CFloat32VolumeData3DMemory::returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSliceData) +{ + // TODO: + assert(false); +} + +//---------------------------------------------------------------------------------------- +// Returns a specific value +float32 CFloat32VolumeData3DMemory::getVoxelValue(int _iIndex) +{ + return m_pfData[_iIndex]; +} + +//---------------------------------------------------------------------------------------- +// Sets a specific value +void CFloat32VolumeData3DMemory::setVoxelValue(int _iIndex, float32 _fValue) +{ + m_pfData[_iIndex] = _fValue; +} +//---------------------------------------------------------------------------------------- + +CFloat32VolumeData3DMemory& CFloat32VolumeData3DMemory::operator=(const CFloat32VolumeData3DMemory& _dataIn) +{ + memcpy(m_pfData, _dataIn.m_pfData, sizeof(float32) * _dataIn.m_pGeometry->getGridTotCount()); + + return *this; +} + +} // end namespace astra diff --git a/src/ForwardProjectionAlgorithm.cpp b/src/ForwardProjectionAlgorithm.cpp new file mode 100644 index 0000000..970d5b0 --- /dev/null +++ b/src/ForwardProjectionAlgorithm.cpp @@ -0,0 +1,280 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ForwardProjectionAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CForwardProjectionAlgorithm::type = "FP"; + +//---------------------------------------------------------------------------------------- +// Constructor - Default +CForwardProjectionAlgorithm::CForwardProjectionAlgorithm() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor +CForwardProjectionAlgorithm::CForwardProjectionAlgorithm(CProjector2D* _pProjector, CFloat32VolumeData2D* _pVolume, CFloat32ProjectionData2D* _pSinogram) +{ + _clear(); + initialize(_pProjector, _pVolume, _pSinogram); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CForwardProjectionAlgorithm::~CForwardProjectionAlgorithm() +{ + delete m_pForwardProjector; + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CForwardProjectionAlgorithm::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pVolume = NULL; + m_pForwardProjector = NULL; + m_bUseSinogramMask = false; + m_bUseVolumeMask = false; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CForwardProjectionAlgorithm::clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pVolume = NULL; + m_bUseSinogramMask = false; + m_bUseVolumeMask = false; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CForwardProjectionAlgorithm::_check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pProjector, "ForwardProjection", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pSinogram, "ForwardProjection", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pVolume, "ForwardProjection", "Invalid Volume Data Object."); + + // check initializations + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ForwardProjection", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "ForwardProjection", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "ForwardProjection", "Volume Data Object Not Initialized."); + + // check compatibility between projector and data classes + ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "ForwardProjection", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_pVolume->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "ForwardProjection", "Volume Data not compatible with the specified Projector."); + + ASTRA_CONFIG_CHECK(m_pForwardProjector, "ForwardProjection", "Invalid FP Policy"); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CForwardProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // volume data + node = _cfg.self->getSingleNode("VolumeDataId"); + ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No VolumeDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // volume mask + if (_cfg.self->hasOption("VolumeMaskId")) { + m_bUseVolumeMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("VolumeMaskId")); + m_pVolumeMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + + // sino mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + + // ray or voxel-driven projector? + //m_bUseVoxelProjector = _cfg.self->getOptionBool("VoxelDriven", false); + + // init data projector + _init(); + + // return success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Get Information - all +map<string,boost::any> CForwardProjectionAlgorithm::getInformation() +{ + map<string, boost::any> result; + result["ProjectorId"] = getInformation("ProjectorId"); + result["ProjectionDataId"] = getInformation("ProjectionDataId"); + result["VolumeDataId"] = getInformation("VolumeDataId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), result); +}; + +//--------------------------------------------------------------------------------------- +// Get Information - specific +boost::any CForwardProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "VolumeDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pVolume); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Initialize +bool CForwardProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram) +{ + // store classes + m_pProjector = _pProjector; + m_pVolume = _pVolume; + m_pSinogram = _pSinogram; + + // init data projector + _init(); + + // return success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CForwardProjectionAlgorithm::_init() +{ + // forward projection data projector + m_pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pVolumeMask), // reconstruction mask + DefaultFPPolicy(m_pVolume, m_pSinogram), // forward projection + m_bUseSinogramMask, m_bUseVolumeMask, true // options on/off + ); +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CForwardProjectionAlgorithm::setVolumeMask(CFloat32VolumeData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches volume + m_bUseVolumeMask = _bEnable; + m_pVolumeMask = _pMask; + if (m_pVolumeMask == NULL) { + m_bUseVolumeMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Sinogram Mask +void CForwardProjectionAlgorithm::setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches sinogram + m_bUseSinogramMask = _bEnable; + m_pSinogramMask = _pMask; + if (m_pSinogramMask == NULL) { + m_bUseSinogramMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Iterate +void CForwardProjectionAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_pSinogram->setData(0.0f); + +// if (m_bUseVoxelProjector) { +// m_pForwardProjector->projectAllVoxels(); +// } else { + m_pForwardProjector->project(); +// } + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/Fourier.cpp b/src/Fourier.cpp new file mode 100644 index 0000000..0f7da28 --- /dev/null +++ b/src/Fourier.cpp @@ -0,0 +1,233 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Fourier.h" + +namespace astra { + + +void discreteFourierTransform1D(unsigned int iLength, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + unsigned int iStrideIn, + unsigned int iStrideOut, + bool inverse) +{ + for (unsigned int w = 0; w < iLength; w++) + { + pfRealOut[iStrideOut*w] = pfImaginaryOut[iStrideOut*w] = 0; + for (unsigned int y = 0; y < iLength; y++) + { + float32 a = 2 * PI * w * y / float32(iLength); + if (!inverse) + a = -a; + float32 ca = cos(a); + float32 sa = sin(a); + pfRealOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * ca - pfImaginaryIn[iStrideIn*y] * sa; + pfImaginaryOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * sa + pfImaginaryIn[iStrideIn*y] * ca; + } + } + + if (inverse) { + for (unsigned int x = 0; x < iLength; ++x) { + pfRealOut[iStrideOut*x] /= iLength; + pfImaginaryOut[iStrideOut*x] /= iLength; + } + } +} + +void discreteFourierTransform2D(unsigned int iHeight, unsigned int iWidth, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + bool inverse) +{ + float32* reTemp = new float32[iWidth * iHeight]; + float32* imTemp = new float32[iWidth * iHeight]; + + //calculate the fourier transform of the columns + for (unsigned int x = 0; x < iWidth; x++) + { + discreteFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x, + reTemp+x, imTemp+x, + iWidth, iWidth, inverse); + } + + //calculate the fourier transform of the rows + for(unsigned int y = 0; y < iHeight; y++) + { + discreteFourierTransform1D(iWidth, + reTemp+y*iWidth, + imTemp+y*iWidth, + pfRealOut+y*iWidth, + pfImaginaryOut+y*iWidth, + 1, 1, inverse); + } + + delete[] reTemp; + delete[] imTemp; +} + +/** permute the entries from pfDataIn into pfDataOut to prepare for an + * in-place FFT. pfDataIn may be equal to pfDataOut. + */ +static void bitReverse(unsigned int iLength, + const float32* pfDataIn, float32* pfDataOut, + unsigned int iStrideShiftIn, + unsigned int iStrideShiftOut) +{ + if (pfDataIn == pfDataOut) { + assert(iStrideShiftIn == iStrideShiftOut); + float32 t; + unsigned int j = 0; + for(unsigned int i = 0; i < iLength - 1; i++) { + if (i < j) { + t = pfDataOut[i<<iStrideShiftOut]; + pfDataOut[i<<iStrideShiftOut] = pfDataOut[j<<iStrideShiftOut]; + pfDataOut[j<<iStrideShiftOut] = t; + } + unsigned int k = iLength / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + } else { + unsigned int j = 0; + for(unsigned int i = 0; i < iLength - 1; i++) { + pfDataOut[i<<iStrideShiftOut] = pfDataIn[j<<iStrideShiftIn]; + unsigned int k = iLength / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + pfDataOut[(iLength-1)<<iStrideShiftOut] = pfDataIn[(iLength-1)<<iStrideShiftOut]; + } +} + +static unsigned int log2(unsigned int n) +{ + unsigned int l = 0; + while (n > 1) { + n /= 2; + ++l; + } + return l; +} + +/** perform 1D FFT. iLength, iStrideIn, iStrideOut must be powers of two. */ +void fastTwoPowerFourierTransform1D(unsigned int iLength, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + unsigned int iStrideIn, + unsigned int iStrideOut, + bool inverse) +{ + unsigned int iStrideShiftIn = log2(iStrideIn); + unsigned int iStrideShiftOut = log2(iStrideOut); + unsigned int iLogLength = log2(iLength); + + bitReverse(iLength, pfRealIn, pfRealOut, iStrideShiftIn, iStrideShiftOut); + bitReverse(iLength, pfImaginaryIn, pfImaginaryOut, iStrideShiftIn, iStrideShiftOut); + + float32 ca = -1.0; + float32 sa = 0.0; + unsigned int l1 = 1, l2 = 1; + for(unsigned int l=0; l < iLogLength; ++l) + { + l1 = l2; + l2 *= 2; + float32 u1 = 1.0; + float32 u2 = 0.0; + for(unsigned int j = 0; j < l1; j++) + { + for(unsigned int i = j; i < iLength; i += l2) + { + unsigned int i1 = i + l1; + float32 t1 = u1 * pfRealOut[i1<<iStrideShiftOut] - u2 * pfImaginaryOut[i1<<iStrideShiftOut]; + float32 t2 = u1 * pfImaginaryOut[i1<<iStrideShiftOut] + u2 * pfRealOut[i1<<iStrideShiftOut]; + pfRealOut[i1<<iStrideShiftOut] = pfRealOut[i<<iStrideShiftOut] - t1; + pfImaginaryOut[i1<<iStrideShiftOut] = pfImaginaryOut[i<<iStrideShiftOut] - t2; + pfRealOut[i<<iStrideShiftOut] += t1; + pfImaginaryOut[i<<iStrideShiftOut] += t2; + } + float32 z = u1 * ca - u2 * sa; + u2 = u1 * sa + u2 * ca; + u1 = z; + } + sa = sqrt((1.0 - ca) / 2.0); + if (!inverse) + sa = -sa; + ca = sqrt((1.0 + ca) / 2.0); + } + + if (inverse) { + for (unsigned int i = 0; i < iLength; ++i) { + pfRealOut[i<<iStrideShiftOut] /= iLength; + pfImaginaryOut[i<<iStrideShiftOut] /= iLength; + } + } +} + +void fastTwoPowerFourierTransform2D(unsigned int iHeight, + unsigned int iWidth, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + bool inverse) +{ + //calculate the fourier transform of the columns + for (unsigned int x = 0; x < iWidth; x++) + { + fastTwoPowerFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x, + pfRealOut+x, pfImaginaryOut+x, + iWidth, iWidth, inverse); + } + + //calculate the fourier transform of the rows + for (unsigned int y = 0; y < iHeight; y++) + { + fastTwoPowerFourierTransform1D(iWidth, + pfRealOut+y*iWidth, + pfImaginaryOut+y*iWidth, + pfRealOut+y*iWidth, + pfImaginaryOut+y*iWidth, + 1, 1, inverse); + } +} + +} diff --git a/src/Globals.cpp b/src/Globals.cpp new file mode 100644 index 0000000..7f93fae --- /dev/null +++ b/src/Globals.cpp @@ -0,0 +1,32 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Globals.h" + +// nothing to see here :) + diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..28368b2 --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,77 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <astra/Logger.h> + +using namespace astra; + +const char * g_loggerFileName = "astra_logger.txt"; + +void CLogger::_assureIsInitialized() +{ + if(!m_bInitialized) + { + m_pOutFile = fopen(g_loggerFileName, "r"); + if(m_pOutFile != NULL) + { + // file exists, users wants to log + fclose(m_pOutFile); + m_pOutFile = fopen(g_loggerFileName, "w"); + } + + m_bInitialized = true; + } +} + +void CLogger::writeLine(const char * _text) +{ + _assureIsInitialized(); + + if(m_pOutFile != NULL) + { + fprintf(m_pOutFile, "%s\n", _text); + fflush(m_pOutFile); + } +} + +void CLogger::writeTerminalCUDAError(const char * _fileName, int _iLine, const char * _errString) +{ + char buffer[256]; + + sprintf(buffer, "Cuda error in file '%s' in line %i : %s.", _fileName, _iLine, _errString); + + writeLine(buffer); +} + +CLogger::CLogger() +{ + ; +} + +FILE * CLogger::m_pOutFile = NULL; +bool CLogger::m_bInitialized = false; diff --git a/src/ParallelBeamBlobKernelProjector2D.cpp b/src/ParallelBeamBlobKernelProjector2D.cpp new file mode 100644 index 0000000..e08f616 --- /dev/null +++ b/src/ParallelBeamBlobKernelProjector2D.cpp @@ -0,0 +1,271 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamBlobKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamBlobKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamBlobKernelProjector2D::type = "blob"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamBlobKernelProjector2D::CParallelBeamBlobKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamBlobKernelProjector2D::CParallelBeamBlobKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry, + float32 _fBlobSize, + float32 _fBlobSampleRate, + int _iBlobSampleCount, + float32* _pfBlobValues) +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry, _fBlobSize, _fBlobSampleRate, _iBlobSampleCount, _pfBlobValues); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamBlobKernelProjector2D::~CParallelBeamBlobKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CParallelBeamBlobKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_pfBlobValues = NULL; + m_iBlobSampleCount = 0; + m_fBlobSize = 0; + m_fBlobSampleRate = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamBlobKernelProjector2D::clear() +{ + CProjector2D::clear(); + if (m_pfBlobValues) { + delete[] m_pfBlobValues; + m_pfBlobValues = NULL; + } + m_iBlobSampleCount = 0; + m_fBlobSize = 0; + m_fBlobSampleRate = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamBlobKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamBlobKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamBlobKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_iBlobSampleCount > 0, "ParallelBeamBlobKernelProjector2D", "m_iBlobSampleCount should be strictly positive."); + ASTRA_CONFIG_CHECK(m_pfBlobValues, "ParallelBeamBlobKernelProjector2D", "Invalid Volume Geometry Object."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamBlobKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // required: Kernel + XMLNode* node = _cfg.self->getSingleNode("Kernel"); + ASTRA_CONFIG_CHECK(node, "BlobProjector", "No Kernel tag specified."); + { + // Required: KernelSize + XMLNode* node2 = node->getSingleNode("KernelSize"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelSize tag specified."); + m_fBlobSize = boost::lexical_cast<float32>(node2->getContent()); + + // Required: SampleRate + node2 = node->getSingleNode("SampleRate"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleRate tag specified."); + m_fBlobSampleRate = boost::lexical_cast<float32>(node2->getContent()); + + // Required: SampleCount + node2 = node->getSingleNode("SampleCount"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleCount tag specified."); + m_iBlobSampleCount = boost::lexical_cast<int>(node2->getContent()); + + // Required: KernelValues + node2 = node->getSingleNode("KernelValues"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValues tag specified."); + vector<float32> values = node2->getContentNumericalArray(); + ASTRA_CONFIG_CHECK(values.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount."); + m_pfBlobValues = new float32[m_iBlobSampleCount]; + for (int i = 0; i < m_iBlobSampleCount; i++) { + m_pfBlobValues[i] = values[i]; + } + + // Required: KernelValues + node2 = node->getSingleNode("KernelValuesNeg"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValuesNeg tag specified."); + vector<float32> values2 = node2->getContentNumericalArray(); + ASTRA_CONFIG_CHECK(values2.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount."); + m_pfBlobValuesNeg = new float32[m_iBlobSampleCount]; + for (int i = 0; i < m_iBlobSampleCount; i++) { + m_pfBlobValuesNeg[i] = values2[i]; + } + + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// initialize +bool CParallelBeamBlobKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry, + float32 _fBlobSize, + float32 _fBlobSampleRate, + int _iBlobSampleCount, + float32* _pfBlobValues) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + ASTRA_CONFIG_CHECK(_pProjectionGeometry, "BlobProjector", "Invalid ProjectionGeometry Object"); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "BlobProjector", "Invalid ProjectionGeometry Object"); + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + m_fBlobSize = _fBlobSize; + m_fBlobSampleRate = _fBlobSampleRate; + m_iBlobSampleCount = _iBlobSampleCount; + m_pfBlobValues = new float32[_iBlobSampleCount]; + for (int i = 0; i <_iBlobSampleCount; i++) { + m_pfBlobValues[i] = _pfBlobValues[i]; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamBlobKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return (int)(maxDim * 2 * (m_fBlobSize+2) + 1); +} +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamBlobKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CParallelBeamBlobKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 x = m_pVolumeGeometry->pixelColToCenterX(_iCol); + float32 y = m_pVolumeGeometry->pixelRowToCenterY(_iRow); + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 t = x * cos(theta) + y * sin(theta); + if (inverse) t *= -1.0f; + + // calculate the offset on the detectorarray (in indices) + float32 d = m_pProjectionGeometry->detectorOffsetToIndexFloat(t); + int dmin = (int)ceil(d - m_fBlobSize); + int dmax = (int)floor(d + m_fBlobSize); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (d >= 0 && d < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} diff --git a/src/ParallelBeamLineKernelProjector2D.cpp b/src/ParallelBeamLineKernelProjector2D.cpp new file mode 100644 index 0000000..16cc614 --- /dev/null +++ b/src/ParallelBeamLineKernelProjector2D.cpp @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamLineKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamLineKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamLineKernelProjector2D::type = "line"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamLineKernelProjector2D::CParallelBeamLineKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamLineKernelProjector2D::CParallelBeamLineKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamLineKernelProjector2D::~CParallelBeamLineKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CParallelBeamLineKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamLineKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamLineKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamLineKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamLineKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamLineKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamLineKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CParallelBeamLineKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamLineKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 2 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamLineKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Project Point +std::vector<SDetector2D> CParallelBeamLineKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 tUL = xUL * cos(theta) + yUL * sin(theta); + float32 tUR = xUR * cos(theta) + yUR * sin(theta); + float32 tLL = xLL * cos(theta) + yLL * sin(theta); + float32 tLR = xLR * cos(theta) + yLR * sin(theta); + if (inverse) { + tUL *= -1.0f; + tUR *= -1.0f; + tLL *= -1.0f; + tLR *= -1.0f; + } + float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // calculate the offset on the detectorarray (in indices) + int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} + +//---------------------------------------------------------------------------------------- diff --git a/src/ParallelBeamLinearKernelProjector2D.cpp b/src/ParallelBeamLinearKernelProjector2D.cpp new file mode 100644 index 0000000..5f1679d --- /dev/null +++ b/src/ParallelBeamLinearKernelProjector2D.cpp @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamLinearKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamLinearKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamLinearKernelProjector2D::type = "linear"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamLinearKernelProjector2D::CParallelBeamLinearKernelProjector2D() +{ + _clear(); +} + + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamLinearKernelProjector2D::CParallelBeamLinearKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamLinearKernelProjector2D::~CParallelBeamLinearKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - CParallelBeamLinearKernelProjector2D +void CParallelBeamLinearKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamLinearKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamLinearKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamLinearKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamLinearKernelProjector2D", "Unsupported projection geometry"); + + /// TODO: ADD PIXEL H/W LIMITATIONS + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamLinearKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamLinearKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CParallelBeamLinearKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamLinearKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 2 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamLinearKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CParallelBeamLinearKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 1.5f; + float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 1.5f; + float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 1.5f; + float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 1.5f; + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 tUL = xUL * cos(theta) + yUL * sin(theta); + float32 tUR = xUR * cos(theta) + yUR * sin(theta); + float32 tLL = xLL * cos(theta) + yLL * sin(theta); + float32 tLR = xLR * cos(theta) + yLR * sin(theta); + if (inverse) { + tUL *= -1.0f; + tUR *= -1.0f; + tLL *= -1.0f; + tLR *= -1.0f; + } + float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // calculate the offset on the detectorarray (in indices) + int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} diff --git a/src/ParallelBeamStripKernelProjector2D.cpp b/src/ParallelBeamStripKernelProjector2D.cpp new file mode 100644 index 0000000..78997af --- /dev/null +++ b/src/ParallelBeamStripKernelProjector2D.cpp @@ -0,0 +1,224 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamStripKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamStripKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamStripKernelProjector2D::type = "strip"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamStripKernelProjector2D::CParallelBeamStripKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamStripKernelProjector2D::CParallelBeamStripKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamStripKernelProjector2D::~CParallelBeamStripKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CParallelBeamStripKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamStripKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamStripKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamStripKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamStripKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamStripKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamStripKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CParallelBeamStripKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamStripKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + int scale = m_pProjectionGeometry->getDetectorWidth() / min(m_pVolumeGeometry->getPixelLengthX(), m_pVolumeGeometry->getPixelLengthY()); + return maxDim * scale * 10 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamStripKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CParallelBeamStripKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 tUL = xUL * cos(theta) + yUL * sin(theta); + float32 tUR = xUR * cos(theta) + yUR * sin(theta); + float32 tLL = xLL * cos(theta) + yLL * sin(theta); + float32 tLR = xLR * cos(theta) + yLR * sin(theta); + if (inverse) { + tUL *= -1.0f; + tUR *= -1.0f; + tLL *= -1.0f; + tLR *= -1.0f; + } + float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // calculate the offset on the detectorarray (in indices) + int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} + +//---------------------------------------------------------------------------------------- diff --git a/src/ParallelProjectionGeometry2D.cpp b/src/ParallelProjectionGeometry2D.cpp new file mode 100644 index 0000000..79a325b --- /dev/null +++ b/src/ParallelProjectionGeometry2D.cpp @@ -0,0 +1,186 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelProjectionGeometry2D.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CParallelProjectionGeometry2D::CParallelProjectionGeometry2D() : + CProjectionGeometry2D() +{ + +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CParallelProjectionGeometry2D::CParallelProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) +{ + _clear(); + initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles, + _pfExtraDetectorOffsets); +} + +//---------------------------------------------------------------------------------------- +CParallelProjectionGeometry2D::CParallelProjectionGeometry2D(const CParallelProjectionGeometry2D& _projGeom) +{ + _clear(); + initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_fDetectorWidth, + _projGeom.m_pfProjectionAngles, + _projGeom.m_pfExtraDetectorOffset); +} + +//---------------------------------------------------------------------------------------- + +CParallelProjectionGeometry2D& CParallelProjectionGeometry2D::operator=(const CParallelProjectionGeometry2D& _other) +{ + if (m_bInitialized) + delete[] m_pfProjectionAngles; + m_bInitialized = _other.m_bInitialized; + if (_other.m_bInitialized) { + m_iProjectionAngleCount = _other.m_iProjectionAngleCount; + m_iDetectorCount = _other.m_iDetectorCount; + m_fDetectorWidth = _other.m_fDetectorWidth; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(m_pfProjectionAngles, _other.m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + } + return *this; + +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CParallelProjectionGeometry2D::~CParallelProjectionGeometry2D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CParallelProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("ParallelProjectionGeometry2D", this, _cfg); + + + // initialization of parent class + CProjectionGeometry2D::initialize(_cfg); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CParallelProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) +{ + _initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles, + _pfExtraDetectorOffsets); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CParallelProjectionGeometry2D::clone() +{ + return new CParallelProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CParallelProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry2D + CParallelProjectionGeometry2D* pGeom2 = dynamic_cast<CParallelProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + // if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CParallelProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "parallel"); +} +//---------------------------------------------------------------------------------------- + +CVector3D CParallelProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */) +{ + CVector3D vOutput; + + float32 fProjectionAngle = getProjectionAngle(_iProjectionIndex); + + vOutput.setX(cosf(fProjectionAngle)); + vOutput.setY(sinf(fProjectionAngle)); + vOutput.setZ(0.0f); + + return vOutput; +} + +} // end namespace astra diff --git a/src/ParallelProjectionGeometry3D.cpp b/src/ParallelProjectionGeometry3D.cpp new file mode 100644 index 0000000..c0366bc --- /dev/null +++ b/src/ParallelProjectionGeometry3D.cpp @@ -0,0 +1,211 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelProjectionGeometry3D.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CParallelProjectionGeometry3D::CParallelProjectionGeometry3D() : + CProjectionGeometry3D() +{ + +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CParallelProjectionGeometry3D::CParallelProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX, + const float32* _pfExtraDetectorOffsetsY) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles, + _pfExtraDetectorOffsetsX, + _pfExtraDetectorOffsetsY); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CParallelProjectionGeometry3D::~CParallelProjectionGeometry3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CParallelProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ParallelProjectionGeometry3D", this, _cfg); + + + // initialization of parent class + CProjectionGeometry3D::initialize(_cfg); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CParallelProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX, + const float32* _pfExtraDetectorOffsetsY) +{ + _initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles, + _pfExtraDetectorOffsetsX, + _pfExtraDetectorOffsetsY); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CParallelProjectionGeometry3D::clone() const +{ + CParallelProjectionGeometry3D* res = new CParallelProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfProjectionAngles, m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + res->m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfExtraDetectorOffsetsX, m_pfExtraDetectorOffsetsX, sizeof(float32)*m_iProjectionAngleCount); + res->m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfExtraDetectorOffsetsY, m_pfExtraDetectorOffsetsY, sizeof(float32)*m_iProjectionAngleCount); + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CParallelProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry3D + const CParallelProjectionGeometry3D* pGeom2 = dynamic_cast<const CParallelProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CParallelProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "parallel"); +} + +//---------------------------------------------------------------------------------------- +void CParallelProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type","parallel3d"); + _sNode->addChildNode("DetectorSpacingX", m_fDetectorSpacingX); + _sNode->addChildNode("DetectorSpacingY", m_fDetectorSpacingY); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + _sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); + _sNode->addChildNode("ExtraDetectorOffsetsX", m_pfExtraDetectorOffsetsX, m_iProjectionAngleCount); + _sNode->addChildNode("ExtraDetectorOffsetsY", m_pfExtraDetectorOffsetsY, m_iProjectionAngleCount); +} + +CVector3D CParallelProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + float fTheta = m_pfProjectionAngles[_iProjectionIndex]; + + float fDirX = cosf(fTheta); + float fDirY = sinf(fTheta); + float fDirZ = 0.0f; + + return CVector3D(fDirX, fDirY, fDirZ); +} + +CParallelProjectionGeometry2D * CParallelProjectionGeometry3D::createProjectionGeometry2D() const +{ + const float32 * pfProjectionAngles = getProjectionAngles(); //new float32[getProjectionCount()]; + //getProjectionAngles(pfProjectionAngles); + + CParallelProjectionGeometry2D * pOutput = new CParallelProjectionGeometry2D(getProjectionCount(), + getDetectorColCount(), getDetectorSpacingX(), pfProjectionAngles,getExtraDetectorOffsetsX()); + + //delete [] pfProjectionAngles; + + return pOutput; +} + +//---------------------------------------------------------------------------------------- + +} // end namespace astra diff --git a/src/ParallelVecProjectionGeometry3D.cpp b/src/ParallelVecProjectionGeometry3D.cpp new file mode 100644 index 0000000..c1265dd --- /dev/null +++ b/src/ParallelVecProjectionGeometry3D.cpp @@ -0,0 +1,230 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelVecProjectionGeometry3D.h" + +#include <cstring> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CParallelVecProjectionGeometry3D::CParallelVecProjectionGeometry3D() : + CProjectionGeometry3D() +{ + m_pProjectionAngles = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CParallelVecProjectionGeometry3D::CParallelVecProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SPar3DProjection* _pProjectionAngles + ) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CParallelVecProjectionGeometry3D::~CParallelVecProjectionGeometry3D() +{ + delete[] m_pProjectionAngles; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CParallelVecProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ParallelVecProjectionGeometry3D", this, _cfg); + + XMLNode* node; + + // TODO: Fix up class hierarchy... this class doesn't fit very well. + // initialization of parent class + //CProjectionGeometry3D::initialize(_cfg); + + // Required: DetectorRowCount + node = _cfg.self->getSingleNode("DetectorRowCount"); + ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorRowCount"); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorColCount"); + ASTRA_CONFIG_CHECK(node, "", "No DetectorColCount tag specified."); + m_iDetectorColCount = boost::lexical_cast<int>(node->getContent()); + m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount; + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorColCount"); + + // Required: Vectors + node = _cfg.self->getSingleNode("Vectors"); + ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No Vectors tag specified."); + vector<double> data = node->getContentNumericalArrayDouble(); + CC.markNodeParsed("Vectors"); + ASTRA_DELETE(node); + ASTRA_CONFIG_CHECK(data.size() % 12 == 0, "ParallelVecProjectionGeometry3D", "Vectors doesn't consist of 12-tuples."); + m_iProjectionAngleCount = data.size() / 12; + m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount]; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + SPar3DProjection& p = m_pProjectionAngles[i]; + p.fRayX = data[12*i + 0]; + p.fRayY = data[12*i + 1]; + p.fRayZ = data[12*i + 2]; + p.fDetUX = data[12*i + 6]; + p.fDetUY = data[12*i + 7]; + p.fDetUZ = data[12*i + 8]; + p.fDetVX = data[12*i + 9]; + p.fDetVY = data[12*i + 10]; + p.fDetVZ = data[12*i + 11]; + + // The backend code currently expects the corner of the detector, while + // the matlab interface supplies the center + p.fDetSX = data[12*i + 3] - 0.5f * m_iDetectorRowCount * p.fDetVX - 0.5f * m_iDetectorColCount * p.fDetUX; + p.fDetSY = data[12*i + 4] - 0.5f * m_iDetectorRowCount * p.fDetVY - 0.5f * m_iDetectorColCount * p.fDetUY; + p.fDetSZ = data[12*i + 5] - 0.5f * m_iDetectorRowCount * p.fDetVZ - 0.5f * m_iDetectorColCount * p.fDetUZ; + } + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CParallelVecProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SPar3DProjection* _pProjectionAngles) +{ + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorRowCount = _iDetectorRowCount; + m_iDetectorColCount = _iDetectorColCount; + m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pProjectionAngles[i] = _pProjectionAngles[i]; + + // TODO: check? + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CParallelVecProjectionGeometry3D::clone() const +{ + CParallelVecProjectionGeometry3D* res = new CParallelVecProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount]; + memcpy(res->m_pProjectionAngles, m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount); + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CParallelVecProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry3D + const CParallelVecProjectionGeometry3D* pGeom2 = dynamic_cast<const CParallelVecProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + //if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + //if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CParallelVecProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "parallel3d_vec"); +} + +//---------------------------------------------------------------------------------------- +void CParallelVecProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type","parallel3d_vec"); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + // TODO: + //_sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); +} + +CVector3D CParallelVecProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + const SPar3DProjection& p = m_pProjectionAngles[_iProjectionIndex]; + + return CVector3D(p.fRayX, p.fRayY, p.fRayZ); +} + + +//---------------------------------------------------------------------------------------- + +bool CParallelVecProjectionGeometry3D::_check() +{ + // TODO + return true; +} + +} // end namespace astra diff --git a/src/PlatformDepSystemCode.cpp b/src/PlatformDepSystemCode.cpp new file mode 100644 index 0000000..a628aeb --- /dev/null +++ b/src/PlatformDepSystemCode.cpp @@ -0,0 +1,76 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/PlatformDepSystemCode.h" + +using namespace astra; + +#ifdef _WIN32 +#include "windows.h" +// windows API available + +unsigned long CPlatformDepSystemCode::getMSCount() +{ + return ::GetTickCount(); +} + +int CPlatformDepSystemCode::fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin) +{ + return _fseeki64(_pStream, _iOffset, _iOrigin); +} + +astra::int64 CPlatformDepSystemCode::ftell64(FILE * _pStream) +{ + return _ftelli64(_pStream); +} + +#else +// linux, ... + +#include <sys/time.h> + +unsigned long CPlatformDepSystemCode::getMSCount() +{ + struct timeval tv; + gettimeofday(&tv, 0); + return (tv.tv_sec * 1000) + (tv.tv_usec/1000); +} + +int CPlatformDepSystemCode::fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin) +{ + return fseeko(_pStream, _iOffset, _iOrigin); +} + +astra::int64 CPlatformDepSystemCode::ftell64(FILE * _pStream) +{ + return ftello(_pStream); +} + + + +#endif diff --git a/src/ProjectionGeometry2D.cpp b/src/ProjectionGeometry2D.cpp new file mode 100644 index 0000000..982a1e4 --- /dev/null +++ b/src/ProjectionGeometry2D.cpp @@ -0,0 +1,203 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ProjectionGeometry2D.h" + +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CProjectionGeometry2D::CProjectionGeometry2D() : configCheckData(0) +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CProjectionGeometry2D::CProjectionGeometry2D(int _iAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) : configCheckData(0) +{ + _clear(); + _initialize(_iAngleCount, _iDetectorCount, _fDetectorWidth, _pfProjectionAngles,_pfExtraDetectorOffsets); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CProjectionGeometry2D::~CProjectionGeometry2D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +// Should only be used by constructors. Otherwise use the clear() function. +void CProjectionGeometry2D::_clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorCount = 0; + m_fDetectorWidth = 0.0f; + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffset = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CProjectionGeometry2D::clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorCount = 0; + m_fDetectorWidth = 0.0f; + if (m_bInitialized){ + delete[] m_pfProjectionAngles; + delete[] m_pfExtraDetectorOffset; + } + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffset = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check all variable values. +bool CProjectionGeometry2D::_check() +{ + ASTRA_CONFIG_CHECK(m_iDetectorCount > 0, "ProjectionGeometry2D", "Detector Count should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorWidth > 0.0f, "ProjectionGeometry2D", "Detector Width should be positive."); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry2D", "ProjectionAngleCount should be positive."); + ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry2D", "ProjectionAngles not initialized"); + + // autofix: angles in [0,2pi[ + for (int i = 0; i < m_iProjectionAngleCount; i++) { + while (2*PI <= m_pfProjectionAngles[i]) m_pfProjectionAngles[i] -= 2*PI; + while (m_pfProjectionAngles[i] < 0) m_pfProjectionAngles[i] += 2*PI; + } + + // success + return true; +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("ProjectionGeometry2D", this, _cfg); + + // uninitialize if the object was initialized before + if (m_bInitialized) { + clear(); + } + + // Required: DetectorWidth + XMLNode* node = _cfg.self->getSingleNode("DetectorWidth"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorWidth tag specified."); + m_fDetectorWidth = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorWidth"); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorCount"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorCount tag specified."); + m_iDetectorCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorCount"); + + // Required: ProjectionAngles + node = _cfg.self->getSingleNode("ProjectionAngles"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No ProjectionAngles tag specified."); + vector<float32> angles = node->getContentNumericalArray(); + delete node; + m_iProjectionAngleCount = angles.size(); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry2D", "Not enough ProjectionAngles specified."); + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = angles[i]; + } + CC.markNodeParsed("ProjectionAngles"); + + vector<float32> offset = _cfg.self->getOptionNumericalArray("ExtraDetectorOffset"); + m_pfExtraDetectorOffset = new float32[m_iProjectionAngleCount]; + if (offset.size() == (size_t)m_iProjectionAngleCount) { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffset[i] = offset[i]; + } + } else { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffset[i] = 0.0f; + } + } + CC.markOptionParsed("ExtraDetectorOffset"); + + // some checks + ASTRA_CONFIG_CHECK(m_iDetectorCount > 0, "ProjectionGeometry2D", "DetectorCount should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorWidth > 0.0f, "ProjectionGeometry2D", "DetectorWidth should be positive."); + ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry2D", "ProjectionAngles not initialized"); + + // Interface class, so don't return true + return false; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CProjectionGeometry2D::_initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) +{ + if (m_bInitialized) { + clear(); + } + + // copy parameters + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorCount = _iDetectorCount; + m_fDetectorWidth = _fDetectorWidth; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + m_pfExtraDetectorOffset = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = _pfProjectionAngles[i]; + m_pfExtraDetectorOffset[i] = _pfExtraDetectorOffsets ? _pfExtraDetectorOffsets[i]:0; + } + + // Interface class, so don't set m_bInitialized to true + return true; +} +//--------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ProjectionGeometry3D.cpp b/src/ProjectionGeometry3D.cpp new file mode 100644 index 0000000..b78b7b8 --- /dev/null +++ b/src/ProjectionGeometry3D.cpp @@ -0,0 +1,329 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ProjectionGeometry3D.h" + +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Check all variable values. +bool CProjectionGeometry3D::_check() +{ + ASTRA_CONFIG_CHECK(m_iDetectorRowCount > 0, "ProjectionGeometry3D", "DetectorRowCount should be positive."); + ASTRA_CONFIG_CHECK(m_iDetectorColCount > 0, "ProjectionGeometry3D", "DetectorColCount should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorSpacingX > 0.0f, "ProjectionGeometry3D", "m_fDetectorSpacingX should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorSpacingY > 0.0f, "ProjectionGeometry3D", "m_fDetectorSpacingY should be positive."); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry3D", "ProjectionAngleCount should be positive."); + ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry3D", "ProjectionAngles not initialized"); + +/* + // autofix: angles in [0,2pi[ + for (int i = 0; i < m_iProjectionAngleCount; i++) { + while (2*PI <= m_pfProjectionAngles[i]) m_pfProjectionAngles[i] -= 2*PI; + while (m_pfProjectionAngles[i] < 0) m_pfProjectionAngles[i] += 2*PI; + } +*/ + + // succes + return true; +} + +//---------------------------------------------------------------------------------------- +// Default constructor. +CProjectionGeometry3D::CProjectionGeometry3D() : configCheckData(0) +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CProjectionGeometry3D::CProjectionGeometry3D(int _iAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorSpacingX, + float32 _fDetectorSpacingY, + const float32 *_pfProjectionAngles, + const float32 *_pfExtraDetectorOffsetsX, + const float32 *_pfExtraDetectorOffsetsY) : configCheckData(0) +{ + _clear(); + _initialize(_iAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorSpacingX, + _fDetectorSpacingY, + _pfProjectionAngles, + _pfExtraDetectorOffsetsX, + _pfExtraDetectorOffsetsY); +} + +//---------------------------------------------------------------------------------------- +// Copy constructor. +CProjectionGeometry3D::CProjectionGeometry3D(const CProjectionGeometry3D& _projGeom) +{ + _clear(); + _initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorRowCount, + _projGeom.m_iDetectorColCount, + _projGeom.m_fDetectorSpacingX, + _projGeom.m_fDetectorSpacingY, + _projGeom.m_pfProjectionAngles, + _projGeom.m_pfExtraDetectorOffsetsX, + _projGeom.m_pfExtraDetectorOffsetsY); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CProjectionGeometry3D::~CProjectionGeometry3D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +// Should only be used by constructors. Otherwise use the clear() function. +void CProjectionGeometry3D::_clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorRowCount = 0; + m_iDetectorColCount = 0; + m_fDetectorSpacingX = 0.0f; + m_fDetectorSpacingY = 0.0f; + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffsetsX = NULL; + m_pfExtraDetectorOffsetsY = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CProjectionGeometry3D::clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorRowCount = 0; + m_iDetectorColCount = 0; + m_fDetectorSpacingX = 0.0f; + m_fDetectorSpacingY = 0.0f; + if (m_pfProjectionAngles != NULL) { + delete [] m_pfProjectionAngles; + } + if (m_pfExtraDetectorOffsetsX != NULL) { + delete [] m_pfExtraDetectorOffsetsX; + } + if (m_pfExtraDetectorOffsetsY != NULL) { + delete [] m_pfExtraDetectorOffsetsY; + } + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffsetsX = NULL; + m_pfExtraDetectorOffsetsY = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Initialization witha Config object +bool CProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ProjectionGeometry3D", this, _cfg); + + if (m_bInitialized) { + clear(); + } + + ASTRA_ASSERT(_cfg.self); + + // Required: DetectorWidth + XMLNode* node = _cfg.self->getSingleNode("DetectorSpacingX"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingX tag specified."); + m_fDetectorSpacingX = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorSpacingX"); + + // Required: DetectorHeight + node = _cfg.self->getSingleNode("DetectorSpacingY"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingY tag specified."); + m_fDetectorSpacingY = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorSpacingY"); + + // Required: DetectorRowCount + node = _cfg.self->getSingleNode("DetectorRowCount"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorRowCount"); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorColCount"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorColCount tag specified."); + m_iDetectorColCount = boost::lexical_cast<int>(node->getContent()); + m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount; + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorColCount"); + + // Required: ProjectionAngles + node = _cfg.self->getSingleNode("ProjectionAngles"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No ProjectionAngles tag specified."); + vector<float32> angles = node->getContentNumericalArray(); + m_iProjectionAngleCount = angles.size(); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry3D", "Not enough ProjectionAngles specified."); + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = angles[i]; + } + CC.markNodeParsed("ProjectionAngles"); + ASTRA_DELETE(node); + + // Optional: ExtraDetectorOffsetX + node = _cfg.self->getSingleNode("ExtraDetectorOffsetsX"); + m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount]; + if (node) { + vector<float32> translationsX = node->getContentNumericalArray(); + if (translationsX.size() < m_iProjectionAngleCount){ + cout << "Not enough ExtraDetectorOffsetsX components specified. " << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsX[i] = 0; + } + } + else { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsX[i] = translationsX[i]; + } + } + } + else { + //cout << "No ExtraDetectorOffsetsX tag specified." << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsX[i] = 0; + } + } + CC.markOptionParsed("ExtraDetectorOffsetsX"); + ASTRA_DELETE(node); + + // Optional: ExtraDetectorOffsetsY + node = _cfg.self->getSingleNode("ExtraDetectorOffsetsY"); + m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount]; + if (node) { + vector<float32> translationsX = node->getContentNumericalArray(); + if (translationsX.size() < m_iProjectionAngleCount){ + cout << "Not enough ExtraDetectorOffsetsY components specified. " << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsY[i] = 0; + } + } + else { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsY[i] = translationsX[i]; + } + } + } + else { + //cout << "No ExtraDetectorOffsetsY tag specified." << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsY[i] = 0; + } + } + CC.markOptionParsed("ExtraDetectorOffsetsY"); + ASTRA_DELETE(node); + + // Interface class, so don't return true + return false; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CProjectionGeometry3D::_initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorSpacingX, + float32 _fDetectorSpacingY, + const float32 *_pfProjectionAngles, + const float32 *_pfExtraDetectorOffsetsX, + const float32 *_pfExtraDetectorOffsetsY) +{ + if (m_bInitialized) { + clear(); + } + + // copy parameters + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorRowCount = _iDetectorRowCount; + m_iDetectorColCount = _iDetectorColCount; + m_iDetectorTotCount = _iDetectorRowCount * _iDetectorColCount; + m_fDetectorSpacingX = _fDetectorSpacingX; + m_fDetectorSpacingY = _fDetectorSpacingY; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount]; + m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = _pfProjectionAngles[i]; + m_pfExtraDetectorOffsetsX[i] = _pfExtraDetectorOffsetsX ? _pfExtraDetectorOffsetsX[i]:0; + m_pfExtraDetectorOffsetsY[i] = _pfExtraDetectorOffsetsY ? _pfExtraDetectorOffsetsY[i]:0; + //m_pfExtraDetectorOffsetsX[i] = 0; + //m_pfExtraDetectorOffsetsY[i] = 0; + } + + m_iDetectorTotCount = m_iProjectionAngleCount * m_iDetectorRowCount * m_iDetectorColCount; + + // Interface class, so don't return true + return false; +} + +//--------------------------------------------------------------------------------------- +// +AstraError CProjectionGeometry3D::setExtraDetectorOffsetsX(float32* _pfExtraDetectorOffsetsX) +{ + if (!m_bInitialized) + return ASTRA_ERROR_NOT_INITIALIZED; + + for (int iAngle = 0; iAngle<m_iProjectionAngleCount; iAngle++) + m_pfExtraDetectorOffsetsX[iAngle] = _pfExtraDetectorOffsetsX[iAngle]; + + return ASTRA_SUCCESS; +} + +//--------------------------------------------------------------------------------------- +// +AstraError CProjectionGeometry3D::setExtraDetectorOffsetsY(float32* _pfExtraDetectorOffsetsY) +{ + if (!m_bInitialized) + return ASTRA_ERROR_NOT_INITIALIZED; + + for (int iAngle = 0; iAngle<m_iProjectionAngleCount; iAngle++) + m_pfExtraDetectorOffsetsY[iAngle] = _pfExtraDetectorOffsetsY[iAngle]; + + return ASTRA_SUCCESS; +} +} // namespace astra diff --git a/src/Projector2D.cpp b/src/Projector2D.cpp new file mode 100644 index 0000000..e67cd0c --- /dev/null +++ b/src/Projector2D.cpp @@ -0,0 +1,217 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Projector2D.h" + +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/SparseMatrixProjectionGeometry2D.h" +#include "astra/SparseMatrix.h" + + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// constructor +CProjector2D::CProjector2D() : configCheckData(0) +{ + + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// constructor +CProjector2D::CProjector2D(CProjectionGeometry2D* _pProjectionGeometry, CVolumeGeometry2D* _pVolumeGeometry) : configCheckData(0) +{ + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + m_bIsInitialized = true; +} + +//---------------------------------------------------------------------------------------- +// destructor +CProjector2D::~CProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CProjector2D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CProjector2D::clear() +{ + if (m_pProjectionGeometry) { + delete m_pProjectionGeometry; + m_pProjectionGeometry = NULL; + } + if (m_pVolumeGeometry) { + delete m_pVolumeGeometry; + m_pVolumeGeometry = NULL; + } + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CProjector2D::_check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "Projector2D", "Invalid Projection Geometry Object."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "Projector2D", "Invalid Volume Geometry Object."); + + // check initializations + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector2D", "Projection Geometry Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector2D", "Volume Geometry Object Not Initialized."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjector2D> CC("Projector2D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required: ProjectionGeometry + XMLNode* node = _cfg.self->getSingleNode("ProjectionGeometry"); + ASTRA_CONFIG_CHECK(node, "Projector2D", "No ProjectionGeometry tag specified."); + + // FIXME: Change how the base class is created. (This is duplicated + // in astra_mex_data2d.cpp.) + std::string type = node->getAttribute("type"); + if (type == "sparse_matrix") { + m_pProjectionGeometry = new CSparseMatrixProjectionGeometry2D(); + m_pProjectionGeometry->initialize(Config(node)); + } else if (type == "fanflat") { + CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D(); + pFanFlatProjectionGeometry->initialize(Config(node)); + m_pProjectionGeometry = pFanFlatProjectionGeometry; + } else if (type == "fanflat_vec") { + CFanFlatVecProjectionGeometry2D* pFanFlatVecProjectionGeometry = new CFanFlatVecProjectionGeometry2D(); + pFanFlatVecProjectionGeometry->initialize(Config(node)); + m_pProjectionGeometry = pFanFlatVecProjectionGeometry; + } else { + m_pProjectionGeometry = new CParallelProjectionGeometry2D(); + m_pProjectionGeometry->initialize(Config(node)); + } + // "node" is deleted by the temp Config(node) objects + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector2D", "ProjectionGeometry not initialized."); + CC.markNodeParsed("ProjectionGeometry"); + + + // required: VolumeGeometry + node = _cfg.self->getSingleNode("VolumeGeometry"); + ASTRA_CONFIG_CHECK(node, "Projector2D", "No VolumeGeometry tag specified."); + m_pVolumeGeometry = new CVolumeGeometry2D(); + m_pVolumeGeometry->initialize(Config(node)); + // "node" is deleted by the temp Config(node) object + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector2D", "VolumeGeometry not initialized."); + CC.markNodeParsed("VolumeGeometry"); + + return true; +} + +//---------------------------------------------------------------------------------------- +// weights of each detector in a projection angle +void CProjector2D::computeProjectionRayWeights(int _iProjection, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount) +{ + int iPixelBufferSize = getProjectionWeightsCount(_iProjection); + + int iDetector; + for(iDetector = m_pProjectionGeometry->getDetectorCount()-1; iDetector >= 0; --iDetector) { + computeSingleRayWeights(_iProjection, // projector index + iDetector, // detector index + &_pfWeightedPixels[iDetector*iPixelBufferSize], // pixel buffer + iPixelBufferSize, // pixel buffer size + _piRayStoredPixelCount[iDetector]); // stored pixel count + } + +} + +//---------------------------------------------------------------------------------------- +// explicit projection matrix +CSparseMatrix* CProjector2D::getMatrix() +{ + unsigned int iProjectionCount = m_pProjectionGeometry->getProjectionAngleCount(); + unsigned int iDetectorCount = m_pProjectionGeometry->getDetectorCount(); + unsigned int iRayCount = iProjectionCount * iDetectorCount; + unsigned int iVolumeSize = m_pVolumeGeometry->getGridTotCount(); + unsigned long lSize = 0; + unsigned int iMaxRayLength = 0; + for (unsigned int i = 0; i < iProjectionCount; ++i) { + unsigned int iRayLength = getProjectionWeightsCount(i); + lSize += iDetectorCount * iRayLength; + if (iRayLength > iMaxRayLength) + iMaxRayLength = iRayLength; + } + CSparseMatrix* pMatrix = new CSparseMatrix(iRayCount, iVolumeSize, lSize); + + if (!pMatrix || !pMatrix->isInitialized()) { + delete pMatrix; + return 0; + } + + SPixelWeight* pEntries = new SPixelWeight[iMaxRayLength]; + unsigned long lMatrixIndex = 0; + for (unsigned int iRay = 0; iRay < iRayCount; ++iRay) { + pMatrix->m_plRowStarts[iRay] = lMatrixIndex; + int iPixelCount; + int iProjIndex, iDetIndex; + m_pProjectionGeometry->indexToAngleDetectorIndex(iRay, iProjIndex, iDetIndex); + computeSingleRayWeights(iProjIndex, iDetIndex, pEntries, iMaxRayLength, iPixelCount); + + for (int i = 0; i < iPixelCount; ++i) { + pMatrix->m_piColIndices[lMatrixIndex] = pEntries[i].m_iIndex; + pMatrix->m_pfValues[lMatrixIndex] = pEntries[i].m_fWeight; + ++lMatrixIndex; + } + + } + pMatrix->m_plRowStarts[iRayCount] = lMatrixIndex; + + delete[] pEntries; + return pMatrix; +} + +} // end namespace diff --git a/src/Projector3D.cpp b/src/Projector3D.cpp new file mode 100644 index 0000000..f8fddf4 --- /dev/null +++ b/src/Projector3D.cpp @@ -0,0 +1,121 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Projector3D.h" + + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CProjector3D::CProjector3D() : configCheckData(0) +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CProjector3D::~CProjector3D() +{ + if (m_bIsInitialized) clear(); +} + +//---------------------------------------------------------------------------------------- +// Clear for constructors +void CProjector3D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Clear +void CProjector3D::clear() +{ + ASTRA_DELETE(m_pProjectionGeometry); + ASTRA_DELETE(m_pVolumeGeometry); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CProjector3D::_check() +{ + // projection geometry + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "Projector3D", "ProjectionGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector3D", "ProjectionGeometry3D not initialized."); + + // volume geometry + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "Projector3D", "VolumeGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector3D", "VolumeGeometry3D not initialized."); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CProjector3D::initialize(const Config& _cfg) +{ + assert(_cfg.self); + + return true; +} + +/* +bool CProjector3D::initialize(astra::CProjectionGeometry3D *, astra::CVolumeGeometry3D *) +{ + ASTRA_ASSERT(false); + + return false; +} +*/ + +//---------------------------------------------------------------------------------------- +// Weights of each detector in a projection angle +void CProjector3D::computeProjectionRayWeights(int _iProjection, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount) +{ + int iPixelBufferSize = getProjectionWeightsCount(_iProjection); + + int iDetector = 0; + for(iDetector = m_pProjectionGeometry->getDetectorTotCount()-1; iDetector >= 0; --iDetector) { + int iSliceIndex = iDetector / m_pProjectionGeometry->getDetectorColCount(); + int iDetectorColIndex = iDetector % m_pProjectionGeometry->getDetectorColCount(); + + computeSingleRayWeights(_iProjection, // projector index + iSliceIndex, // slice index + iDetectorColIndex, // detector index + &_pfWeightedPixels[iDetector*iPixelBufferSize], // pixel buffer + iPixelBufferSize, // pixel buffer size + _piRayStoredPixelCount[iDetector]); // stored pixel count + } +} +//---------------------------------------------------------------------------------------- + +} // end namespace diff --git a/src/ReconstructionAlgorithm2D.cpp b/src/ReconstructionAlgorithm2D.cpp new file mode 100644 index 0000000..ea693e3 --- /dev/null +++ b/src/ReconstructionAlgorithm2D.cpp @@ -0,0 +1,275 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ReconstructionAlgorithm2D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CReconstructionAlgorithm2D::CReconstructionAlgorithm2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CReconstructionAlgorithm2D::~CReconstructionAlgorithm2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CReconstructionAlgorithm2D::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CReconstructionAlgorithm2D::clear() +{ + // Nothing to delete, so just _clear() + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CReconstructionAlgorithm2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithm2D", this, _cfg); + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectorId"); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // fixed mask + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + + // fixed mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("SinogramMaskId"); + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // return success + return _check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // return success + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Set Constraints +void CReconstructionAlgorithm2D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue) +{ + m_bUseMinConstraint = _bUseMin; + m_fMinValue = _fMinValue; + m_bUseMaxConstraint = _bUseMax; + m_fMaxValue = _fMaxValue; +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CReconstructionAlgorithm2D::setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches volume + m_bUseReconstructionMask = _bEnable; + m_pReconstructionMask = _pMask; + if (m_pReconstructionMask == NULL) { + m_bUseReconstructionMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Sinogram Mask +void CReconstructionAlgorithm2D::setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches sinogram + m_bUseSinogramMask = _bEnable; + m_pSinogramMask = _pMask; + if (m_pSinogramMask == NULL) { + m_bUseSinogramMask = false; + } +}//---------------------------------------------------------------------------------------- +// Check +bool CReconstructionAlgorithm2D::_check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction2D", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction2D", "Invalid Reconstruction Data Object."); + + // check initializations + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction2D", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction2D", "Reconstruction Data Object Not Initialized."); + + // check compatibility between projector and data classes + ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CReconstructionAlgorithm2D::getInformation() +{ + map<string, boost::any> res; + res["ProjectorId"] = getInformation("ProjectorId"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CReconstructionAlgorithm2D::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ReconstructionAlgorithm3D.cpp b/src/ReconstructionAlgorithm3D.cpp new file mode 100644 index 0000000..4d9bbc6 --- /dev/null +++ b/src/ReconstructionAlgorithm3D.cpp @@ -0,0 +1,306 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ReconstructionAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CReconstructionAlgorithm3D::CReconstructionAlgorithm3D() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CReconstructionAlgorithm3D::~CReconstructionAlgorithm3D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CReconstructionAlgorithm3D::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CReconstructionAlgorithm3D::clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CReconstructionAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithm3D", this, _cfg); + + XMLNode* node; + int id; +#if 0 + // projector + node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectorId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector3DManager::getSingleton().get(id); + ASTRA_DELETE(node); +#endif + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // fixed mask + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + + // fixed mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id)); + } + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // return success + return _check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CReconstructionAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3D* _pSinogram, + CFloat32VolumeData3D* _pReconstruction) +{ + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // return success + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Set Constraints +void CReconstructionAlgorithm3D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue) +{ + m_bUseMinConstraint = _bUseMin; + m_fMinValue = _fMinValue; + m_bUseMaxConstraint = _bUseMax; + m_fMaxValue = _fMaxValue; +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CReconstructionAlgorithm3D::setReconstructionMask(CFloat32VolumeData3D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches volume + m_bUseReconstructionMask = _bEnable; + m_pReconstructionMask = _pMask; + if (m_pReconstructionMask == NULL) { + m_bUseReconstructionMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Sinogram Mask +void CReconstructionAlgorithm3D::setSinogramMask(CFloat32ProjectionData3D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches sinogram + m_bUseSinogramMask = _bEnable; + m_pSinogramMask = _pMask; + if (m_pSinogramMask == NULL) { + m_bUseSinogramMask = false; + } +}//---------------------------------------------------------------------------------------- +// Check +bool CReconstructionAlgorithm3D::_check() +{ + // check pointers +#if 0 + ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction3D", "Invalid Projector Object."); +#endif + ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction3D", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction3D", "Invalid Reconstruction Data Object."); + + // check initializations +#if 0 + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction3D", "Projector Object Not Initialized."); +#endif + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction3D", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction3D", "Reconstruction Data Object Not Initialized."); + +#if 0 + // check compatibility between projector and data classes + ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction3D", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction3D", "Reconstruction Data not compatible with the specified Projector."); +#endif + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CReconstructionAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + res["ProjectorId"] = getInformation("ProjectorId"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CReconstructionAlgorithm3D::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } +#if 0 + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector3DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } +#endif + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData3DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ReconstructionAlgorithmMultiSlice2D.cpp b/src/ReconstructionAlgorithmMultiSlice2D.cpp new file mode 100644 index 0000000..648db61 --- /dev/null +++ b/src/ReconstructionAlgorithmMultiSlice2D.cpp @@ -0,0 +1,288 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ReconstructionAlgorithmMultiSlice2D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CReconstructionAlgorithmMultiSlice2D::CReconstructionAlgorithmMultiSlice2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CReconstructionAlgorithmMultiSlice2D::~CReconstructionAlgorithmMultiSlice2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CReconstructionAlgorithmMultiSlice2D::_clear() +{ + m_pProjector = NULL; + m_iSliceCount = 0; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CReconstructionAlgorithmMultiSlice2D::clear() +{ + m_pProjector = NULL; + m_vpSinogram.clear(); + m_vpReconstruction.clear(); + m_iSliceCount = 0; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CReconstructionAlgorithmMultiSlice2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithmMultiSlice2D", this, _cfg); + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectorId"); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified."); + vector<float32> tmpvector = node->getContentNumericalArray(); + for (unsigned int i = 0; i < tmpvector.size(); ++i) { + m_vpSinogram.push_back(dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(int(tmpvector[i])))); + } + m_iSliceCount = tmpvector.size(); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified."); + tmpvector = node->getContentNumericalArray(); + for (unsigned int i = 0; i < tmpvector.size(); ++i) { + m_vpReconstruction.push_back(dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(int(tmpvector[i])))); + } + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // reconstruction masks + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + + // sinogram masks + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("SinogramMaskId"); + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // return success + return _check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CReconstructionAlgorithmMultiSlice2D::initialize(CProjector2D* _pProjector, + vector<CFloat32ProjectionData2D*> _vpSinogram, + vector<CFloat32VolumeData2D*> _vpReconstruction) +{ + m_pProjector = _pProjector; + m_vpSinogram = _vpSinogram; + m_vpReconstruction = _vpReconstruction; + m_iSliceCount = _vpSinogram.size(); + + // return success + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Set Constraints +void CReconstructionAlgorithmMultiSlice2D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue) +{ + m_bUseMinConstraint = _bUseMin; + m_fMinValue = _fMinValue; + m_bUseMaxConstraint = _bUseMax; + m_fMaxValue = _fMaxValue; +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CReconstructionAlgorithmMultiSlice2D::setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable) +{ + m_bUseReconstructionMask = _bEnable; + m_pReconstructionMask = _pMask; + if (m_pReconstructionMask == NULL) { + m_bUseReconstructionMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Check +bool CReconstructionAlgorithmMultiSlice2D::_check() +{ + // check projector + ASTRA_CONFIG_CHECK(m_pProjector, "ReconstructionMultiSlice2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ReconstructionMultiSlice2D", "Projector Object Not Initialized."); + + // check list + ASTRA_CONFIG_CHECK(m_vpSinogram.size() == (unsigned int)m_iSliceCount, "ReconstructionMultiSlice2D", "Sinogram slicecount mismatch."); + ASTRA_CONFIG_CHECK(m_vpReconstruction.size() == (unsigned int)m_iSliceCount, "ReconstructionMultiSlice2D", "Volume slicecount mismatch."); + + for (int i = 0; i < m_iSliceCount; ++i) { + // pointers + ASTRA_CONFIG_CHECK(m_vpSinogram[i], "ReconstructionMultiSlice2D", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_vpReconstruction[i], "ReconstructionMultiSlice2D", "Invalid Volume Data Object."); + + // initialized + ASTRA_CONFIG_CHECK(m_vpSinogram[i]->isInitialized(), "ReconstructionMultiSlice2D", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_vpReconstruction[i]->isInitialized(), "ReconstructionMultiSlice2D", "Volume Data Object Not Initialized."); + + // geometry compatibility + ASTRA_CONFIG_CHECK(m_vpSinogram[i]->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_vpReconstruction[i]->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector."); + } + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CReconstructionAlgorithmMultiSlice2D::getInformation() +{ + map<string, boost::any> res; + res["ProjectorId"] = getInformation("ProjectorId"); +// res["ProjectionDataId"] = getInformation("ProjectionDataId"); +// res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CReconstructionAlgorithmMultiSlice2D::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } +// if (_sIdentifier == "ProjectionDataId") { +// int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); +// if (iIndex != 0) return iIndex; +// return std::string("not in manager"); +// } +// if (_sIdentifier == "ReconstructionDataId") { +// int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); +// if (iIndex != 0) return iIndex; +// return std::string("not in manager"); +// } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/SartAlgorithm.cpp b/src/SartAlgorithm.cpp new file mode 100644 index 0000000..d898297 --- /dev/null +++ b/src/SartAlgorithm.cpp @@ -0,0 +1,452 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SartAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CSartAlgorithm::type = "SART"; + + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CSartAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_piProjectionOrder = NULL; + m_iProjectionCount = 0; + m_iCurrentProjection = 0; + m_bIsInitialized = false; + m_iIterationCount = 0; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CSartAlgorithm::clear() +{ + CReconstructionAlgorithm2D::clear(); + if (m_piProjectionOrder) { + delete[] m_piProjectionOrder; + m_piProjectionOrder = NULL; + } + m_iProjectionCount = 0; + m_iCurrentProjection = 0; + m_bIsInitialized = false; + m_iIterationCount = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor +CSartAlgorithm::CSartAlgorithm() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor +CSartAlgorithm::CSartAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Constructor +CSartAlgorithm::CSartAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int* _piProjectionOrder, + int _iProjectionCount) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction, _piProjectionOrder, _iProjectionCount); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CSartAlgorithm::~CSartAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CSartAlgorithm::initialize(const Config& _cfg) +{ + assert(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("SartAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // projection order + m_iCurrentProjection = 0; + m_iProjectionCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); + string projOrder = _cfg.self->getOption("ProjectionOrder", "sequential"); + CC.markOptionParsed("ProjectionOrder"); + if (projOrder == "sequential") { + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = i; + } + } else if (projOrder == "random") { + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = i; + } + for (int i = 0; i < m_iProjectionCount-1; i++) { + int k = (rand() % (m_iProjectionCount - i)); + int t = m_piProjectionOrder[i]; + m_piProjectionOrder[i] = m_piProjectionOrder[i + k]; + m_piProjectionOrder[i + k] = t; + } + } else if (projOrder == "custom") { + vector<float32> projOrderList = _cfg.self->getOptionNumericalArray("ProjectionOrderList"); + m_piProjectionOrder = new int[projOrderList.size()]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = static_cast<int>(projOrderList[i]); + } + CC.markOptionParsed("ProjectionOrderList"); + } + + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CSartAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // ray order + m_iCurrentProjection = 0; + m_iProjectionCount = _pProjector->getProjectionGeometry()->getProjectionAngleCount(); + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = i; + } + + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CSartAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int* _piProjectionOrder, + int _iProjectionCount) +{ + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // ray order + m_iCurrentProjection = 0; + m_iProjectionCount = _iProjectionCount; + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = _piProjectionOrder[i]; + } + + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +bool CSartAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "SART", "Error in ReconstructionAlgorithm2D initialization"); + + // check projection order all within range + for (int i = 0; i < m_iProjectionCount; ++i) { + ASTRA_CONFIG_CHECK(0 <= m_piProjectionOrder[i] && m_piProjectionOrder[i] < m_pProjector->getProjectionGeometry()->getProjectionAngleCount(), "SART", "Projection Order out of range."); + } + + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CSartAlgorithm::getInformation() +{ + map<string, boost::any> res; + res["ProjectionOrder"] = getInformation("ProjectionOrder"); + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CSartAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectionOrder") { + vector<float32> res; + for (int i = 0; i < m_iProjectionCount; i++) { + res.push_back(m_piProjectionOrder[i]); + } + return res; + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CSartAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_bShouldAbort = false; + + int iIteration = 0; + + // data projectors + CDataProjectorInterface* pForwardProjector; + CDataProjectorInterface* pBackProjector; + + m_pTotalRayLength->setData(0.0f); + m_pTotalPixelWeight->setData(0.0f); + + // backprojection data projector + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength), // SIRT backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // first time forward projection data projector, + // also computes total pixel weight and total ray length + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + Combine3Policy<DiffFPPolicy, TotalPixelWeightPolicy, TotalRayLengthPolicy>( // 3 basic operations + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + TotalPixelWeightPolicy(m_pTotalPixelWeight), // calculate the total pixel weights + TotalRayLengthPolicy(m_pTotalRayLength)), // calculate the total ray lengths + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + + + // iteration loop + for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + + int iProjection = m_piProjectionOrder[m_iIterationCount % m_iProjectionCount]; + + // forward projection and difference calculation + m_pTotalPixelWeight->setData(0.0f); + pForwardProjector->projectSingleProjection(iProjection); + // backprojection + pBackProjector->projectSingleProjection(iProjection); + // update iteration count + m_iIterationCount++; + + if (m_bUseMinConstraint) + m_pReconstruction->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + m_pReconstruction->clampMax(m_fMaxValue); + } + + + ASTRA_DELETE(pForwardProjector); + ASTRA_DELETE(pBackProjector); + + + + + + + + + + + + + + + //// check initialized + // ASTRA_ASSERT(m_bIsInitialized); + + //// variables + //int iIteration, iDetector; + //int baseIndex, iPixel; + //float32* pfGamma = new float32[m_pReconstruction->getSize()]; + //float32* pfBeta = new float32[m_pProjector->getProjectionGeometry()->getDetectorCount()]; + //float32* pfProjectionDiff = new float32[m_pProjector->getProjectionGeometry()->getDetectorCount()]; + + //// ITERATE + //for (iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) { + // + // // reset gamma + // memset(pfGamma, 0, sizeof(float32) * m_pReconstruction->getSize()); + // memset(pfBeta, 0, sizeof(float32) * m_pProjector->getProjectionGeometry()->getDetectorCount()); + // + // // get current projection angle + // int iProjection = m_piProjectionOrder[m_iCurrentProjection]; + // m_iCurrentProjection = (m_iCurrentProjection + 1) % m_iProjectionCount; + // int iProjectionWeightCount = m_pProjector->getProjectionWeightsCount(iProjection); + // + // // allocate memory for the pixel buffer + // SPixelWeight* pPixels = new SPixelWeight[m_pProjector->getProjectionWeightsCount(iProjection) * m_pProjector->getProjectionGeometry()->getDetectorCount()]; + // int* piRayStoredPixelCount = new int[m_pProjector->getProjectionGeometry()->getDetectorCount()]; + + // // compute weights for this projection + // m_pProjector->computeProjectionRayWeights(iProjection, pPixels, piRayStoredPixelCount); + // + // // calculate projection difference in each detector + // for (iDetector = m_pProjector->getProjectionGeometry()->getDetectorCount()-1; iDetector >= 0; --iDetector) { + + // if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue; + + // // index base of the pixel in question + // baseIndex = iDetector * iProjectionWeightCount; + // + // // set the initial projection difference to the sinogram value + // pfProjectionDiff[iDetector] = m_pSinogram->getData2DConst()[iProjection][iDetector]; + // + // // update projection difference, beta and gamma + // for (iPixel = piRayStoredPixelCount[iDetector]-1; iPixel >= 0; --iPixel) { + + // // pixel must be loose + // if (m_bUseReconstructionMask && m_pReconstructionMask->getData()[pPixels[baseIndex+iPixel].m_iIndex] == 0) continue; + + // // subtract projection value from projection difference + // pfProjectionDiff[iDetector] -= + // pPixels[baseIndex+iPixel].m_fWeight * m_pReconstruction->getDataConst()[pPixels[baseIndex+iPixel].m_iIndex]; + // + // // update beta and gamma if this pixel lies inside a loose part + // pfBeta[iDetector] += pPixels[baseIndex+iPixel].m_fWeight; + // pfGamma[pPixels[baseIndex+iPixel].m_iIndex] += pPixels[baseIndex+iPixel].m_fWeight; + // } + // + // } + // + // // back projection + // for (iDetector = m_pProjector->getProjectionGeometry()->getDetectorCount()-1; iDetector >= 0; --iDetector) { + // + // if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue; + + // // index base of the pixel in question + // baseIndex = iDetector * iProjectionWeightCount; + + // // update pixel values + // for (iPixel = piRayStoredPixelCount[iDetector]-1; iPixel >= 0; --iPixel) { + + // + // // pixel must be loose + // if (m_bUseReconstructionMask && m_pReconstructionMask->getData()[pPixels[baseIndex+iPixel].m_iIndex] == 0) continue; + + // + + // // update reconstruction volume + // float32 fGammaBeta = pfGamma[pPixels[baseIndex+iPixel].m_iIndex] * pfBeta[iDetector]; + // if ((fGammaBeta > 0.01f) || (fGammaBeta < -0.01f)) { + // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] += + // pPixels[baseIndex+iPixel].m_fWeight * pfProjectionDiff[iDetector] / fGammaBeta; + // } + + // // constraints + // if (m_bUseMinConstraint && m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] < m_fMinValue) { + // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] = m_fMinValue; + // } + // if (m_bUseMaxConstraint && m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] > m_fMaxValue) { + // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] = m_fMaxValue; + // } + // } + // } + // + // // garbage disposal + // delete[] pPixels; + // delete[] piRayStoredPixelCount; + //} + + //// garbage disposal + //delete[] pfGamma; + //delete[] pfBeta; + //delete[] pfProjectionDiff; + + //// update statistics + //m_pReconstruction->updateStatistics(); +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/SirtAlgorithm.cpp b/src/SirtAlgorithm.cpp new file mode 100644 index 0000000..60cee8a --- /dev/null +++ b/src/SirtAlgorithm.cpp @@ -0,0 +1,321 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SirtAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CSirtAlgorithm::type = "SIRT"; + +//---------------------------------------------------------------------------------------- +// Constructor +CSirtAlgorithm::CSirtAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CSirtAlgorithm::CSirtAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CSirtAlgorithm::~CSirtAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CSirtAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; + + m_pTotalRayLength = NULL; + m_pTotalPixelWeight = NULL; + m_pDiffSinogram = NULL; + m_pTmpVolume = NULL; + + m_iIterationCount = 0; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CSirtAlgorithm::clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; + + ASTRA_DELETE(m_pTotalRayLength); + ASTRA_DELETE(m_pTotalPixelWeight); + ASTRA_DELETE(m_pDiffSinogram); + ASTRA_DELETE(m_pTmpVolume); + + m_iIterationCount = 0; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CSirtAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "SIRT", "Error in ReconstructionAlgorithm2D initialization"); + + ASTRA_CONFIG_CHECK(m_pTotalRayLength, "SIRT", "Invalid TotalRayLength Object"); + ASTRA_CONFIG_CHECK(m_pTotalRayLength->isInitialized(), "SIRT", "Invalid TotalRayLength Object"); + ASTRA_CONFIG_CHECK(m_pTotalPixelWeight, "SIRT", "Invalid TotalPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pTotalPixelWeight->isInitialized(), "SIRT", "Invalid TotalPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pDiffSinogram, "SIRT", "Invalid DiffSinogram Object"); + ASTRA_CONFIG_CHECK(m_pDiffSinogram->isInitialized(), "SIRT", "Invalid DiffSinogram Object"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CSirtAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("SirtAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CSirtAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CSirtAlgorithm::_init() +{ + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTmpVolume = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CSirtAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CSirtAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CSirtAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_bShouldAbort = false; + + int iIteration = 0; + + // data projectors + CDataProjectorInterface* pForwardProjector; + CDataProjectorInterface* pBackProjector; + CDataProjectorInterface* pFirstForwardProjector; + + m_pTotalRayLength->setData(0.0f); + m_pTotalPixelWeight->setData(0.0f); + + // forward projection data projector + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // backprojection data projector + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultBPPolicy(m_pTmpVolume, m_pDiffSinogram), // backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // first time forward projection data projector, + // also computes total pixel weight and total ray length + pFirstForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + Combine3Policy<DiffFPPolicy, TotalPixelWeightPolicy, TotalRayLengthPolicy>( // 3 basic operations + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + TotalPixelWeightPolicy(m_pTotalPixelWeight), // calculate the total pixel weights + TotalRayLengthPolicy(m_pTotalRayLength)), // calculate the total ray lengths + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + + + // forward projection, difference calculation and raylength/pixelweight computation + pFirstForwardProjector->project(); + + float32* pfT = m_pTotalPixelWeight->getData(); + for (int i = 0; i < m_pTotalPixelWeight->getSize(); ++i) { + float32 x = pfT[i]; + if (x < -eps || x > eps) + x = 1.0f / x; + else + x = 0.0f; + pfT[i] = x; + } + pfT = m_pTotalRayLength->getData(); + for (int i = 0; i < m_pTotalRayLength->getSize(); ++i) { + float32 x = pfT[i]; + if (x < -eps || x > eps) + x = 1.0f / x; + else + x = 0.0f; + pfT[i] = x; + } + + // divide by line weights + (*m_pDiffSinogram) *= (*m_pTotalRayLength); + + // backprojection + m_pTmpVolume->setData(0.0f); + pBackProjector->project(); + + // divide by pixel weights + (*m_pTmpVolume) *= (*m_pTotalPixelWeight); + (*m_pReconstruction) += (*m_pTmpVolume); + + if (m_bUseMinConstraint) + m_pReconstruction->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + m_pReconstruction->clampMax(m_fMaxValue); + + // update iteration count + m_iIterationCount++; + iIteration++; + + + + + // iteration loop + for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + // forward projection and difference calculation + pForwardProjector->project(); + + // divide by line weights + (*m_pDiffSinogram) *= (*m_pTotalRayLength); + + + // backprojection + m_pTmpVolume->setData(0.0f); + pBackProjector->project(); + + // divide by pixel weights + (*m_pTmpVolume) *= (*m_pTotalPixelWeight); + (*m_pReconstruction) += (*m_pTmpVolume); + + if (m_bUseMinConstraint) + m_pReconstruction->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + m_pReconstruction->clampMax(m_fMaxValue); + + // update iteration count + m_iIterationCount++; + } + + + ASTRA_DELETE(pForwardProjector); + ASTRA_DELETE(pBackProjector); + ASTRA_DELETE(pFirstForwardProjector); +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/SparseMatrix.cpp b/src/SparseMatrix.cpp new file mode 100644 index 0000000..e6d115f --- /dev/null +++ b/src/SparseMatrix.cpp @@ -0,0 +1,91 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <sstream> + +#include "astra/Globals.h" +#include "astra/SparseMatrix.h" + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// constructor + +CSparseMatrix::CSparseMatrix() +{ + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// constructor +CSparseMatrix::CSparseMatrix(unsigned int _iHeight, unsigned int _iWidth, + unsigned long _lSize) +{ + initialize(_iHeight, _iWidth, _lSize); +} + + +//---------------------------------------------------------------------------------------- +// destructor +CSparseMatrix::~CSparseMatrix() +{ + delete[] m_pfValues; + delete[] m_piColIndices; + delete[] m_plRowStarts; +} + +//---------------------------------------------------------------------------------------- +// initialize +bool CSparseMatrix::initialize(unsigned int _iHeight, unsigned int _iWidth, + unsigned long _lSize) +{ + m_iHeight = _iHeight; + m_iWidth = _iWidth; + m_lSize = _lSize; + + m_pfValues = new float32[_lSize]; + m_piColIndices = new unsigned int[_lSize]; + m_plRowStarts = new unsigned long[_iHeight+1]; + m_bInitialized = true; + + return m_bInitialized; +} + + +std::string CSparseMatrix::description() const +{ + std::stringstream res; + res << m_iHeight << "x" << m_iWidth << " sparse matrix"; + return res.str(); +} + + + + +} // end namespace diff --git a/src/SparseMatrixProjectionGeometry2D.cpp b/src/SparseMatrixProjectionGeometry2D.cpp new file mode 100644 index 0000000..b95bbf4 --- /dev/null +++ b/src/SparseMatrixProjectionGeometry2D.cpp @@ -0,0 +1,203 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SparseMatrixProjectionGeometry2D.h" + +#include <boost/lexical_cast.hpp> +#include "astra/AstraObjectManager.h" + + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D() : + CProjectionGeometry2D() +{ + m_pMatrix = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + const CSparseMatrix* _pMatrix) +{ + _clear(); + initialize(_iProjectionAngleCount, + _iDetectorCount, + _pMatrix); +} + +//---------------------------------------------------------------------------------------- +CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D(const CSparseMatrixProjectionGeometry2D& _projGeom) +{ + _clear(); + initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_pMatrix); +} + +//---------------------------------------------------------------------------------------- + +CSparseMatrixProjectionGeometry2D& CSparseMatrixProjectionGeometry2D::operator=(const CSparseMatrixProjectionGeometry2D& _other) +{ + m_bInitialized = _other.m_bInitialized; + if (_other.m_bInitialized) { + m_pMatrix = _other.m_pMatrix; + m_iDetectorCount = _other.m_iDetectorCount; + m_fDetectorWidth = _other.m_fDetectorWidth; + } + return *this; + +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CSparseMatrixProjectionGeometry2D::~CSparseMatrixProjectionGeometry2D() +{ + m_pMatrix = 0; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CSparseMatrixProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("SparseMatrixProjectionGeometry2D", this, _cfg); + + // initialization of parent class + CProjectionGeometry2D::initialize(_cfg); + + // get matrix + XMLNode* node = _cfg.self->getSingleNode("MatrixID"); + ASTRA_CONFIG_CHECK(node, "SparseMatrixProjectionGeometry2D", "No MatrixID tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pMatrix = CMatrixManager::getSingleton().get(id); + ASTRA_DELETE(node); + CC.markNodeParsed("MatrixID"); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CSparseMatrixProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + const CSparseMatrix* _pMatrix) +{ + if (m_bInitialized) { + clear(); + } + + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorCount = _iDetectorCount; + + // FIXME: We should probably require these for consistency? + m_fDetectorWidth = 1.0f; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pfProjectionAngles[i] = 0.0f; + + m_pMatrix = _pMatrix; + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Check. +bool CSparseMatrixProjectionGeometry2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjectionGeometry2D::_check(), "SparseMatrixProjectionGeometry2D", "Error in ProjectionGeometry2D initialization"); + + ASTRA_CONFIG_CHECK(m_pMatrix, "SparseMatrixProjectionGeometry2D", "No matrix specified"); + + ASTRA_CONFIG_CHECK(m_pMatrix->m_iHeight == (unsigned int)(m_iProjectionAngleCount * m_iDetectorCount), "SparseMatrixProjectionGeometry2D", "Matrix height doesn't match projection geometry"); + + return true; +} + + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CSparseMatrixProjectionGeometry2D::clone() +{ + return new CSparseMatrixProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CSparseMatrixProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CSparseMatrixProjectionGeometry2D + CSparseMatrixProjectionGeometry2D* pGeom2 = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false; + + // Maybe check equality of matrices by element? + if (m_pMatrix != pGeom2->m_pMatrix) return false; + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CSparseMatrixProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "sparse_matrix"); +} +//---------------------------------------------------------------------------------------- + +CVector3D CSparseMatrixProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) +{ + CVector3D vOutput(0.0f, 0.0f, 0.0f); + + // not implemented, yet + ASTRA_ASSERT(false); + + return vOutput; +} + +} // end namespace astra diff --git a/src/SparseMatrixProjector2D.cpp b/src/SparseMatrixProjector2D.cpp new file mode 100644 index 0000000..ba3a46b --- /dev/null +++ b/src/SparseMatrixProjector2D.cpp @@ -0,0 +1,219 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SparseMatrixProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/SparseMatrixProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CSparseMatrixProjector2D::type = "sparse_matrix"; + +//---------------------------------------------------------------------------------------- +// default constructor +CSparseMatrixProjector2D::CSparseMatrixProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CSparseMatrixProjector2D::CSparseMatrixProjector2D(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CSparseMatrixProjector2D::~CSparseMatrixProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CSparseMatrixProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CSparseMatrixProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CSparseMatrixProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "SparseMatrixProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "SparseMatrixProjector2D", "Volume geometry not initialized"); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SparseMatrixProjector2D", "Projection geometry not initialized"); + + + ASTRA_CONFIG_CHECK(dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry), "SparseMatrixProjector2D", "Unsupported projection geometry"); + + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + ASTRA_CONFIG_CHECK(pMatrix, "SparseMatrixProjector2D", "No matrix specified in projection geometry"); + + ASTRA_CONFIG_CHECK(pMatrix->m_iWidth == (unsigned int)m_pVolumeGeometry->getGridTotCount(), "SparseMatrixProjector2D", "Matrix width doesn't match volume geometry"); + + return true; +} + + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CSparseMatrixProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CSparseMatrixProjector2D::initialize(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CSparseMatrixProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + + unsigned int iMax = 0; + unsigned long lSize = m_pProjectionGeometry->getDetectorCount(); + lSize *= m_pProjectionGeometry->getProjectionAngleCount(); + for (unsigned long i = 0; i < lSize; ++i) { + unsigned int iRowSize = pMatrix->getRowSize(i); + if (iRowSize > iMax) + iMax = pMatrix->getRowSize(i); + } + return iMax; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CSparseMatrixProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + // TODO: Move this default implementation to Projector2D? + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CSparseMatrixProjector2D::projectPoint(int _iRow, int _iCol) +{ + unsigned int iVolumeIndex = _iCol * m_pVolumeGeometry->getGridRowCount() + _iRow; + + // NOTE: This is very slow currently because we don't have the + // sparse matrix stored in an appropriate form for this function. + std::vector<SDetector2D> ret; + + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + + for (int iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) + { + for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) + { + int iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + const unsigned int* piColIndices; + const float32* pfValues; + unsigned int iSize; + + pMatrix->getRowData(iRayIndex, iSize, pfValues, piColIndices); + + for (unsigned int i = 0; i < iSize; ++i) { + if (piColIndices[i] == iVolumeIndex) { + SDetector2D s; + s.m_iIndex = iRayIndex; + s.m_iAngleIndex = iAngle; + s.m_iDetectorIndex = iDetector; + ret.push_back(s); + break; + } else if (piColIndices[i] > iVolumeIndex) { + break; + } + } + } + } + return ret; +} + +//---------------------------------------------------------------------------------------- diff --git a/src/Utilities.cpp b/src/Utilities.cpp new file mode 100644 index 0000000..94992a9 --- /dev/null +++ b/src/Utilities.cpp @@ -0,0 +1,128 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Utilities.h" + +using namespace std; +using namespace astra; + +//----------------------------------------------------------------------------- +// Trim Whitespace Characters +void StringUtil::trim(std::string& _sString, bool _bLeft, bool _bRight) +{ + // trim right + if (_bRight) + _sString.erase(_sString.find_last_not_of(" \t\r") + 1); + + // trim left + if (_bLeft) + _sString.erase(0, _sString.find_first_not_of(" \t\r")); +} +//----------------------------------------------------------------------------- +// Split String +vector<string> StringUtil::split(const string& _sString, const string& _sDelims) +{ + std::vector<string> ret; + + size_t start, pos; + start = 0; + do { + pos = _sString.find_first_of(_sDelims, start); + if (pos == start) { + // Do nothing + start = pos + 1; + } else if (pos == string::npos) { + // Copy the rest of the string + ret.push_back(_sString.substr(start)); + break; + } else { + // Copy up to newt delimiter + ret.push_back(_sString.substr(start, pos - start)); + start = pos + 1; + } + + // Parse up to next real data (in case there are two delims after each other) + start = _sString.find_first_not_of(_sDelims, start); + } while (pos != string::npos); + + return ret; +} +//----------------------------------------------------------------------------- +// Cast string to int +bool StringUtil::toInt(const string& _sString, int& _iValue) +{ + std::istringstream ss(_sString); + ss >> _iValue; + return !ss.fail(); +} +//----------------------------------------------------------------------------- +// Cast string to float +bool StringUtil::toFloat32(const string& _sString, float32& _fValue) +{ + std::istringstream ss(_sString); + ss >> _fValue; + return !ss.fail(); +} +//----------------------------------------------------------------------------- +// Convert string to Lower Case +void StringUtil::toLowerCase(std::string& _sString) +{ + std::transform(_sString.begin(), + _sString.end(), + _sString.begin(), + ::tolower); +} +//----------------------------------------------------------------------------- +// Convert string to Upper Case +void StringUtil::toUpperCase(std::string& _sString) +{ + std::transform(_sString.begin(), + _sString.end(), + _sString.begin(), + ::toupper); +} +//----------------------------------------------------------------------------- + + + + +//----------------------------------------------------------------------------- +// Get Extension +string FileSystemUtil::getExtension(string& _sFilename) +{ + string sExtension = ""; + for (int i = _sFilename.length() - 1; 0 < i; i--) { + if (_sFilename[i] == '.') { + std::transform(sExtension.begin(),sExtension.end(),sExtension.begin(),::tolower); + return sExtension; + } + sExtension = _sFilename[i] + sExtension; + } + return ""; +} +//----------------------------------------------------------------------------- diff --git a/src/Vector3D.cpp b/src/Vector3D.cpp new file mode 100644 index 0000000..1e571b1 --- /dev/null +++ b/src/Vector3D.cpp @@ -0,0 +1,29 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "../include/astra/Vector3D.h" diff --git a/src/VolumeGeometry2D.cpp b/src/VolumeGeometry2D.cpp new file mode 100644 index 0000000..01d9b9a --- /dev/null +++ b/src/VolumeGeometry2D.cpp @@ -0,0 +1,282 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/VolumeGeometry2D.h" + +#include <boost/lexical_cast.hpp> +#include <cmath> + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Check all variable values +bool CVolumeGeometry2D::_check() +{ + ASTRA_CONFIG_CHECK(m_iGridColCount > 0, "VolumeGeometry2D", "GridColCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_iGridRowCount > 0, "VolumeGeometry2D", "GridRowCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_fWindowMinX < m_fWindowMaxX, "VolumeGeometry2D", "WindowMinX should be lower than WindowMaxX."); + ASTRA_CONFIG_CHECK(m_fWindowMinY < m_fWindowMaxY, "VolumeGeometry2D", "WindowMinY should be lower than WindowMaxY."); + + ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowArea == (m_fWindowLengthX * m_fWindowLengthY), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthX == (m_fWindowLengthX / (float32)m_iGridColCount), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthY == (m_fWindowLengthY / (float32)m_iGridRowCount), "VolumeGeometry2D", "Internal configuration error."); + + ASTRA_CONFIG_CHECK(m_fPixelArea == (m_fPixelLengthX * m_fPixelLengthY), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(fabsf(m_fDivPixelLengthX * m_fPixelLengthX - 1.0f) < eps, "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(fabsf(m_fDivPixelLengthY * m_fPixelLengthY - 1.0f) < eps, "VolumeGeometry2D", "Internal configuration error."); + + return true; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CVolumeGeometry2D::clear() +{ + m_iGridColCount = 0; + m_iGridRowCount = 0; + m_iGridTotCount = 0; + + m_fWindowLengthX = 0.0f; + m_fWindowLengthY = 0.0f; + m_fWindowArea = 0.0f; + + m_fPixelLengthX = 0.0f; + m_fPixelLengthY = 0.0f; + m_fPixelArea = 0.0f; + + m_fDivPixelLengthX = 0.0f; + m_fDivPixelLengthY = 0.0f; + + m_fWindowMinX = 0.0f; + m_fWindowMinY = 0.0f; + m_fWindowMaxX = 0.0f; + m_fWindowMaxY = 0.0f; + + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Default constructor. +CVolumeGeometry2D::CVolumeGeometry2D() : configCheckData(0) +{ + clear(); +} + +//---------------------------------------------------------------------------------------- +// Default constructor +CVolumeGeometry2D::CVolumeGeometry2D(int _iGridColCount, int _iGridRowCount) + : configCheckData(0) +{ + clear(); + initialize(_iGridColCount, _iGridRowCount); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CVolumeGeometry2D::CVolumeGeometry2D(int _iGridColCount, + int _iGridRowCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMaxX, + float32 _fWindowMaxY) +{ + clear(); + initialize(_iGridColCount, + _iGridRowCount, + _fWindowMinX, + _fWindowMinY, + _fWindowMaxX, + _fWindowMaxY); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CVolumeGeometry2D::~CVolumeGeometry2D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Clone +CVolumeGeometry2D* CVolumeGeometry2D::clone() +{ + CVolumeGeometry2D* res = new CVolumeGeometry2D(); + res->m_bInitialized = m_bInitialized; + res->m_iGridColCount = m_iGridColCount; + res->m_iGridRowCount = m_iGridRowCount; + res->m_iGridTotCount = m_iGridTotCount; + res->m_fWindowLengthX = m_fWindowLengthX; + res->m_fWindowLengthY = m_fWindowLengthY; + res->m_fWindowArea = m_fWindowArea; + res->m_fPixelLengthX = m_fPixelLengthX; + res->m_fPixelLengthY = m_fPixelLengthY; + res->m_fPixelArea = m_fPixelArea; + res->m_fDivPixelLengthX = m_fDivPixelLengthX; + res->m_fDivPixelLengthY = m_fDivPixelLengthY; + res->m_fWindowMinX = m_fWindowMinX; + res->m_fWindowMinY = m_fWindowMinY; + res->m_fWindowMaxX = m_fWindowMaxX; + res->m_fWindowMaxY = m_fWindowMaxY; + return res; +} + +//---------------------------------------------------------------------------------------- +// Initialization witha COnfig object +bool CVolumeGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CVolumeGeometry2D> CC("VolumeGeometry2D", this, _cfg); + + // uninitialize if the object was initialized before + if (m_bInitialized) { + clear(); + } + + // Required: GridColCount + XMLNode* node = _cfg.self->getSingleNode("GridColCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified."); + m_iGridColCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridColCount"); + + // Required: GridRowCount + node = _cfg.self->getSingleNode("GridRowCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified."); + m_iGridRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridRowCount"); + + // Optional: Window minima and maxima + m_fWindowMinX = _cfg.self->getOptionNumerical("WindowMinX", -m_iGridColCount/2.0f); + m_fWindowMaxX = _cfg.self->getOptionNumerical("WindowMaxX", m_iGridColCount/2.0f); + m_fWindowMinY = _cfg.self->getOptionNumerical("WindowMinY", -m_iGridRowCount/2.0f); + m_fWindowMaxY = _cfg.self->getOptionNumerical("WindowMaxY", m_iGridRowCount/2.0f); + CC.markOptionParsed("WindowMinX"); + CC.markOptionParsed("WindowMaxX"); + CC.markOptionParsed("WindowMinY"); + CC.markOptionParsed("WindowMaxY"); + + _calculateDependents(); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry2D::initialize(int _iGridColCount, int _iGridRowCount) +{ + return initialize(_iGridColCount, + _iGridRowCount, + -_iGridColCount/2.0f, + -_iGridRowCount/2.0f, + _iGridColCount/2.0f, + _iGridRowCount/2.0f); +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry2D::initialize(int _iGridColCount, + int _iGridRowCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMaxX, + float32 _fWindowMaxY) +{ + if (m_bInitialized) { + clear(); + } + + m_iGridColCount = _iGridColCount; + m_iGridRowCount = _iGridRowCount; + + m_fWindowMinX = _fWindowMinX; + m_fWindowMinY = _fWindowMinY; + m_fWindowMaxX = _fWindowMaxX; + m_fWindowMaxY = _fWindowMaxY; + + _calculateDependents(); + + m_bInitialized = _check(); + return m_bInitialized; +} + +void CVolumeGeometry2D::_calculateDependents() +{ + m_iGridTotCount = (m_iGridColCount * m_iGridRowCount); + + m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX); + m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY); + m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY); + + m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount); + m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount); + m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY); + + m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX); + m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY); +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CVolumeGeometry2D::isEqual(CVolumeGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !_pGeom2->m_bInitialized) return false; + + // check all values + if (m_iGridColCount != _pGeom2->m_iGridColCount) return false; + if (m_iGridRowCount != _pGeom2->m_iGridRowCount) return false; + if (m_iGridTotCount != _pGeom2->m_iGridTotCount) return false; + if (m_fWindowLengthX != _pGeom2->m_fWindowLengthX) return false; + if (m_fWindowLengthY != _pGeom2->m_fWindowLengthY) return false; + if (m_fWindowArea != _pGeom2->m_fWindowArea) return false; + if (m_fPixelLengthX != _pGeom2->m_fPixelLengthX) return false; + if (m_fPixelLengthY != _pGeom2->m_fPixelLengthY) return false; + if (m_fPixelArea != _pGeom2->m_fPixelArea) return false; + if (m_fDivPixelLengthX != _pGeom2->m_fDivPixelLengthX) return false; + if (m_fDivPixelLengthY != _pGeom2->m_fDivPixelLengthY) return false; + if (m_fWindowMinX != _pGeom2->m_fWindowMinX) return false; + if (m_fWindowMinY != _pGeom2->m_fWindowMinY) return false; + if (m_fWindowMaxX != _pGeom2->m_fWindowMaxX) return false; + if (m_fWindowMaxY != _pGeom2->m_fWindowMaxY) return false; + + return true; +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/VolumeGeometry3D.cpp b/src/VolumeGeometry3D.cpp new file mode 100644 index 0000000..86b8642 --- /dev/null +++ b/src/VolumeGeometry3D.cpp @@ -0,0 +1,384 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/VolumeGeometry3D.h" + +#include <boost/lexical_cast.hpp> + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Check all variable values +bool CVolumeGeometry3D::_check() +{ + ASTRA_CONFIG_CHECK(m_iGridColCount > 0, "VolumeGeometry3D", "GridColCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_iGridRowCount > 0, "VolumeGeometry3D", "GridRowCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_iGridSliceCount > 0, "VolumeGeometry3D", "GridSliceCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_fWindowMinX < m_fWindowMaxX, "VolumeGeometry3D", "WindowMinX should be lower than WindowMaxX."); + ASTRA_CONFIG_CHECK(m_fWindowMinY < m_fWindowMaxY, "VolumeGeometry3D", "WindowMinY should be lower than WindowMaxY."); + ASTRA_CONFIG_CHECK(m_fWindowMinZ < m_fWindowMaxZ, "VolumeGeometry3D", "WindowMinZ should be lower than WindowMaxZ."); + + ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthZ == (m_fWindowMaxZ - m_fWindowMinZ), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowArea == (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthX == (m_fWindowLengthX / (float32)m_iGridColCount), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthY == (m_fWindowLengthY / (float32)m_iGridRowCount), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthZ == (m_fWindowLengthZ / (float32)m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error."); + + ASTRA_CONFIG_CHECK(m_fPixelArea == (m_fPixelLengthX * m_fPixelLengthY * m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fDivPixelLengthX == (1.0f / m_fPixelLengthX), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fDivPixelLengthY == (1.0f / m_fPixelLengthY), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fDivPixelLengthZ == (1.0f / m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error."); + + return true; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CVolumeGeometry3D::clear() +{ + m_iGridColCount = 0; + m_iGridRowCount = 0; + m_iGridSliceCount = 0; + m_iGridTotCount = 0; + + m_fWindowLengthX = 0.0f; + m_fWindowLengthY = 0.0f; + m_fWindowLengthZ = 0.0f; + m_fWindowArea = 0.0f; + + m_fPixelLengthX = 0.0f; + m_fPixelLengthY = 0.0f; + m_fPixelLengthZ = 0.0f; + m_fPixelArea = 0.0f; + + m_fDivPixelLengthX = 0.0f; + m_fDivPixelLengthY = 0.0f; + m_fDivPixelLengthZ = 0.0f; + + m_fWindowMinX = 0.0f; + m_fWindowMinY = 0.0f; + m_fWindowMinZ = 0.0f; + m_fWindowMaxX = 0.0f; + m_fWindowMaxY = 0.0f; + m_fWindowMaxZ = 0.0f; + + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Default constructor. +CVolumeGeometry3D::CVolumeGeometry3D() : configCheckData(0) +{ + clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Default constructor +CVolumeGeometry3D::CVolumeGeometry3D(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount) + : configCheckData(0) +{ + clear(); + initialize(_iGridColCount, _iGridRowCount, _iGridSliceCount); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CVolumeGeometry3D::CVolumeGeometry3D(int _iGridColCount, + int _iGridRowCount, + int _iGridSliceCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMinZ, + float32 _fWindowMaxX, + float32 _fWindowMaxY, + float32 _fWindowMaxZ) +{ + clear(); + initialize(_iGridColCount, + _iGridRowCount, + _iGridSliceCount, + _fWindowMinX, + _fWindowMinY, + _fWindowMinZ, + _fWindowMaxX, + _fWindowMaxY, + _fWindowMaxZ); +} + +CVolumeGeometry3D::CVolumeGeometry3D(const CVolumeGeometry3D& _other) +{ + *this = _other; +} + +CVolumeGeometry3D& CVolumeGeometry3D::operator=(const CVolumeGeometry3D& _other) +{ + m_bInitialized = _other.m_bInitialized; + m_iGridColCount = _other.m_iGridColCount; + m_iGridRowCount = _other.m_iGridRowCount; + m_iGridSliceCount = _other.m_iGridSliceCount; + m_fWindowLengthX = _other.m_fWindowLengthX; + m_fWindowLengthY = _other.m_fWindowLengthY; + m_fWindowLengthZ = _other.m_fWindowLengthZ; + m_fWindowArea = _other.m_fWindowArea; + m_fPixelLengthX = _other.m_fPixelLengthX; + m_fPixelLengthY = _other.m_fPixelLengthY; + m_fPixelLengthZ = _other.m_fPixelLengthZ; + m_fDivPixelLengthX = _other.m_fDivPixelLengthX; + m_fDivPixelLengthY = _other.m_fDivPixelLengthY; + m_fDivPixelLengthZ = _other.m_fDivPixelLengthZ; + m_fWindowMinX = _other.m_fWindowMinX; + m_fWindowMinY = _other.m_fWindowMinY; + m_fWindowMinZ = _other.m_fWindowMinZ; + m_fWindowMaxX = _other.m_fWindowMaxX; + m_fWindowMaxY = _other.m_fWindowMaxY; + m_fWindowMaxZ = _other.m_fWindowMaxZ; + + m_iGridTotCount = _other.m_iGridTotCount; + m_fPixelArea = _other.m_fPixelArea; + + return *this; +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CVolumeGeometry3D::~CVolumeGeometry3D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CVolumeGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CVolumeGeometry3D> CC("VolumeGeometry3D", this, _cfg); + + + // uninitialize if the object was initialized before + if (m_bInitialized) { + clear(); + } + + // Required: GridColCount + XMLNode* node = _cfg.self->getSingleNode("GridColCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified."); + m_iGridColCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridColCount"); + + // Required: GridRowCount + node = _cfg.self->getSingleNode("GridRowCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified."); + m_iGridRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridRowCount"); + + // Required: GridRowCount + node = _cfg.self->getSingleNode("GridSliceCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridSliceCount tag specified."); + m_iGridSliceCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridSliceCount"); + + // Optional: Window minima and maxima + m_fWindowMinX = _cfg.self->getOptionNumerical("WindowMinX", -m_iGridColCount/2.0f); + m_fWindowMaxX = _cfg.self->getOptionNumerical("WindowMaxX", m_iGridColCount/2.0f); + m_fWindowMinY = _cfg.self->getOptionNumerical("WindowMinY", -m_iGridRowCount/2.0f); + m_fWindowMaxY = _cfg.self->getOptionNumerical("WindowMaxY", m_iGridRowCount/2.0f); + m_fWindowMinZ = _cfg.self->getOptionNumerical("WindowMinZ", -m_iGridSliceCount/2.0f); + m_fWindowMaxZ = _cfg.self->getOptionNumerical("WindowMaxZ", m_iGridSliceCount/2.0f); + CC.markOptionParsed("WindowMinX"); + CC.markOptionParsed("WindowMaxX"); + CC.markOptionParsed("WindowMinY"); + CC.markOptionParsed("WindowMaxY"); + CC.markOptionParsed("WindowMinZ"); + CC.markOptionParsed("WindowMaxZ"); + + // calculate some other things + m_iGridTotCount = (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount); + m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX); + m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY); + m_fWindowLengthZ = (m_fWindowMaxZ - m_fWindowMinZ); + m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ); + m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount); + m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount); + m_fPixelLengthZ = (m_fWindowLengthZ / (float32)m_iGridSliceCount); + + m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY * m_fPixelLengthZ); + m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX); + m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY); + m_fDivPixelLengthZ = ((float32)m_iGridSliceCount / m_fWindowLengthZ); // == (1.0f / m_fPixelLengthZ); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry3D::initialize(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount) +{ + return initialize(_iGridColCount, + _iGridRowCount, + _iGridSliceCount, + -_iGridColCount/2.0f, + -_iGridRowCount/2.0f, + -_iGridSliceCount/2.0f, + _iGridColCount/2.0f, + _iGridRowCount/2.0f, + _iGridSliceCount/2.0f); +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry3D::initialize(int _iGridColCount, + int _iGridRowCount, + int _iGridSliceCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMinZ, + float32 _fWindowMaxX, + float32 _fWindowMaxY, + float32 _fWindowMaxZ) +{ + if (m_bInitialized) { + clear(); + } + + m_iGridColCount = _iGridColCount; + m_iGridRowCount = _iGridRowCount; + m_iGridSliceCount = _iGridSliceCount; + m_iGridTotCount = (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount); + + m_fWindowMinX = _fWindowMinX; + m_fWindowMinY = _fWindowMinY; + m_fWindowMinZ = _fWindowMinZ; + m_fWindowMaxX = _fWindowMaxX; + m_fWindowMaxY = _fWindowMaxY; + m_fWindowMaxZ = _fWindowMaxZ; + + m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX); + m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY); + m_fWindowLengthZ = (m_fWindowMaxZ - m_fWindowMinZ); + m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ); + + m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount); + m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount); + m_fPixelLengthZ = (m_fWindowLengthZ / (float32)m_iGridSliceCount); + m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY); + + m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX); + m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY); + m_fDivPixelLengthZ = ((float32)m_iGridSliceCount / m_fWindowLengthZ); // == (1.0f / m_fPixelLengthZ); + + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CVolumeGeometry3D* CVolumeGeometry3D::clone() const +{ + CVolumeGeometry3D* res = new CVolumeGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iGridColCount = m_iGridColCount; + res->m_iGridRowCount = m_iGridRowCount; + res->m_iGridSliceCount = m_iGridSliceCount; + res->m_iGridTotCount = m_iGridTotCount; + res->m_fWindowLengthX = m_fWindowLengthX; + res->m_fWindowLengthY = m_fWindowLengthY; + res->m_fWindowLengthZ = m_fWindowLengthZ; + res->m_fWindowArea = m_fWindowArea; + res->m_fPixelLengthX = m_fPixelLengthX; + res->m_fPixelLengthY = m_fPixelLengthY; + res->m_fPixelLengthZ = m_fPixelLengthZ; + res->m_fPixelArea = m_fPixelArea; + res->m_fDivPixelLengthX = m_fDivPixelLengthX; + res->m_fDivPixelLengthY = m_fDivPixelLengthY; + res->m_fDivPixelLengthZ = m_fDivPixelLengthZ; + res->m_fWindowMinX = m_fWindowMinX; + res->m_fWindowMinY = m_fWindowMinY; + res->m_fWindowMinZ = m_fWindowMinZ; + res->m_fWindowMaxX = m_fWindowMaxX; + res->m_fWindowMaxY = m_fWindowMaxY; + res->m_fWindowMaxZ = m_fWindowMaxZ; + return res; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CVolumeGeometry3D::isEqual(const CVolumeGeometry3D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !_pGeom2->m_bInitialized) return false; + + // check all values + if (m_iGridColCount != _pGeom2->m_iGridColCount) return false; + if (m_iGridRowCount != _pGeom2->m_iGridRowCount) return false; + if (m_iGridSliceCount != _pGeom2->m_iGridSliceCount) return false; + if (m_iGridTotCount != _pGeom2->m_iGridTotCount) return false; + if (m_fWindowLengthX != _pGeom2->m_fWindowLengthX) return false; + if (m_fWindowLengthY != _pGeom2->m_fWindowLengthY) return false; + if (m_fWindowLengthZ != _pGeom2->m_fWindowLengthZ) return false; + if (m_fWindowArea != _pGeom2->m_fWindowArea) return false; + if (m_fPixelLengthX != _pGeom2->m_fPixelLengthX) return false; + if (m_fPixelLengthY != _pGeom2->m_fPixelLengthY) return false; + if (m_fPixelLengthZ != _pGeom2->m_fPixelLengthZ) return false; + if (m_fPixelArea != _pGeom2->m_fPixelArea) return false; + if (m_fDivPixelLengthX != _pGeom2->m_fDivPixelLengthX) return false; + if (m_fDivPixelLengthY != _pGeom2->m_fDivPixelLengthY) return false; + if (m_fDivPixelLengthZ != _pGeom2->m_fDivPixelLengthZ) return false; + if (m_fWindowMinX != _pGeom2->m_fWindowMinX) return false; + if (m_fWindowMinY != _pGeom2->m_fWindowMinY) return false; + if (m_fWindowMinZ != _pGeom2->m_fWindowMinZ) return false; + if (m_fWindowMaxX != _pGeom2->m_fWindowMaxX) return false; + if (m_fWindowMaxY != _pGeom2->m_fWindowMaxY) return false; + if (m_fWindowMaxZ != _pGeom2->m_fWindowMaxZ) return false; + + return true; +} + +CVolumeGeometry2D * CVolumeGeometry3D::createVolumeGeometry2D() const +{ + CVolumeGeometry2D * pOutput = new CVolumeGeometry2D(); + pOutput->initialize(getGridColCount(), getGridRowCount()); + return pOutput; +} + +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/XMLDocument.cpp b/src/XMLDocument.cpp new file mode 100644 index 0000000..96d0f80 --- /dev/null +++ b/src/XMLDocument.cpp @@ -0,0 +1,112 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/XMLDocument.h" +#include <string> +#include <fstream> +#include <iostream> +#include <sstream> + +#ifdef _MSC_VER +#include "rapidxml/rapidxml.hpp" +#include "rapidxml/rapidxml_print.hpp" +#else +#include "rapidxml.hpp" +#include "rapidxml_print.hpp" +#endif + +using namespace rapidxml; +using namespace astra; +using namespace std; + + + +//----------------------------------------------------------------------------- +XMLDocument::XMLDocument() +{ + fDOMDocument = 0; +} + +//----------------------------------------------------------------------------- +XMLDocument::~XMLDocument() +{ + delete fDOMDocument; + //parser->release(); +} + +//----------------------------------------------------------------------------- +XMLDocument* XMLDocument::readFromFile(string filename) +{ + // create the document + XMLDocument* res = new XMLDocument(); + res->fDOMDocument = new xml_document<>(); + + std::ifstream file(filename.c_str()); + std::stringstream reader; + reader << file.rdbuf(); + res->fBuf = reader.str(); + + res->fDOMDocument->parse<0>((char*)res->fBuf.c_str()); + + // return the document + return res; + +} + +//----------------------------------------------------------------------------- +// create an XML document with an empty root node +XMLDocument* XMLDocument::createDocument(string sRootName) +{ + XMLDocument* res = new XMLDocument(); + res->fDOMDocument = new xml_document<>(); + + char *node_name = res->fDOMDocument->allocate_string(sRootName.c_str()); + xml_node<> *node = res->fDOMDocument->allocate_node(node_element, node_name); + + res->fDOMDocument->append_node(node); + + return res; +} + +//----------------------------------------------------------------------------- +XMLNode* XMLDocument::getRootNode() +{ + // TODO: clean up: this 'new' requires callers to do memory management + return new XMLNode(fDOMDocument->first_node()); +} + +//----------------------------------------------------------------------------- +void XMLDocument::saveToFile(string sFilename) +{ + std::ofstream file(sFilename.c_str()); + + file << *fDOMDocument; +} + +//----------------------------------------------------------------------------- + diff --git a/src/XMLNode.cpp b/src/XMLNode.cpp new file mode 100644 index 0000000..e47c3e7 --- /dev/null +++ b/src/XMLNode.cpp @@ -0,0 +1,499 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/XMLNode.h" + +#ifdef _MSC_VER +#include "rapidxml/rapidxml.hpp" +#include "rapidxml/rapidxml_print.hpp" +#else +#include "rapidxml.hpp" +#include "rapidxml_print.hpp" +#endif + +#include <boost/lexical_cast.hpp> + +using namespace rapidxml; +using namespace astra; +using namespace std; + + +//----------------------------------------------------------------------------- +// Utility function to delete a list of nodes +static void deleteNodes(list<XMLNode*>& nodes) +{ + for (list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) + delete (*i); + + nodes.clear(); +} + + +//----------------------------------------------------------------------------- +// default constructor +XMLNode::XMLNode() +{ + +} + +//----------------------------------------------------------------------------- +// private constructor +XMLNode::XMLNode(xml_node<>* node) +{ + fDOMElement = node; +} + +//----------------------------------------------------------------------------- +// destructor +XMLNode::~XMLNode() +{ + +} + +//----------------------------------------------------------------------------- +// set DOM node (private) +void XMLNode::setDOMNode(xml_node<>* n) +{ + fDOMElement = n; +} + +//----------------------------------------------------------------------------- +// print XML Node +void XMLNode::print() +{ + std::cout << fDOMElement; +} + +//----------------------------------------------------------------------------- +// print XML Node +std::string XMLNode::toString() +{ + std::string s; + ::print(std::back_inserter(s), *fDOMElement, 0); + return s; +} + +//----------------------------------------------------------------------------- +// Get single node +XMLNode* XMLNode::getSingleNode(string name) +{ + xml_node<> *node = fDOMElement->first_node(name.c_str()); + + if (node) + return new XMLNode(node); + else + return 0; +} + +//----------------------------------------------------------------------------- +// Get list of nodes +list<XMLNode*> XMLNode::getNodes(string name) +{ + list<XMLNode*> result; + xml_node<> *iter; + for (iter = fDOMElement->first_node(name.c_str()); iter; iter = iter->next_sibling(name.c_str())) { + result.push_back(new XMLNode(iter)); + } + return result; +} + +//----------------------------------------------------------------------------- +// Get list of nodes +list<XMLNode*> XMLNode::getNodes() +{ + list<XMLNode*> result; + xml_node<> *iter; + for (iter = fDOMElement->first_node(); iter; iter = iter->next_sibling()) { + result.push_back(new XMLNode(iter)); + } + return result; +} + +//----------------------------------------------------------------------------- +// Get name of this node +std::string XMLNode::getName() +{ + return fDOMElement->name(); +} + +//----------------------------------------------------------------------------- +// Get node content - STRING +string XMLNode::getContent() +{ + return fDOMElement->value(); +} + +//----------------------------------------------------------------------------- +// Get node content - NUMERICAL +float32 XMLNode::getContentNumerical() +{ + return boost::lexical_cast<float32>(getContent()); +} + +//----------------------------------------------------------------------------- +// Get node content - BOOLEAN +bool XMLNode::getContentBool() +{ + string res = getContent(); + return ((res == "1") || (res == "yes") || (res == "true") || (res == "on")); +} + +//----------------------------------------------------------------------------- +// Get node content - STRING LIST +vector<string> XMLNode::getContentArray() +{ + // get listsize + int iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + vector<string> res(iSize); + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + string sValue = (*it)->getAttribute("value"); + ASTRA_ASSERT(iIndex < iSize); + res[iIndex] = sValue; + } + deleteNodes(nodes); + + // return + return res; +} + +//----------------------------------------------------------------------------- +// Get node content - NUMERICAL LIST +vector<float32> XMLNode::getContentNumericalArray() +{ + // is scalar + if (!hasAttribute("listsize")) { + vector<float32> res(1); + res[0] = getContentNumerical(); + return res; + } + + int iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + vector<float32> res(iSize); + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + float32 fValue = (*it)->getAttributeNumerical("value"); + ASTRA_ASSERT(iIndex < iSize); + res[iIndex] = fValue; + } + deleteNodes(nodes); + // return + return res; +} + +vector<double> XMLNode::getContentNumericalArrayDouble() +{ + // is scalar + if (!hasAttribute("listsize")) { + vector<double> res(1); + res[0] = getContentNumerical(); + return res; + } + + int iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + vector<double> res(iSize); + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + double fValue = (*it)->getAttributeNumericalDouble("value"); + ASTRA_ASSERT(iIndex < iSize); + res[iIndex] = fValue; + } + deleteNodes(nodes); + // return + return res; +} + +//----------------------------------------------------------------------------- +// Get node content - NUMERICAL LIST 2 +void XMLNode::getContentNumericalArray(float32*& _pfData, int& _iSize) +{ + // is scalar + if (!hasAttribute("listsize")) { + _iSize = 1; + _pfData = new float32[_iSize]; + _pfData[0] = getContentNumerical(); + return; + } + // get listsize + _iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + _pfData = new float32[_iSize]; + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + float32 fValue = (*it)->getAttributeNumerical("value"); + ASTRA_ASSERT(iIndex < _iSize); + _pfData[iIndex] = fValue; + } + deleteNodes(nodes); +} + +//----------------------------------------------------------------------------- +// Is attribute? +bool XMLNode::hasAttribute(string _sName) +{ + xml_attribute<> *attr = fDOMElement->first_attribute(_sName.c_str()); + return (attr != 0); +} + +//----------------------------------------------------------------------------- +// Get attribute - STRING +string XMLNode::getAttribute(string _sName, string _sDefaultValue) +{ + xml_attribute<> *attr = fDOMElement->first_attribute(_sName.c_str()); + + if (!attr) return _sDefaultValue; + + return attr->value(); +} + +//----------------------------------------------------------------------------- +// Get attribute - NUMERICAL +float32 XMLNode::getAttributeNumerical(string _sName, float32 _fDefaultValue) +{ + if (!hasAttribute(_sName)) return _fDefaultValue; + return boost::lexical_cast<float32>(getAttribute(_sName)); +} +double XMLNode::getAttributeNumericalDouble(string _sName, double _fDefaultValue) +{ + if (!hasAttribute(_sName)) return _fDefaultValue; + return boost::lexical_cast<double>(getAttribute(_sName)); +} + +//----------------------------------------------------------------------------- +// Get attribute - BOOLEAN +bool XMLNode::getAttributeBool(string _sName, bool _bDefaultValue) +{ + if (!hasAttribute(_sName)) return _bDefaultValue; + string res = getAttribute(_sName); + return ((res == "1") || (res == "yes") || (res == "true") || (res == "on")); +} + +//----------------------------------------------------------------------------- +// Has option? +bool XMLNode::hasOption(string _sKey) +{ + xml_node<> *iter; + for (iter = fDOMElement->first_node("Option"); iter; iter = iter->next_sibling("Option")) { + xml_attribute<> *attr = iter->first_attribute("key"); + if (attr && _sKey == attr->value()) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Get option - STRING +string XMLNode::getOption(string _sKey, string _sDefaultValue) +{ + xml_node<> *iter; + for (iter = fDOMElement->first_node("Option"); iter; iter = iter->next_sibling("Option")) { + xml_attribute<> *attr = iter->first_attribute("key"); + if (attr && _sKey == attr->value()) { + attr = iter->first_attribute("value"); + if (!attr) + return ""; + return attr->value(); + } + } + return _sDefaultValue; +} + +//----------------------------------------------------------------------------- +// Get option - NUMERICAL +float32 XMLNode::getOptionNumerical(string _sKey, float32 _fDefaultValue) +{ + if (!hasOption(_sKey)) return _fDefaultValue; + return boost::lexical_cast<float32>(getOption(_sKey)); +} + +//----------------------------------------------------------------------------- +// Get option - BOOL +bool XMLNode::getOptionBool(string _sKey, bool _bDefaultValue) +{ + bool bHasOption = hasOption(_sKey); + if (!bHasOption) return _bDefaultValue; + string res = getOption(_sKey); + return ((res == "1") || (res == "yes") || (res == "true") || (res == "on")); +} + +//----------------------------------------------------------------------------- +// Get option - NUMERICAL ARRAY +vector<float32> XMLNode::getOptionNumericalArray(string _sKey) +{ + if (!hasOption(_sKey)) return vector<float32>(); + + list<XMLNode*> nodes = getNodes("Option"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + if ((*it)->getAttribute("key") == _sKey) { + vector<float32> vals = (*it)->getContentNumericalArray(); + deleteNodes(nodes); + return vals; + } + } + + deleteNodes(nodes); + return vector<float32>(); +} + +//----------------------------------------------------------------------------- + + + + + + + + + + + + +//----------------------------------------------------------------------------- +// BUILD NODE +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Add child node - EMPTY +XMLNode* XMLNode::addChildNode(string _sNodeName) +{ + xml_document<> *doc = fDOMElement->document(); + char *node_name = doc->allocate_string(_sNodeName.c_str()); + xml_node<> *node = doc->allocate_node(node_element, node_name); + fDOMElement->append_node(node); + + // TODO: clean up: this 'new' requires callers to do memory management + return new XMLNode(node); +} + +//----------------------------------------------------------------------------- +// Add child node - STRING +XMLNode* XMLNode::addChildNode(string _sNodeName, string _sText) +{ + XMLNode* res = addChildNode(_sNodeName); + res->setContent(_sText); + return res; +} + +//----------------------------------------------------------------------------- +// Add child node - FLOAT +XMLNode* XMLNode::addChildNode(string _sNodeName, float32 _fValue) +{ + XMLNode* res = addChildNode(_sNodeName); + res->setContent(_fValue); + return res; +} + +//----------------------------------------------------------------------------- +// Add child node - LIST +XMLNode* XMLNode::addChildNode(string _sNodeName, float32* _pfList, int _iSize) +{ + XMLNode* res = addChildNode(_sNodeName); + res->setContent(_pfList, _iSize); + return res; +} + +//----------------------------------------------------------------------------- +// Set content - STRING +void XMLNode::setContent(string _sText) +{ + xml_document<> *doc = fDOMElement->document(); + char *text = doc->allocate_string(_sText.c_str()); + fDOMElement->value(text); +} + +//----------------------------------------------------------------------------- +// Set content - FLOAT +void XMLNode::setContent(float32 _fValue) +{ + setContent(boost::lexical_cast<string>(_fValue)); +} + +//----------------------------------------------------------------------------- +// Set content - LIST +void XMLNode::setContent(float32* pfList, int _iSize) +{ + addAttribute("listsize", _iSize); + for (int i = 0; i < _iSize; i++) { + XMLNode* item = addChildNode("ListItem"); + item->addAttribute("index", i); + item->addAttribute("value",pfList[i]); + delete item; + } +} + +//----------------------------------------------------------------------------- +// Add attribute - STRING +void XMLNode::addAttribute(string _sName, string _sText) +{ + xml_document<> *doc = fDOMElement->document(); + char *name = doc->allocate_string(_sName.c_str()); + char *text = doc->allocate_string(_sText.c_str()); + xml_attribute<> *attr = doc->allocate_attribute(name, text); + fDOMElement->append_attribute(attr); +} + +//----------------------------------------------------------------------------- +// Add attribute - FLOAT +void XMLNode::addAttribute(string _sName, float32 _fValue) +{ + addAttribute(_sName, boost::lexical_cast<string>(_fValue)); +} + +//----------------------------------------------------------------------------- +// Add option - STRING +void XMLNode::addOption(string _sName, string _sText) +{ + XMLNode* node = addChildNode("Option"); + node->addAttribute("key", _sName); + node->addAttribute("value", _sText); + delete node; +} + +//----------------------------------------------------------------------------- +// Add option - FLOAT +void XMLNode::addOption(string _sName, float32 _sText) +{ + XMLNode* node = addChildNode("Option"); + node->addAttribute("key", _sName); + node->addAttribute("value", _sText); + delete node; +} +//----------------------------------------------------------------------------- + + diff --git a/src/astra.def b/src/astra.def new file mode 100644 index 0000000..585324c --- /dev/null +++ b/src/astra.def @@ -0,0 +1,6 @@ +; MatlabDLL.def : Declares the module parameters for the DLL. + +LIBRARY "astra" + +EXPORTS + ; Explicit exports can go here diff --git a/src/swrap.cpp b/src/swrap.cpp new file mode 100644 index 0000000..be8238e --- /dev/null +++ b/src/swrap.cpp @@ -0,0 +1,47 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _MSC_VER + +#include "astra/swrap.h" +#include <cerrno> + +errno_t fopen_s(FILE** pFile, const char* filename, const char* mode) +{ + if (!pFile) + return EINVAL; + + FILE* x = fopen(filename, mode); + if (!x) + return errno; + + *pFile = x; + return 0; +} + +#endif diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..6fc963e --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,38 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + + +#define BOOST_TEST_DYN_LINK + +// Generate main() +#define BOOST_AUTO_TEST_MAIN + +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/floating_point_comparison.hpp> diff --git a/tests/test_AstraObjectManager.cpp b/tests/test_AstraObjectManager.cpp new file mode 100644 index 0000000..893efb9 --- /dev/null +++ b/tests/test_AstraObjectManager.cpp @@ -0,0 +1,79 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> + +#include "astra/AstraObjectManager.h" + +namespace astra { +DEFINE_SINGLETON(CAstraObjectManager<int>); +} + +BOOST_AUTO_TEST_CASE( testAstraObjectManager ) +{ + astra::CAstraObjectManager<int> man; + + int i1 = man.store(new int(1)); + BOOST_REQUIRE(man.hasIndex(i1)); + BOOST_CHECK(*(man.get(i1)) == 1); + + int i2 = man.store(new int(2)); + BOOST_REQUIRE(man.hasIndex(i2)); + BOOST_CHECK(*(man.get(i1)) == 1); + BOOST_CHECK(*(man.get(i2)) == 2); + + man.remove(i1); + + BOOST_CHECK(!man.hasIndex(i1)); + BOOST_REQUIRE(man.hasIndex(i2)); + + int i3 = man.store(new int(3)); + BOOST_REQUIRE(man.hasIndex(i3)); + BOOST_CHECK(*(man.get(i2)) == 2); + BOOST_CHECK(*(man.get(i3)) == 3); + + int* pi4 = new int(4); + int i4 = man.store(pi4); + BOOST_REQUIRE(man.hasIndex(i4)); + BOOST_CHECK(*(man.get(i2)) == 2); + BOOST_CHECK(*(man.get(i3)) == 3); + BOOST_CHECK(*(man.get(i4)) == 4); + + BOOST_CHECK(man.getIndex(pi4) == i4); + + man.clear(); + + BOOST_CHECK(!man.hasIndex(i1)); + BOOST_CHECK(!man.hasIndex(i2)); + BOOST_CHECK(!man.hasIndex(i3)); + BOOST_CHECK(!man.hasIndex(i4)); + BOOST_CHECK(!man.getIndex(pi4)); +} diff --git a/tests/test_FanFlatProjectionGeometry2D.cpp b/tests/test_FanFlatProjectionGeometry2D.cpp new file mode 100644 index 0000000..a07fbf8 --- /dev/null +++ b/tests/test_FanFlatProjectionGeometry2D.cpp @@ -0,0 +1,119 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include <cmath> + +#include "astra/FanFlatProjectionGeometry2D.h" + +BOOST_AUTO_TEST_CASE( testFanFlatProjectionGeometry2D_Constructor ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CFanFlatProjectionGeometry2D geom(4, 8, 0.5f, angles, 1.0f, 2.0f); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.getProjectionAngleCount() == 4 ); + BOOST_CHECK( geom.getDetectorCount() == 8 ); + BOOST_CHECK( geom.getDetectorWidth() == 0.5f ); + BOOST_CHECK( geom.getProjectionAngle(0) == 0.0f ); + BOOST_CHECK( geom.getProjectionAngle(1) == 1.0f ); + BOOST_CHECK( geom.getProjectionAngle(2) == 2.0f ); + BOOST_CHECK( geom.getProjectionAngle(3) == 3.0f ); + BOOST_CHECK( geom.getProjectionAngles()[0] == 0.0f ); + BOOST_CHECK( geom.getProjectionAngles()[3] == 3.0f ); + BOOST_CHECK( geom.getOriginSourceDistance() == 1.0f ); + BOOST_CHECK( geom.getOriginDetectorDistance() == 2.0f ); +} + +BOOST_AUTO_TEST_CASE( testFanFlatProjectionGeometry2D_Offsets ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CFanFlatProjectionGeometry2D geom(4, 8, 0.5f, angles, 1.0f, 2.0f); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.getSourceDetectorDistance() == 3.0f ); + BOOST_CHECK_SMALL( geom.getProjectionAngleDegrees(2) - 114.591559026165f, 1e-5f ); + + // CHECKME: where is the center of the detector array? + BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.0f) == 3.5f ); + BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.625f) == 4.75f ); + BOOST_CHECK( geom.detectorOffsetToIndex(-0.1f) == 3 ); + + BOOST_CHECK( geom.indexToDetectorOffset(0) == -1.75f ); + BOOST_CHECK( geom.indexToDetectorOffset(1) == -1.25f ); + + int angle, detector; + geom.indexToAngleDetectorIndex(10, angle, detector); + BOOST_CHECK( angle == 1 ); + BOOST_CHECK( detector == 2 ); + + float t, theta; + geom.getRayParams(0, 2, t, theta); + BOOST_CHECK_SMALL( tan(theta) + 0.25f, astra::eps ); + BOOST_CHECK_SMALL( 17.0f*t*t - 1.0f, astra::eps ); + + // TODO: add test with large angle +} + + +BOOST_AUTO_TEST_CASE( testFanFlatProjectionGeometry2D_Clone ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CFanFlatProjectionGeometry2D geom(4, 8, 0.5f, angles, 1.0f, 2.0f); + + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFanFlatProjectionGeometry2D* geom2; + geom2 = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(geom.clone()); + + BOOST_REQUIRE( geom2 ); + BOOST_REQUIRE( geom2->isInitialized() ); + + BOOST_CHECK( geom.isEqual(geom2) ); + BOOST_CHECK( geom2->getProjectionAngleCount() == 4 ); + BOOST_CHECK( geom2->getDetectorCount() == 8 ); + BOOST_CHECK( geom2->getDetectorWidth() == 0.5f ); + BOOST_CHECK( geom2->getProjectionAngle(0) == 0.0f ); + BOOST_CHECK( geom2->getProjectionAngle(1) == 1.0f ); + BOOST_CHECK( geom2->getProjectionAngle(2) == 2.0f ); + BOOST_CHECK( geom2->getProjectionAngle(3) == 3.0f ); + BOOST_CHECK( geom2->getProjectionAngles()[0] == 0.0f ); + BOOST_CHECK( geom2->getProjectionAngles()[3] == 3.0f ); + BOOST_CHECK( geom2->getOriginSourceDistance() == 1.0f ); + BOOST_CHECK( geom2->getOriginDetectorDistance() == 2.0f ); + delete geom2; +} + diff --git a/tests/test_Float32Data2D.cpp b/tests/test_Float32Data2D.cpp new file mode 100644 index 0000000..54d642b --- /dev/null +++ b/tests/test_Float32Data2D.cpp @@ -0,0 +1,229 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/Float32Data2D.h" + + +// Utility class to test Float32Data2D +class CTestFloat32Data2D : public astra::CFloat32Data2D { +public: + CTestFloat32Data2D(int _iWidth, int _iHeight) + { + m_bInitialized = _initialize(_iWidth, _iHeight); + } + CTestFloat32Data2D(int _iWidth, int _iHeight, const astra::float32* _pfData) + { + m_bInitialized = _initialize(_iWidth, _iHeight, _pfData); + } + + CTestFloat32Data2D(int _iWidth, int _iHeight, astra::float32 _fScalar) + { + m_bInitialized = _initialize(_iWidth, _iHeight, _fScalar); + } + + CTestFloat32Data2D() { } + +}; + + +struct TestFloat32Data2D { + static astra::float32 d[]; + TestFloat32Data2D() : data(2,2,d) + { + } + + ~TestFloat32Data2D() + { + } + + CTestFloat32Data2D data; +}; + +astra::float32 TestFloat32Data2D::d[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + +BOOST_AUTO_TEST_CASE( testFloat32Data2D_Constructor1 ) +{ + CTestFloat32Data2D data(2,2); + + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getWidth() == 2 ); + BOOST_CHECK( data.getHeight() == 2 ); + BOOST_CHECK( data.getSize() == 4 ); + BOOST_CHECK( data.getDimensionCount() == 2 ); + + BOOST_REQUIRE( data.getDataConst() != 0 ); + BOOST_REQUIRE( data.getData() != 0 ); + BOOST_REQUIRE( data.getData2D() != 0 ); + BOOST_REQUIRE( data.getData2DConst() != 0 ); + BOOST_REQUIRE( data.getData2D()[0] != 0 ); + BOOST_REQUIRE( data.getData2DConst()[0] != 0 ); + + data.setData(1.0f); + + // CHECKME: should this be necessary? + data.updateStatistics(); + + BOOST_CHECK( data.getGlobalMin() == 1.0f ); + BOOST_CHECK( data.getGlobalMax() == 1.0f ); + BOOST_CHECK( data.getGlobalMean() == 1.0f ); + + BOOST_CHECK( data.getData()[0] == 1.0f ); + BOOST_CHECK( data.getDataConst()[0] == 1.0f ); + BOOST_CHECK( data.getData2D()[0][0] == 1.0f ); + BOOST_CHECK( data.getData2DConst()[0][0] == 1.0f ); +} + +BOOST_AUTO_TEST_CASE( testFloat32Data2D_Constructor2 ) +{ + CTestFloat32Data2D data(2,2,1.5f); + + // CHECKME: should this be necessary? + data.updateStatistics(); + + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getWidth() == 2 ); + BOOST_CHECK( data.getHeight() == 2 ); + BOOST_CHECK( data.getSize() == 4 ); + BOOST_CHECK( data.getDimensionCount() == 2 ); + + BOOST_REQUIRE( data.getDataConst() != 0 ); + BOOST_REQUIRE( data.getData() != 0 ); + BOOST_REQUIRE( data.getData2D() != 0 ); + BOOST_REQUIRE( data.getData2DConst() != 0 ); + BOOST_REQUIRE( data.getData2D()[0] != 0 ); + BOOST_REQUIRE( data.getData2DConst()[0] != 0 ); + + BOOST_CHECK( data.getGlobalMin() == 1.5f ); + BOOST_CHECK( data.getGlobalMax() == 1.5f ); + BOOST_CHECK( data.getGlobalMean() == 1.5f ); + + BOOST_CHECK( data.getData()[0] == 1.5f ); + BOOST_CHECK( data.getDataConst()[0] == 1.5f ); + BOOST_CHECK( data.getData2D()[0][0] == 1.5f ); + BOOST_CHECK( data.getData2DConst()[0][0] == 1.5f ); +} + +BOOST_AUTO_TEST_CASE( testFloat32Data2D_Constructor3 ) +{ + astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + CTestFloat32Data2D data(2,2,d); + + // CHECKME: should this be necessary? + data.updateStatistics(); + + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getWidth() == 2 ); + BOOST_CHECK( data.getHeight() == 2 ); + BOOST_CHECK( data.getSize() == 4 ); + BOOST_CHECK( data.getDimensionCount() == 2 ); + + BOOST_REQUIRE( data.getDataConst() != 0 ); + BOOST_REQUIRE( data.getData() != 0 ); + BOOST_REQUIRE( data.getData2D() != 0 ); + BOOST_REQUIRE( data.getData2DConst() != 0 ); + BOOST_REQUIRE( data.getData2D()[0] != 0 ); + BOOST_REQUIRE( data.getData2DConst()[0] != 0 ); + + BOOST_CHECK( data.getGlobalMin() == 1.0f ); + BOOST_CHECK( data.getGlobalMax() == 4.0f ); + + BOOST_CHECK( data.getData()[0] == 1.0f ); + BOOST_CHECK( data.getDataConst()[0] == 1.0f ); + BOOST_CHECK( data.getData2D()[0][0] == 1.0f ); + BOOST_CHECK( data.getData2DConst()[0][0] == 1.0f ); + +} + +BOOST_FIXTURE_TEST_CASE( testFloat32Data2D_Operators, TestFloat32Data2D ) +{ + // Note: all operations below involve exactly representable floats, + // so there is no need to use epsilons in the checks + + data.updateStatistics(); + + // FIXME: should those be correct here? + BOOST_CHECK( data.getGlobalMin() == 1.0f ); + BOOST_CHECK( data.getGlobalMax() == 4.0f ); + BOOST_CHECK( data.getGlobalMean() == 2.5f ); + + data *= 2.0f; + + BOOST_CHECK( data.getDataConst()[0] == 2.0f ); + BOOST_CHECK( data.getDataConst()[3] == 8.0f ); + + data /= 0.5f; + + BOOST_CHECK( data.getDataConst()[0] == 4.0f ); + BOOST_CHECK( data.getDataConst()[3] == 16.0f ); + + astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + CTestFloat32Data2D data2(2,2,d); + + data += data2; + + BOOST_CHECK( data.getDataConst()[0] == 5.0f ); + BOOST_CHECK( data.getDataConst()[3] == 20.0f ); + + data *= data2; + + BOOST_CHECK( data.getDataConst()[0] == 5.0f ); + BOOST_CHECK( data.getDataConst()[3] == 80.0f ); + + data -= data2; + BOOST_CHECK( data.getDataConst()[0] == 4.0f ); + BOOST_CHECK( data.getDataConst()[3] == 76.0f ); + + data += 0.5f; + BOOST_CHECK( data.getDataConst()[0] == 4.5f ); + BOOST_CHECK( data.getDataConst()[3] == 76.5f ); + + data -= 0.5f; + BOOST_CHECK( data.getDataConst()[0] == 4.0f ); + BOOST_CHECK( data.getDataConst()[3] == 76.0f ); +} + +BOOST_FIXTURE_TEST_CASE( testFloat32Data2D_Update, TestFloat32Data2D ) +{ + data.getData()[2] = 42.0f; + data.getData()[1] = -37.0f; + data.updateStatistics(); + + BOOST_CHECK( data.getGlobalMin() == -37.0f ); + BOOST_CHECK( data.getGlobalMax() == 42.0f ); + BOOST_CHECK( data.getGlobalMean() == 2.5f ); +} diff --git a/tests/test_Float32ProjectionData2D.cpp b/tests/test_Float32ProjectionData2D.cpp new file mode 100644 index 0000000..1fddeec --- /dev/null +++ b/tests/test_Float32ProjectionData2D.cpp @@ -0,0 +1,115 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/Float32ProjectionData2D.h" +#include "astra/ParallelProjectionGeometry2D.h" + +// Note: most of the features of CFloat32ProjectionData2D are tested by +// the CFloat32Data2D tests. + +BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Constructor1 ) +{ + astra::float32 angles[] = { 0.0f, 1.0f }; + astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32ProjectionData2D data(&geom); + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getType() == astra::CFloat32Data2D::PROJECTION ); + BOOST_CHECK( data.getGeometry()->isEqual(&geom) ); +} + +BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Constructor2 ) +{ + astra::float32 angles[] = { 0.0f, 1.0f }; + astra::float32 d[] = { 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f }; + astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32ProjectionData2D data(&geom, d); + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getType() == astra::CFloat32Data2D::PROJECTION ); + BOOST_CHECK( data.getGeometry()->isEqual(&geom) ); + + // CHECKME: should this be necessary? + data.updateStatistics(); + + BOOST_CHECK( data.getGlobalMax() == 10.0f ); +} + +BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Constructor3 ) +{ + astra::float32 angles[] = { 0.0f, 1.0f }; + astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32ProjectionData2D data(&geom, 3.5f); + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getType() == astra::CFloat32Data2D::PROJECTION ); + BOOST_CHECK( data.getGeometry()->isEqual(&geom) ); + + // CHECKME: should this be necessary? + data.updateStatistics(); + + BOOST_CHECK( data.getGlobalMax() == 3.5f ); +} + +BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Clone ) +{ + astra::float32 angles[] = { 0.0f, 1.0f }; + astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32ProjectionData2D data(&geom, 3.5f); + BOOST_REQUIRE( data.isInitialized() ); + + astra::CFloat32ProjectionData2D data2(data); + BOOST_REQUIRE( data2.isInitialized() ); + + BOOST_CHECK( data2.getGeometry()->isEqual(&geom) ); + BOOST_CHECK( data2.getDataConst()[0] == 3.5f ); + BOOST_CHECK( data2.getDataConst()[3] == 3.5f ); + + astra::CFloat32ProjectionData2D data3; + data3 = data; + BOOST_REQUIRE( data3.isInitialized() ); + + BOOST_CHECK( data3.getGeometry()->isEqual(&geom) ); + BOOST_CHECK( data3.getDataConst()[0] == 3.5f ); + BOOST_CHECK( data3.getDataConst()[3] == 3.5f ); +} diff --git a/tests/test_Float32VolumeData2D.cpp b/tests/test_Float32VolumeData2D.cpp new file mode 100644 index 0000000..29dde3a --- /dev/null +++ b/tests/test_Float32VolumeData2D.cpp @@ -0,0 +1,110 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/Float32VolumeData2D.h" + +// Note: most of the features of CFloat32VolumeData2D are tested by +// the CFloat32Data2D tests. + +BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Constructor1 ) +{ + astra::CVolumeGeometry2D geom(16, 32); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32VolumeData2D data(&geom); + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getType() == astra::CFloat32Data2D::VOLUME ); + BOOST_CHECK( data.getGeometry()->isEqual(&geom) ); +} + +BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Constructor1odd ) +{ + astra::CVolumeGeometry2D geom(16, 32); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32VolumeData2D data(&geom, 1.0f); + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getType() == astra::CFloat32Data2D::VOLUME ); + BOOST_CHECK( data.getGeometry()->isEqual(&geom) ); + + // CHECKME: should this be necessary? + data.updateStatistics(); + BOOST_CHECK( data.getGlobalMax() == 1.0f ); +} + +BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Constructor2 ) +{ + astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + astra::CVolumeGeometry2D geom(2, 2); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32VolumeData2D data(&geom, d); + BOOST_REQUIRE( data.isInitialized() ); + + BOOST_CHECK( data.getType() == astra::CFloat32Data2D::VOLUME ); + + BOOST_CHECK( data.getGeometry()->isEqual(&geom) ); + + // CHECKME: should this be necessary? + data.updateStatistics(); + BOOST_CHECK( data.getGlobalMax() == 4.0f ); +} + +BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Clone ) +{ + astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f }; + astra::CVolumeGeometry2D geom(2, 2); + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CFloat32VolumeData2D data(&geom, d); + BOOST_REQUIRE( data.isInitialized() ); + + astra::CFloat32VolumeData2D data2(data); + BOOST_REQUIRE( data2.isInitialized() ); + + BOOST_CHECK( data2.getGeometry()->isEqual(&geom) ); + BOOST_CHECK( data2.getDataConst()[0] == 1.0f ); + BOOST_CHECK( data2.getDataConst()[3] == 4.0f ); + + astra::CFloat32VolumeData2D data3; + data3 = data; + BOOST_REQUIRE( data3.isInitialized() ); + + BOOST_CHECK( data3.getGeometry()->isEqual(&geom) ); + BOOST_CHECK( data3.getDataConst()[0] == 1.0f ); + BOOST_CHECK( data3.getDataConst()[3] == 4.0f ); +} diff --git a/tests/test_Fourier.cpp b/tests/test_Fourier.cpp new file mode 100644 index 0000000..2602edb --- /dev/null +++ b/tests/test_Fourier.cpp @@ -0,0 +1,182 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/Fourier.h" + +BOOST_AUTO_TEST_CASE( testFourier_DFT_1D_1 ) +{ + astra::float32 inR[5] = { 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }; + astra::float32 inI[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + astra::float32 outR[5]; + astra::float32 outI[5]; + + astra::discreteFourierTransform1D(5, inR, inI, outR, outI, 1, 1, false); + + astra::float32 expected1R[5] = { 3.0f, 1.618034f, -0.618034f, -0.618034f, 1.618034f }; + for (unsigned int i = 0; i < 5; ++i) { + BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00001f); + BOOST_CHECK_SMALL(outI[i], 0.00001f); + } + + astra::discreteFourierTransform1D(5, outR, outI, inR, inI, 1, 1, true); + astra::float32 expected2R[5] = { 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }; + for (unsigned int i = 0; i < 5; ++i) { + BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f); + BOOST_CHECK_SMALL(inI[i], 0.00001f); + } +} + +BOOST_AUTO_TEST_CASE( testFourier_DFT_2D_1 ) +{ + astra::float32 inR[25] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }; + astra::float32 inI[25] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + astra::float32 outR[25]; + astra::float32 outI[25]; + + astra::discreteFourierTransform2D(5, 5, inR, inI, outR, outI, false); + + astra::float32 expected1R[25] = + { 13.0f , 5.236068f, 0.763932f, 0.763932f, 5.236068f, + 5.236068f,-0.618034f,-2.0f ,-2.0f ,-0.618034f, + 0.763932f,-2.0f , 1.618034f, 1.618034f,-2.0f , + 0.763932f,-2.0f , 1.618034f, 1.618034f,-2.0f , + 5.236068f,-0.618034f,-2.0f ,-2.0f ,-0.618034f }; + for (unsigned int i = 0; i < 25; ++i) { + BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00001f); + BOOST_CHECK_SMALL(outI[i], 0.00001f); + } + + astra::discreteFourierTransform2D(5, 5, outR, outI, inR, inI, true); + astra::float32 expected2R[25] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }; + for (unsigned int i = 0; i < 25; ++i) { + BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f); + BOOST_CHECK_SMALL(inI[i], 0.00001f); + } + + +} + + +BOOST_AUTO_TEST_CASE( testFourier_FFT_1D_1 ) +{ + astra::float32 inR[8] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }; + astra::float32 inI[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + astra::float32 outR[5]; + astra::float32 outI[5]; + + astra::fastTwoPowerFourierTransform1D(8, inR, inI, outR, outI, 1, 1, false); + + astra::float32 expected1R[8] = { 5.0f, 2.414214f, -1.0f, -0.414214f, 1.0f, -0.414214f, -1.0f, 2.414214f }; + for (unsigned int i = 0; i < 8; ++i) { + BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00001f); + BOOST_CHECK_SMALL(outI[i], 0.00001f); + } + + astra::fastTwoPowerFourierTransform1D(8, outR, outI, inR, inI, 1, 1, true); + astra::float32 expected2R[8] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }; + for (unsigned int i = 0; i < 8; ++i) { + BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f); + BOOST_CHECK_SMALL(inI[i], 0.00001f); + } + +} + +BOOST_AUTO_TEST_CASE( testFourier_FFT_2D_1 ) +{ + astra::float32 inR[64] = { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }; + astra::float32 inI[64] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + astra::float32 outR[64]; + astra::float32 outI[64]; + + astra::discreteFourierTransform2D(8, 8, inR, inI, outR, outI, false); + + astra::float32 expected1R[64] = + { 25.0f, 12.656854f, 1.0f, 1.343146f, 1.0f, 1.343146f, 1.0f, 12.656854f, + 12.656854f, 3.0f, -3.828427f, -1.0f, -1.0f, -1.0f, -3.828427f, 3.0f, + 1.0f, -3.828427f, -3.0f, 1.828427f, 1.0f, 1.828427f, -3.0f, -3.828427f, + 1.343146f, -1.0f, 1.828427f, 3.0f, -1.0f, 3.0f, 1.828427f, -1.0f, + 1.0f, -1.0f, 1.0f, -1.0f, -7.0f, -1.0f, 1.0f, -1.0f, + 1.343146f, -1.0f, 1.828427f, 3.0f, -1.0f, 3.0f, 1.828427f, -1.0f, + 1.0f, -3.828427f, -3.0f, 1.828427f, 1.0f, 1.828427f, -3.0f, -3.828427f, + 12.656854f, 3.0f, -3.828427f, -1.0f, -1.0f, -1.0f, -3.828427f, 3.0f }; + for (unsigned int i = 0; i < 64; ++i) { + BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00002f); + BOOST_CHECK_SMALL(outI[i], 0.00001f); + } + + + astra::discreteFourierTransform2D(8, 8, outR, outI, inR, inI, true); + astra::float32 expected2R[64] = { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }; + for (unsigned int i = 0; i < 64; ++i) { + BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f); + BOOST_CHECK_SMALL(inI[i], 0.00001f); + } + + +} + diff --git a/tests/test_ParallelBeamLineKernelProjector2D.cpp b/tests/test_ParallelBeamLineKernelProjector2D.cpp new file mode 100644 index 0000000..86bc54f --- /dev/null +++ b/tests/test_ParallelBeamLineKernelProjector2D.cpp @@ -0,0 +1,82 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/ParallelBeamLineKernelProjector2D.h" +#include "astra/ParallelProjectionGeometry2D.h" +#include "astra/VolumeGeometry2D.h" + +struct TestParallelBeamLineKernelProjector2D { + TestParallelBeamLineKernelProjector2D() + { + astra::float32 angles[] = { 1.0f }; + BOOST_REQUIRE( projGeom.initialize(1, 9, 1.0f, angles) ); + BOOST_REQUIRE( volGeom.initialize(6, 4) ); + BOOST_REQUIRE( proj.initialize(&projGeom, &volGeom) ); + } + ~TestParallelBeamLineKernelProjector2D() + { + + } + + astra::CParallelBeamLineKernelProjector2D proj; + astra::CParallelProjectionGeometry2D projGeom; + astra::CVolumeGeometry2D volGeom; +}; + +BOOST_FIXTURE_TEST_CASE( testParallelBeamLineKernelProjector2D_General, TestParallelBeamLineKernelProjector2D ) +{ + +} + +BOOST_FIXTURE_TEST_CASE( testParallelBeamLineKernelProjector2D_Rectangle, TestParallelBeamLineKernelProjector2D ) +{ + int iMax = proj.getProjectionWeightsCount(0); + BOOST_REQUIRE(iMax > 0); + + astra::SPixelWeight* pPix = new astra::SPixelWeight[iMax]; + BOOST_REQUIRE(pPix); + + int iCount; + proj.computeSingleRayWeights(0, 4, pPix, iMax, iCount); + BOOST_REQUIRE(iCount <= iMax); + + astra::float32 fWeight = 0; + for (int i = 0; i < iCount; ++i) + fWeight += pPix[i].m_fWeight; + + BOOST_CHECK_SMALL(fWeight - 7.13037f, 0.00001f); +} + + diff --git a/tests/test_ParallelBeamLinearKernelProjector2D.cpp b/tests/test_ParallelBeamLinearKernelProjector2D.cpp new file mode 100644 index 0000000..9100db4 --- /dev/null +++ b/tests/test_ParallelBeamLinearKernelProjector2D.cpp @@ -0,0 +1,172 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/ParallelBeamLineKernelProjector2D.h" +#include "astra/ParallelBeamLinearKernelProjector2D.h" +#include "astra/ParallelBeamStripKernelProjector2D.h" +#include "astra/ParallelProjectionGeometry2D.h" +#include "astra/VolumeGeometry2D.h" +#include "astra/ProjectionGeometry2D.h" + +#include <ctime> + +using astra::float32; + +struct TestParallelBeamLinearKernelProjector2D { + TestParallelBeamLinearKernelProjector2D() + { + astra::float32 angles[] = { 2.6f }; + BOOST_REQUIRE( projGeom.initialize(1, 3, 1.0f, angles) ); + BOOST_REQUIRE( volGeom.initialize(3, 2) ); + BOOST_REQUIRE( proj.initialize(&projGeom, &volGeom) ); + } + ~TestParallelBeamLinearKernelProjector2D() + { + + } + + astra::CParallelBeamLinearKernelProjector2D proj; + astra::CParallelProjectionGeometry2D projGeom; + astra::CVolumeGeometry2D volGeom; +}; + +BOOST_FIXTURE_TEST_CASE( testParallelBeamLinearKernelProjector2D_General, TestParallelBeamLinearKernelProjector2D ) +{ + +} + + +// Compute linear kernel for a single volume pixel/detector pixel combination +float32 compute_linear_kernel(const astra::CProjectionGeometry2D& projgeom, const astra::CVolumeGeometry2D& volgeom, + int iX, int iY, int iDet, float32 fAngle) +{ + // projection of center of volume pixel on detector array + float32 fDetProj = (iX - (volgeom.getGridColCount()-1.0f)/2.0f ) * volgeom.getPixelLengthX() * cos(fAngle) - (iY - (volgeom.getGridRowCount()-1.0f)/2.0f ) * volgeom.getPixelLengthY() * sin(fAngle); + + // start of detector pixel on detector array + float32 fDetStart = projgeom.indexToDetectorOffset(iDet) - 0.5f; + +// printf("(%d,%d,%d): %f in (%f,%f)\n", iX,iY,iDet,fDetProj, fDetStart, fDetStart+1.0f); + + // projection of center of next volume pixel on detector array + float32 fDetStep; + // length of projection ray through volume pixel + float32 fWeight; + + if (fabs(cos(fAngle)) > fabs(sin(fAngle))) { + fDetStep = volgeom.getPixelLengthY() * fabs(cos(fAngle)); + fWeight = volgeom.getPixelLengthX() * 1.0f / fabs(cos(fAngle)); + } else { + fDetStep = volgeom.getPixelLengthX() * fabs(sin(fAngle)); + fWeight = volgeom.getPixelLengthY() * 1.0f / fabs(sin(fAngle)); + } + +// printf("step: %f\n weight: %f\n", fDetStep, fWeight); + + // center of detector pixel on detector array + float32 fDetCenter = fDetStart + 0.5f; + + // unweighted contribution of this volume pixel: + // linear interpolation between + // fDetCenter - fDetStep |---> 0 + // fDetCenter |---> 1 + // fDetCenter + fDetStep |---> 0 + float32 fBase; + if (fDetCenter <= fDetProj) { + fBase = (fDetCenter - (fDetProj - fDetStep))/fDetStep; + } else { + fBase = ((fDetProj + fDetStep) - fDetCenter)/fDetStep; + } +// printf("base: %f\n", fBase); + if (fBase < 0) fBase = 0; + return fBase * fWeight; +} + +BOOST_AUTO_TEST_CASE( testParallelBeamLinearKernelProjector2D_Rectangles ) +{ + astra::CParallelBeamLinearKernelProjector2D proj; + astra::CParallelProjectionGeometry2D projGeom; + astra::CVolumeGeometry2D volGeom; + + const unsigned int iRandomTestCount = 100; + + unsigned int iSeed = time(0); + srand(iSeed); + + for (unsigned int iTest = 0; iTest < iRandomTestCount; ++iTest) { + int iDetectorCount = 1 + (rand() % 100); + int iRows = 1 + (rand() % 100); + int iCols = 1 + (rand() % 100); + + + astra::float32 angles[] = { rand() * 2.0f*astra::PI / RAND_MAX }; + projGeom.initialize(1, iDetectorCount, 0.8f, angles); + volGeom.initialize(iCols, iRows); + proj.initialize(&projGeom, &volGeom); + + int iMax = proj.getProjectionWeightsCount(0); + BOOST_REQUIRE(iMax > 0); + + astra::SPixelWeight* pPix = new astra::SPixelWeight[iMax]; + BOOST_REQUIRE(pPix); + + astra::float32 fWeight = 0; + for (int iDet = 0; iDet < projGeom.getDetectorCount(); ++iDet) { + int iCount; + proj.computeSingleRayWeights(0, iDet, pPix, iMax, iCount); + BOOST_REQUIRE(iCount <= iMax); + + astra::float32 fW = 0; + for (int i = 0; i < iCount; ++i) { + float32 fTest = compute_linear_kernel( + projGeom, + volGeom, + pPix[i].m_iIndex % volGeom.getGridColCount(), + pPix[i].m_iIndex / volGeom.getGridColCount(), + iDet, + projGeom.getProjectionAngle(0)); + BOOST_CHECK_SMALL( pPix[i].m_fWeight - fTest, 0.00037f); + fW += pPix[i].m_fWeight; + } + + fWeight += fW; + + } + + delete[] pPix; + } +} + + diff --git a/tests/test_ParallelProjectionGeometry2D.cpp b/tests/test_ParallelProjectionGeometry2D.cpp new file mode 100644 index 0000000..809c6fa --- /dev/null +++ b/tests/test_ParallelProjectionGeometry2D.cpp @@ -0,0 +1,120 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/ParallelProjectionGeometry2D.h" + +BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Constructor ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CParallelProjectionGeometry2D geom(4, 8, 0.5f, angles); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.getProjectionAngleCount() == 4 ); + BOOST_CHECK( geom.getDetectorCount() == 8 ); + BOOST_CHECK( geom.getDetectorWidth() == 0.5f ); + BOOST_CHECK( geom.getProjectionAngle(0) == 0.0f ); + BOOST_CHECK( geom.getProjectionAngle(1) == 1.0f ); + BOOST_CHECK( geom.getProjectionAngle(2) == 2.0f ); + BOOST_CHECK( geom.getProjectionAngle(3) == 3.0f ); + BOOST_CHECK( geom.getProjectionAngles()[0] == 0.0f ); + BOOST_CHECK( geom.getProjectionAngles()[3] == 3.0f ); +} + +BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Offsets ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CParallelProjectionGeometry2D geom(4, 8, 0.5f, angles); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK_SMALL( geom.getProjectionAngleDegrees(2) - 114.59155902f, 1e-5f ); + + BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.0f) == 3.5f ); + BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.625f) == 4.75f ); + BOOST_CHECK( geom.detectorOffsetToIndex(-0.1f) == 3 ); + + BOOST_CHECK( geom.indexToDetectorOffset(0) == -1.75f ); + BOOST_CHECK( geom.indexToDetectorOffset(1) == -1.25f ); + + int angle, detector; + geom.indexToAngleDetectorIndex(10, angle, detector); + BOOST_CHECK( angle == 1 ); + BOOST_CHECK( detector == 2 ); + + float t, theta; + geom.getRayParams(1, 2, t, theta); + BOOST_CHECK( theta == 1.0f ); + BOOST_CHECK( t == -0.75f ); + + // TODO: add test with large angle +} + +BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Offsets_odd ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CParallelProjectionGeometry2D geom(4, 7, 0.5f, angles); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.0f) == 3.0f ); + BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.625f) == 4.25f ); +} + + +BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Clone ) +{ + astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f }; + astra::CParallelProjectionGeometry2D geom(4, 8, 0.5f, angles); + + BOOST_REQUIRE( geom.isInitialized() ); + + astra::CProjectionGeometry2D* geom2 = geom.clone(); + + BOOST_REQUIRE( geom2->isInitialized() ); + + BOOST_CHECK( geom.isEqual(geom2) ); + BOOST_CHECK( geom2->getProjectionAngleCount() == 4 ); + BOOST_CHECK( geom2->getDetectorCount() == 8 ); + BOOST_CHECK( geom2->getDetectorWidth() == 0.5f ); + BOOST_CHECK( geom2->getProjectionAngle(0) == 0.0f ); + BOOST_CHECK( geom2->getProjectionAngle(1) == 1.0f ); + BOOST_CHECK( geom2->getProjectionAngle(2) == 2.0f ); + BOOST_CHECK( geom2->getProjectionAngle(3) == 3.0f ); + BOOST_CHECK( geom2->getProjectionAngles()[0] == 0.0f ); + BOOST_CHECK( geom2->getProjectionAngles()[3] == 3.0f ); + delete geom2; +} + diff --git a/tests/test_VolumeGeometry2D.cpp b/tests/test_VolumeGeometry2D.cpp new file mode 100644 index 0000000..4ae88d3 --- /dev/null +++ b/tests/test_VolumeGeometry2D.cpp @@ -0,0 +1,150 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_case_template.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include "astra/VolumeGeometry2D.h" + +BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Constructor1 ) +{ + astra::CVolumeGeometry2D geom(16, 32); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.getGridColCount() == 16 ); + BOOST_CHECK( geom.getGridRowCount() == 32 ); + BOOST_CHECK( geom.getGridTotCount() == 512 ); + BOOST_CHECK( geom.getWindowLengthX() == 16.0f ); + BOOST_CHECK( geom.getWindowLengthY() == 32.0f ); + BOOST_CHECK( geom.getWindowArea() == 512.0f ); + BOOST_CHECK( geom.getPixelLengthX() == 1.0f ); + BOOST_CHECK( geom.getPixelLengthY() == 1.0f ); + BOOST_CHECK( geom.getPixelArea() == 1.0f ); + BOOST_CHECK( geom.getWindowMinX() == -8.0f ); + BOOST_CHECK( geom.getWindowMaxX() == 8.0f ); + BOOST_CHECK( geom.getWindowMinY() == -16.0f ); + BOOST_CHECK( geom.getWindowMaxY() == 16.0f ); +} + +BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Constructor1odd ) +{ + astra::CVolumeGeometry2D geom(5, 7); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.getGridColCount() == 5 ); + BOOST_CHECK( geom.getGridRowCount() == 7 ); + BOOST_CHECK( geom.getGridTotCount() == 35 ); + BOOST_CHECK( geom.getWindowLengthX() == 5.0f ); + BOOST_CHECK( geom.getWindowLengthY() == 7.0f ); + BOOST_CHECK( geom.getWindowArea() == 35.0f ); + BOOST_CHECK( geom.getPixelLengthX() == 1.0f ); + BOOST_CHECK( geom.getPixelLengthY() == 1.0f ); + BOOST_CHECK( geom.getPixelArea() == 1.0f ); + BOOST_CHECK( geom.getWindowMinX() == -2.5f ); + BOOST_CHECK( geom.getWindowMaxX() == 2.5f ); + BOOST_CHECK( geom.getWindowMinY() == -3.5f ); + BOOST_CHECK( geom.getWindowMaxY() == 3.5f ); +} + +BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Constructor2 ) +{ + astra::CVolumeGeometry2D geom(16, 32, -1.0f, -2.0f, 3.0f, 4.0f); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.getGridColCount() == 16 ); + BOOST_CHECK( geom.getGridRowCount() == 32 ); + BOOST_CHECK( geom.getGridTotCount() == 512 ); + BOOST_CHECK( geom.getWindowLengthX() == 4.0f ); + BOOST_CHECK( geom.getWindowLengthY() == 6.0f ); + BOOST_CHECK( geom.getWindowArea() == 24.0f ); + BOOST_CHECK( geom.getPixelLengthX() == 0.25f ); + BOOST_CHECK( geom.getPixelLengthY() == 0.1875f ); + BOOST_CHECK( geom.getPixelArea() == 0.046875f ); + BOOST_CHECK( geom.getWindowMinX() == -1.0f ); + BOOST_CHECK( geom.getWindowMaxX() == 3.0f ); + BOOST_CHECK( geom.getWindowMinY() == -2.0f ); + BOOST_CHECK( geom.getWindowMaxY() == 4.0f ); +} + +BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Clone ) +{ + astra::CVolumeGeometry2D geom(16, 32, -1.0f, -2.0f, 3.0f, 4.0f); + + astra::CVolumeGeometry2D* geom2 = geom.clone(); + + BOOST_REQUIRE( geom2->isInitialized() ); + + BOOST_CHECK( geom.isEqual(geom2) ); + BOOST_CHECK( geom2->getGridColCount() == 16 ); + BOOST_CHECK( geom2->getGridRowCount() == 32 ); + BOOST_CHECK( geom2->getGridTotCount() == 512 ); + BOOST_CHECK( geom2->getWindowLengthX() == 4.0f ); + BOOST_CHECK( geom2->getWindowLengthY() == 6.0f ); + BOOST_CHECK( geom2->getWindowArea() == 24.0f ); + BOOST_CHECK( geom2->getPixelLengthX() == 0.25f ); + BOOST_CHECK( geom2->getPixelLengthY() == 0.1875f ); + BOOST_CHECK( geom2->getPixelArea() == 0.046875f ); + BOOST_CHECK( geom2->getWindowMinX() == -1.0f ); + BOOST_CHECK( geom2->getWindowMaxX() == 3.0f ); + BOOST_CHECK( geom2->getWindowMinY() == -2.0f ); + BOOST_CHECK( geom2->getWindowMaxY() == 4.0f ); + + delete geom2; +} + +BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Offsets ) +{ + astra::CVolumeGeometry2D geom(16, 32, -1.0f, -2.0f, 3.0f, 4.0f); + + BOOST_REQUIRE( geom.isInitialized() ); + + BOOST_CHECK( geom.pixelRowColToIndex(1,2) == 18 ); + + int r,c; + geom.pixelIndexToRowCol(66, r, c); + BOOST_CHECK( r == 4 ); + BOOST_CHECK( c == 2 ); + + BOOST_CHECK( geom.pixelColToCenterX(2) == -0.375f ); + BOOST_CHECK( geom.pixelColToMinX(2) == -0.5f ); + BOOST_CHECK( geom.pixelColToMaxX(2) == -0.25f ); + + BOOST_CHECK( geom.pixelRowToCenterY(29) == -1.53125f ); + BOOST_CHECK( geom.pixelRowToMinY(29) == -1.625f ); + BOOST_CHECK( geom.pixelRowToMaxY(29) == -1.4375f ); + + BOOST_CHECK( geom.coordXToCol(0.1f) == 4 ); + BOOST_CHECK( geom.coordYToRow(0.1f) == 20 ); +} diff --git a/tests/test_XMLDocument.cpp b/tests/test_XMLDocument.cpp new file mode 100644 index 0000000..adabdd6 --- /dev/null +++ b/tests/test_XMLDocument.cpp @@ -0,0 +1,158 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). + +The ASTRA Toolbox is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The ASTRA Toolbox is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +$Id$ +*/ + + +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/test/auto_unit_test.hpp> + +#include "astra/XMLDocument.h" + +BOOST_AUTO_TEST_CASE( testXMLDocument_Constructor1 ) +{ + astra::XMLDocument *doc = astra::XMLDocument::createDocument("test"); + BOOST_REQUIRE(doc); + + astra::XMLNode *root = doc->getRootNode(); + + BOOST_REQUIRE(root); + + BOOST_CHECK(root->getName() == "test"); + BOOST_CHECK(root->getContent().empty()); +} + +BOOST_AUTO_TEST_CASE( testXMLDocument_FileIO ) +{ + astra::XMLDocument *doc = astra::XMLDocument::createDocument("test"); + + doc->saveToFile("test.xml"); + + astra::XMLDocument *doc2 = astra::XMLDocument::readFromFile("test.xml"); + astra::XMLNode *root = doc2->getRootNode(); + + BOOST_REQUIRE(root); + + BOOST_CHECK(root->getName() == "test"); + BOOST_CHECK(root->getContent().empty()); + +} + +BOOST_AUTO_TEST_CASE( testXMLDocument_CreateNodes ) +{ + astra::XMLDocument *doc = astra::XMLDocument::createDocument("test"); + BOOST_REQUIRE(doc); + + astra::XMLNode *root = doc->getRootNode(); + BOOST_REQUIRE(root); + + astra::XMLNode *node = root->addChildNode("child"); + BOOST_REQUIRE(node); + + node->addAttribute("attr", "val"); + + doc->saveToFile("test2.xml"); + + delete node; + delete root; + delete doc; + + doc = astra::XMLDocument::readFromFile("test2.xml"); + BOOST_REQUIRE(doc); + root = doc->getRootNode(); + BOOST_REQUIRE(node); + node = root->getSingleNode("child"); + BOOST_REQUIRE(node); + + BOOST_CHECK(node->hasAttribute("attr")); + BOOST_CHECK(node->getAttribute("attr") == "val"); + + delete node; + delete root; + delete doc; +} + +BOOST_AUTO_TEST_CASE( testXMLDocument_Options ) +{ + astra::XMLDocument *doc = astra::XMLDocument::createDocument("test"); + BOOST_REQUIRE(doc); + + astra::XMLNode *root = doc->getRootNode(); + BOOST_REQUIRE(root); + + BOOST_CHECK(!root->hasOption("opt")); + + root->addOption("opt", "val"); + + BOOST_CHECK(root->hasOption("opt")); + + BOOST_CHECK(root->getOption("opt") == "val"); + +} + +BOOST_AUTO_TEST_CASE( testXMLDocument_List ) +{ + astra::XMLDocument *doc = astra::XMLDocument::createDocument("test"); + BOOST_REQUIRE(doc); + + astra::XMLNode *root = doc->getRootNode(); + BOOST_REQUIRE(root); + + astra::XMLNode *node = root->addChildNode("child"); + BOOST_REQUIRE(node); + + + float fl[] = { 1.0, 3.5, 2.0, 4.75 }; + + node->setContent(fl, sizeof(fl)/sizeof(fl[0])); + + doc->saveToFile("test3.xml"); + + delete node; + delete root; + delete doc; + + doc = astra::XMLDocument::readFromFile("test3.xml"); + BOOST_REQUIRE(doc); + root = doc->getRootNode(); + BOOST_REQUIRE(root); + node = root->getSingleNode("child"); + BOOST_REQUIRE(node); + + std::vector<astra::float32> f = node->getContentNumericalArray(); + + BOOST_CHECK(f[0] == fl[0]); + BOOST_CHECK(f[1] == fl[1]); + BOOST_CHECK(f[2] == fl[2]); + BOOST_CHECK(f[3] == fl[3]); + + delete node; + delete root; + delete doc; + +} + diff --git a/tests/tests_vc08.vcproj b/tests/tests_vc08.vcproj new file mode 100644 index 0000000..90c5d55 --- /dev/null +++ b/tests/tests_vc08.vcproj @@ -0,0 +1,699 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="tests" + ProjectGUID="{32C1BDD3-38C2-4C80-A03C-2129782F59B5}" + RootNamespace="tests" + Keyword="Win32Proj" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="true" + BasicRuntimeChecks="0" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32D.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32" + GenerateDebugInformation="true" + SubSystem="1" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug|x64" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="true" + BasicRuntimeChecks="0" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64D.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64" + GenerateDebugInformation="true" + SubSystem="1" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra32.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="Astra64.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|Win32" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="true" + BasicRuntimeChecks="0" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32D.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32" + GenerateDebugInformation="true" + SubSystem="1" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Debug_CUDA|x64" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="true" + BasicRuntimeChecks="0" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64D.lib" + LinkIncremental="2" + AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64" + GenerateDebugInformation="true" + SubSystem="1" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|Win32" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda32.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release_CUDA|x64" + OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(OutDir)\obj\" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\lib\include\;..\include\" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="AstraCuda64.lib" + LinkIncremental="1" + AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Test Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\test_FanFlatProjectionGeometry2D.cpp" + > + </File> + <File + RelativePath=".\test_Float32Data2D.cpp" + > + </File> + <File + RelativePath=".\test_Float32ProjectionData2D.cpp" + > + </File> + <File + RelativePath=".\test_Float32VolumeData2D.cpp" + > + </File> + <File + RelativePath=".\test_Fourier.cpp" + > + </File> + <File + RelativePath=".\test_ParallelBeamLinearKernelProjector2D.cpp" + > + </File> + <File + RelativePath=".\test_ParallelBeamLineKernelProjector2D.cpp" + > + </File> + <File + RelativePath=".\test_ParallelProjectionGeometry2D.cpp" + > + </File> + <File + RelativePath=".\test_VolumeGeometry2D.cpp" + > + </File> + </Filter> + <Filter + Name="Main" + > + <File + RelativePath=".\main.cpp" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> |