├── .github ├── build.sh ├── setup.sh └── workflows │ ├── build-main.yml │ └── build-pr.yml ├── .gitignore ├── LICENSE ├── LICENSE.txt ├── README.md ├── build.sh ├── pom.xml └── src └── main ├── java └── net │ └── preibisch │ └── simulation │ ├── Hessian.java │ ├── HypersphereCollectionRealRandomAccessible.java │ ├── NumberGeneratorImage.java │ ├── PerlinNoiseRealRandomAccessible.java │ ├── PointRejectionSampling.java │ ├── RegularTranformHelpers.java │ ├── SimpleCalculatedRealRandomAccessible.java │ ├── SimulateBeads.java │ ├── SimulateBeads2.java │ ├── SimulateMultiViewAberrations.java │ ├── SimulateMultiViewDataset.java │ ├── SimulateTileStitching.java │ ├── Tools.java │ ├── VolumeInjection.java │ ├── cluster │ ├── CreateScripts.java │ └── RunJob.java │ ├── imgloader │ ├── LegacySimulatedBeadsImgLoader.java │ ├── LegacySimulatedBeadsImgLoader2.java │ ├── SimulatedBeadsImgLoader.java │ ├── SimulatedBeadsImgLoader2.java │ └── XmlIoSimulatedBeadsImgLoader.java │ ├── raytracing │ ├── ClearingMap.java │ ├── Lightsheet.java │ ├── RayTracingTest.java │ ├── Raytrace.java │ └── RefractiveIndexMap.java │ └── uncommons │ ├── ConstantGenerator.java │ ├── NumberGenerator.java │ └── PoissonGenerator.java └── resources ├── Angle0.tif ├── Angle104.tif ├── Angle120.tif ├── Angle135.tif ├── Angle156.tif ├── Angle180.tif ├── Angle208.tif ├── Angle225.tif ├── Angle240.tif ├── Angle260.tif ├── Angle270.tif ├── Angle300.tif ├── Angle312.tif ├── Angle315.tif ├── Angle45.tif ├── Angle52.tif ├── Angle60.tif └── Angle90.tif /.github/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/master/ci-build.sh 3 | sh ci-build.sh 4 | -------------------------------------------------------------------------------- /.github/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | curl -fsLO https://raw.githubusercontent.com/scijava/scijava-scripts/master/ci-setup-github-actions.sh 3 | sh ci-setup-github-actions.sh 4 | -------------------------------------------------------------------------------- /.github/workflows/build-main.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - "*-[0-9]+.*" 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up Java 17 | uses: actions/setup-java@v3 18 | with: 19 | java-version: '8' 20 | distribution: 'zulu' 21 | cache: 'maven' 22 | - name: Set up CI environment 23 | run: .github/setup.sh 24 | - name: Execute the build 25 | run: .github/build.sh 26 | env: 27 | GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }} 28 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 29 | MAVEN_USER: ${{ secrets.MAVEN_USER }} 30 | MAVEN_PASS: ${{ secrets.MAVEN_PASS }} 31 | OSSRH_PASS: ${{ secrets.OSSRH_PASS }} 32 | SIGNING_ASC: ${{ secrets.SIGNING_ASC }} 33 | -------------------------------------------------------------------------------- /.github/workflows/build-pr.yml: -------------------------------------------------------------------------------- 1 | name: build PR 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up Java 15 | uses: actions/setup-java@v3 16 | with: 17 | java-version: '8' 18 | distribution: 'zulu' 19 | cache: 'maven' 20 | - name: Set up CI environment 21 | run: .github/setup.sh 22 | - name: Execute the build 23 | run: .github/build.sh 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .DS_STORE 3 | .classpath 4 | .project 5 | /target 6 | /.settings 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://github.com/PreibischLab/multiview-simulation/actions/workflows/build-main.yml/badge.svg)](https://github.com/PreibischLab/multiview-simulation/actions/workflows/build-main.yml) 2 | 3 | multiview-simulation 4 | ==================== 5 | 6 | Code for simulating a multi-view acquisition including attenuation, convolution, reduced axial sampling and poission noise. It is implemented in ImgLib2 (http://bioinformatics.oxfordjournals.org/cgi/pmidlookup?view=long&pmid=22962343, https://github.com/imglib/imglib). 7 | 8 | For more details please check the corresponding publication: "Efficient Bayesian-based multiview deconvolution" http://www.nature.com/nmeth/journal/v11/n6/full/nmeth.2929.html 9 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | mvn clean compile assembly:single 2 | 3 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.scijava 7 | pom-scijava 8 | 31.1.0 9 | 10 | 11 | 12 | net.preibisch 13 | multiview-simulation 14 | 0.2.3-SNAPSHOT 15 | 16 | Multiview Simulation 17 | Library for simulating a multi-view acquisition including 18 | attenuation, convolution, reduced sampling and poission noise. 19 | https://github.com/PreibischLab/multiview-simulation 20 | 2014 21 | 22 | Preibisch Lab 23 | http://preibischlab.mdc-berlin.de 24 | 25 | 26 | 27 | GNU General Public License v2+ 28 | https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html 29 | repo 30 | 31 | 32 | 33 | 34 | 35 | StephanPreibisch 36 | Stephan Preibisch 37 | https://imagej.net/people/StephanPreibisch 38 | 39 | founder 40 | lead 41 | developer 42 | debugger 43 | reviewer 44 | support 45 | maintainer 46 | 47 | 48 | 49 | hoerldavid 50 | David Hoerl 51 | https://imagej.net/people/hoerldavid 52 | 53 | developer 54 | debugger 55 | reviewer 56 | support 57 | maintainer 58 | 59 | 60 | 61 | 62 | 63 | Curtis Rueden 64 | https://imagej.net/people/ctrueden 65 | ctrueden 66 | 67 | 68 | 69 | 70 | 71 | Image.sc Forum 72 | https://forum.image.sc/tag/multiview-simulation 73 | 74 | 75 | 76 | 77 | scm:git:https://github.com/PreibischLab/multiview-simulation 78 | scm:git:git@github.com:PreibischLab/multiview-simulation 79 | HEAD 80 | https://github.com/PreibischLab/multiview-simulation 81 | 82 | 83 | GitHub Issues 84 | https://github.com/PreibischLab/multiview-simulation/issues 85 | 86 | 87 | GitHub Actions 88 | https://github.com/PreibischLab/multiview-simulation/actions 89 | 90 | 91 | 92 | net.preibisch.simulation 93 | 94 | gpl_v2 95 | Multiview Simulation developers. 96 | 97 | 98 | sign,deploy-to-scijava 99 | 100 | 101 | 102 | 103 | scijava.public 104 | https://maven.scijava.org/content/groups/public 105 | 106 | 107 | 108 | 109 | 110 | net.imglib2 111 | imglib2-ij 112 | 113 | 114 | net.imglib2 115 | imglib2-algorithm 116 | 117 | 118 | net.imglib2 119 | imglib2-realtransform 120 | 121 | 122 | mpicbg 123 | mpicbg 124 | 125 | 126 | net.imglib2 127 | imglib2-algorithm-gpl 128 | 129 | 130 | sc.fiji 131 | spim_data 132 | 133 | 134 | 135 | 136 | ome 137 | formats-api 138 | 139 | 140 | ome 141 | formats-bsd 142 | 143 | 144 | ome 145 | formats-gpl 146 | 147 | 148 | ch.systems.cisd 149 | jhdf5 150 | 151 | 152 | 153 | 154 | org.openmicroscopy 155 | ome-xml 156 | 157 | 158 | org.openmicroscopy 159 | ome-common 160 | 161 | 162 | 163 | 164 | 165 | 166 | maven-assembly-plugin 167 | 168 | 169 | 170 | net.preibisch.simulation.cluster.RunJob 171 | 172 | 173 | 174 | jar-with-dependencies 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/Hessian.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation; 2 | 3 | import Jama.EigenvalueDecomposition; 4 | import Jama.Matrix; 5 | import net.imglib2.Cursor; 6 | import net.imglib2.Positionable; 7 | import net.imglib2.RandomAccess; 8 | import net.imglib2.RandomAccessibleInterval; 9 | import net.imglib2.Sampler; 10 | import net.imglib2.algorithm.gauss3.Gauss3; 11 | import net.imglib2.img.Img; 12 | import net.imglib2.img.array.ArrayImgFactory; 13 | import net.imglib2.type.numeric.real.FloatType; 14 | import net.imglib2.util.Pair; 15 | import net.imglib2.util.ValuePair; 16 | import net.imglib2.view.Views; 17 | 18 | public class Hessian 19 | { 20 | /** 21 | * @param randomAccessible 22 | * @return - the Math.abs( largest ) eigenvalue as n-dim image (A), and the corresponding eigenvector as (n+1)-dim image (B) 23 | */ 24 | public static Pair< Img< FloatType >, Img< FloatType > > largestEigenVector( final RandomAccessibleInterval< FloatType > randomAccessible ) 25 | { 26 | final int n = randomAccessible.numDimensions(); 27 | 28 | // blur a bit 29 | Gauss3.gauss( 1.0, Views.extendMirrorSingle( randomAccessible ), randomAccessible ); 30 | 31 | final long[] dimEigenValue = new long[ n ]; 32 | randomAccessible.dimensions( dimEigenValue ); 33 | 34 | final long[] dimEigenVector = new long[ n + 1 ]; 35 | 36 | for ( int d = 0; d < n; ++d ) 37 | dimEigenVector[ d ] = dimEigenValue[ d ]; 38 | 39 | dimEigenVector[ n ] = 3; // vector 40 | 41 | final Img< FloatType > eigenVec = new ArrayImgFactory<>( new FloatType() ).create( dimEigenVector ); 42 | final Img< FloatType > eigenVal = new ArrayImgFactory<>( new FloatType() ).create( dimEigenValue ); 43 | 44 | final double[][] matrix = new double[ 3 ][ 3 ]; // row, column 45 | final double[] eigenVector = new double[ 3 ]; 46 | 47 | final Cursor< FloatType > cursor = Views.iterable( randomAccessible ).localizingCursor(); 48 | final RandomAccess< FloatType > raEVal = eigenVal.randomAccess(); 49 | final RandomAccess< FloatType > raEVec = eigenVec.randomAccess(); 50 | final long[] posN = new long[ eigenVec.numDimensions() ]; 51 | 52 | final RandomAccess< FloatType > ra = Views.extendMirrorSingle( randomAccessible ).randomAccess(); 53 | 54 | while ( cursor.hasNext() ) 55 | { 56 | cursor.fwd(); 57 | cursor.localize( posN ); 58 | posN[ n ] = 0; // n+1 dim 59 | 60 | ra.setPosition( cursor ); 61 | 62 | computeHessianMatrix3D( ra, matrix ); 63 | 64 | final double eigenValue = computeLargestEigenVectorAndValue3d( matrix, eigenVector ); 65 | 66 | raEVec.setPosition( posN ); 67 | raEVec.get().set( (float)eigenVector[ 0 ] ); 68 | 69 | raEVec.fwd( n ); 70 | raEVec.get().set( (float)eigenVector[ 1 ] ); 71 | 72 | raEVec.fwd( n ); 73 | raEVec.get().set( (float)eigenVector[ 2 ] ); 74 | 75 | raEVal.setPosition( cursor ); 76 | raEVal.get().set( (float)eigenValue ); 77 | } 78 | 79 | return new ValuePair< Img, Img >( eigenVal, eigenVec ); 80 | } 81 | 82 | /** 83 | * 84 | * @param hessianMatrix 85 | * @param eigenVector - fills up the eigenvector 86 | * @return eigenvalue 87 | */ 88 | public static double computeLargestEigenVectorAndValue3d( final double[][] hessianMatrix, final double[] eigenVector ) 89 | { 90 | final Matrix m = new Matrix( hessianMatrix ); 91 | final EigenvalueDecomposition evDec = new EigenvalueDecomposition( m ); 92 | 93 | final double[] result = evDec.getImagEigenvalues(); 94 | 95 | for ( int i = 0; i < result.length; ++i ) 96 | if ( result[i] > 0 ) 97 | { 98 | // found imaginary parts 99 | eigenVector[ 0 ] = 1; 100 | eigenVector[ 1 ] = eigenVector[ 2 ] = 0; 101 | return 0; 102 | } 103 | 104 | final double[] ev = evDec.getRealEigenvalues(); 105 | 106 | int biggestEigenValueIndex = 0; 107 | double biggestEigenValue = ev[ 0 ]; 108 | 109 | for ( int i = 1; i < ev.length; ++i ) 110 | { 111 | if ( Math.abs( ev[ i ] ) > Math.abs( biggestEigenValue ) ) 112 | { 113 | biggestEigenValue = ev[ i ]; 114 | biggestEigenValueIndex = i; 115 | } 116 | } 117 | 118 | final Matrix evec = evDec.getV(); 119 | 120 | eigenVector[ 0 ] = evec.get( 0, biggestEigenValueIndex ); 121 | eigenVector[ 1 ] = evec.get( 1, biggestEigenValueIndex ); 122 | eigenVector[ 2 ] = evec.get( 2, biggestEigenValueIndex ); 123 | 124 | return biggestEigenValue; 125 | } 126 | 127 | /** 128 | * computes the Hessian Matrix in local 3x3x3 environment. Works with RandomAccess and RealRandomAccess 129 | * 130 | * @param ra 131 | * @param hessianMatrix 132 | */ 133 | public static < A extends Positionable & Sampler< FloatType > > void computeHessianMatrix3D( final A ra, final double[][] hessianMatrix ) 134 | { 135 | final double temp = 2 * ra.get().get(); 136 | 137 | // xx 138 | //hessianMatrix[0][0] = img.get(x + 1, y, z) - temp + img.get(x - 1, y, z); 139 | ra.fwd( 0 ); 140 | hessianMatrix[0][0] = ra.get().get(); 141 | hessianMatrix[0][0] -= temp; 142 | ra.bck( 0 ); 143 | ra.bck( 0 ); 144 | hessianMatrix[0][0] += ra.get().get(); 145 | ra.fwd( 0 ); 146 | 147 | // yy 148 | //hessianMatrix[1][1] = img.get(x, y + 1, z) - temp + img.get(x, y - 1, z); 149 | ra.fwd( 1 ); 150 | hessianMatrix[1][1] = ra.get().get(); 151 | hessianMatrix[1][1] -= temp; 152 | ra.bck( 1 ); 153 | ra.bck( 1 ); 154 | hessianMatrix[1][1] += ra.get().get(); 155 | ra.fwd( 1 ); 156 | 157 | // zz 158 | //hessianMatrix[2][2] = img.get(x, y, z + 1) - temp + img.get(x, y, z - 1); 159 | ra.fwd( 2 ); 160 | hessianMatrix[2][2] = ra.get().get(); 161 | hessianMatrix[2][2] -= temp; 162 | ra.bck( 2 ); 163 | ra.bck( 2 ); 164 | hessianMatrix[2][2] += ra.get().get(); 165 | ra.fwd( 2 ); 166 | 167 | // xy 168 | ra.fwd( 0 ); 169 | ra.fwd( 1 ); 170 | double a = ra.get().get(); 171 | ra.bck( 0 ); 172 | ra.bck( 0 ); 173 | double b = ra.get().get(); 174 | ra.fwd( 0 ); 175 | ra.fwd( 0 ); 176 | ra.bck( 1 ); 177 | ra.bck( 1 ); 178 | double c = ra.get().get(); 179 | ra.bck( 0 ); 180 | ra.bck( 0 ); 181 | double d = ra.get().get(); 182 | ra.fwd( 0 ); 183 | ra.fwd( 1 ); 184 | 185 | hessianMatrix[0][1] = hessianMatrix[1][0] = 186 | ( 187 | (a - b) / 2 188 | - 189 | (c - d) / 2 190 | ) / 2; 191 | /*( 192 | (img.get(x + 1, y + 1, z) - img.get(x - 1, y + 1, z)) / 2 193 | - 194 | (img.get(x + 1, y - 1, z) - img.get(x - 1, y - 1, z)) / 2 195 | ) / 2;*/ 196 | 197 | // xz 198 | ra.fwd( 0 ); 199 | ra.fwd( 2 ); 200 | a = ra.get().get(); 201 | ra.bck( 0 ); 202 | ra.bck( 0 ); 203 | b = ra.get().get(); 204 | ra.fwd( 0 ); 205 | ra.fwd( 0 ); 206 | ra.bck( 2 ); 207 | ra.bck( 2 ); 208 | c = ra.get().get(); 209 | ra.bck( 0 ); 210 | ra.bck( 0 ); 211 | d = ra.get().get(); 212 | ra.fwd( 0 ); 213 | ra.fwd( 2 ); 214 | 215 | hessianMatrix[0][2] = hessianMatrix[2][0] = 216 | ( 217 | (a - b) / 2 218 | - 219 | (c - d) / 2 220 | ) / 2; 221 | /*( 222 | (img.get(x + 1, y, z + 1) - img.get(x - 1, y, z + 1)) / 2 223 | - 224 | (img.get(x + 1, y, z - 1) - img.get(x - 1, y, z - 1)) / 2 225 | ) / 2;*/ 226 | 227 | // yz 228 | ra.fwd( 1 ); 229 | ra.fwd( 2 ); 230 | a = ra.get().get(); 231 | ra.bck( 1 ); 232 | ra.bck( 1 ); 233 | b = ra.get().get(); 234 | ra.fwd( 1 ); 235 | ra.fwd( 1 ); 236 | ra.bck( 2 ); 237 | ra.bck( 2 ); 238 | c = ra.get().get(); 239 | ra.bck( 1 ); 240 | ra.bck( 1 ); 241 | d = ra.get().get(); 242 | ra.fwd( 1 ); 243 | ra.fwd( 2 ); 244 | 245 | hessianMatrix[1][2] = hessianMatrix[2][1] = 246 | ( 247 | (a - b) / 2 248 | - 249 | (c - d) / 2 250 | ) / 2; 251 | /*( 252 | (img.get(x, y + 1, z + 1) - img.get(x, y - 1, z + 1)) / 2 253 | - 254 | (img.get(x, y + 1, z - 1) - img.get(x, y - 1, z - 1)) / 2 255 | ) / 2;*/ 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/HypersphereCollectionRealRandomAccessible.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Random; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | import java.util.stream.Collectors; 11 | 12 | import ij.ImageJ; 13 | import net.imglib2.FinalInterval; 14 | import net.imglib2.KDTree; 15 | import net.imglib2.RealInterval; 16 | import net.imglib2.RealLocalizable; 17 | import net.imglib2.RealPoint; 18 | import net.imglib2.RealRandomAccess; 19 | import net.imglib2.RealRandomAccessible; 20 | import net.imglib2.Sampler; 21 | import net.imglib2.img.display.imagej.ImageJFunctions; 22 | import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; 23 | import net.imglib2.neighborsearch.RadiusNeighborSearchOnKDTree; 24 | import net.imglib2.realtransform.AffineGet; 25 | import net.imglib2.realtransform.AffineRealRandomAccessible; 26 | import net.imglib2.realtransform.RealViews; 27 | import net.imglib2.realtransform.Scale; 28 | import net.imglib2.realtransform.Scale3D; 29 | import net.imglib2.type.Type; 30 | import net.imglib2.type.numeric.real.FloatType; 31 | import net.imglib2.util.Util; 32 | import net.imglib2.view.IntervalView; 33 | import net.imglib2.view.Views; 34 | 35 | public class HypersphereCollectionRealRandomAccessible< T extends Type< T > > implements RealRandomAccessible< T > 36 | { 37 | 38 | final private T type; 39 | final private List< RealLocalizable > sphereCenters; 40 | final private List< T > sphereValues; 41 | final private List< Double > sphereRadii; 42 | final private int numDimensions; 43 | private KDTree< Integer > kdTree; 44 | private boolean kdNeedsUpdate; 45 | private double maxRadius; 46 | 47 | public HypersphereCollectionRealRandomAccessible(int numDimensions, T type) 48 | { 49 | this.type = type.copy(); 50 | this.numDimensions = numDimensions; 51 | sphereCenters = new ArrayList<>(); 52 | sphereRadii = new ArrayList<>(); 53 | sphereValues = new ArrayList<>(); 54 | kdNeedsUpdate = true; 55 | maxRadius = 0.0; 56 | } 57 | 58 | public HypersphereCollectionRealRandomAccessible(Collection< RealLocalizable > locations, Collection< Double > radii, Collection< T > values, T type) 59 | { 60 | this(locations.iterator().next().numDimensions(), type); 61 | Iterator< RealLocalizable > itLocations = locations.iterator(); 62 | Iterator< Double > itRadii = radii.iterator(); 63 | Iterator< T > itValues = values.iterator(); 64 | while(itLocations.hasNext()) 65 | addSphere( itLocations.next(), itRadii.next(), itValues.next()); 66 | } 67 | 68 | public void addSphere(RealLocalizable location, Double radius, T value) 69 | { 70 | sphereCenters.add( new RealPoint( location ) ); 71 | sphereRadii.add( radius ); 72 | sphereValues.add( value.copy() ); 73 | kdNeedsUpdate = true; 74 | maxRadius = Math.max( maxRadius, radius ); 75 | } 76 | 77 | private void prepareKDTree() 78 | { 79 | if (!kdNeedsUpdate) 80 | return; 81 | 82 | // the values of the KDTree nodes are just increasing indices 83 | // we will later use them to access radii, values, .. 84 | final AtomicInteger i = new AtomicInteger( 0 ); 85 | kdTree = new KDTree<>( sphereCenters.stream().map( (x) -> i.getAndIncrement() ).collect( Collectors.toList() ), sphereCenters ); 86 | kdNeedsUpdate = false; 87 | } 88 | 89 | @Override 90 | public int numDimensions() 91 | { 92 | return numDimensions; 93 | } 94 | 95 | @Override 96 | public RealRandomAccess< T > realRandomAccess() 97 | { 98 | prepareKDTree(); 99 | return new HypersphereCollectionRealRandomAccess(); 100 | } 101 | 102 | @Override 103 | public RealRandomAccess< T > realRandomAccess(RealInterval interval) 104 | { 105 | return realRandomAccess(); 106 | } 107 | 108 | private class HypersphereCollectionRealRandomAccess extends RealPoint implements RealRandomAccess< T > 109 | { 110 | 111 | final private T type; 112 | final private RadiusNeighborSearchOnKDTree< Integer > rs; 113 | 114 | public HypersphereCollectionRealRandomAccess() 115 | { 116 | super(numDimensions); 117 | this.type = HypersphereCollectionRealRandomAccessible.this.type.copy(); 118 | this.rs = new RadiusNeighborSearchOnKDTree<>( kdTree ); 119 | } 120 | 121 | @Override 122 | public T get() 123 | { 124 | rs.search( this, maxRadius, false ); 125 | 126 | if (rs.numNeighbors() < 1) 127 | { 128 | type.set( HypersphereCollectionRealRandomAccessible.this.type ); 129 | } 130 | else 131 | { 132 | boolean found = false; 133 | int minI = Integer.MAX_VALUE; 134 | for (int i=0; i copy() 154 | { 155 | return copyRealRandomAccess(); 156 | } 157 | 158 | @Override 159 | public RealRandomAccess< T > copyRealRandomAccess() 160 | { 161 | return new HypersphereCollectionRealRandomAccess(); 162 | } 163 | 164 | } 165 | 166 | public static void main(String[] args) 167 | { 168 | final Random rnd = new Random( 42 ); 169 | 170 | long[] dim = new long[]{1024, 1024, 256}; 171 | 172 | int nBigSpheres = 400; 173 | float minRadiusBig = 20; 174 | float maxRadiusBig = 40; 175 | float minValueBig = 1.2f; 176 | float maxValueBig = 2.4f; 177 | 178 | int nSmallSamples = 20000; 179 | float minRadiusSmall = 2; 180 | float maxRadiusSmall = 4; 181 | float minValueSmall = 4.0f; 182 | float maxValueSmall = 6.0f; 183 | 184 | 185 | List bigSphereRadii = new ArrayList<>(); 186 | 187 | RealRandomAccessible< FloatType > rrablePerlin = new PerlinNoiseRealRandomAccessible<>( new FloatType(), new double[] {dim[0]/4,dim[1]/1.5,dim[2]}, new int[] {15, 15, 15}, 100, rnd ); 188 | RealRandomAccessible< FloatType > rrablePerlinThrd = new SimpleCalculatedRealRandomAccessible( new FloatType(), (a,b) -> { 189 | a.setReal( b.iterator().next().get() > 0.1 ? 1.0 : 0); 190 | }, rrablePerlin); 191 | 192 | List< RealPoint > bigSpherePositions = PointRejectionSampling.sampleRealPoints( new FinalInterval( dim ), nBigSpheres, rrablePerlinThrd, rnd ); 193 | HypersphereCollectionRealRandomAccessible< FloatType > rrableDensity = new HypersphereCollectionRealRandomAccessible<>( dim.length, new FloatType() ); 194 | for (int i=0; i rrableBigPoints = new HypersphereCollectionRealRandomAccessible<>( dim.length, new FloatType() ); 205 | HypersphereCollectionRealRandomAccessible< FloatType > rrableSmallPoints = new HypersphereCollectionRealRandomAccessible<>( dim.length, new FloatType() ); 206 | List< RealPoint > smallPoints = PointRejectionSampling.sampleRealPoints( new FinalInterval( dim ), nSmallSamples, rrableDensity, rnd ); 207 | 208 | for (final RealPoint sp : smallPoints) 209 | { 210 | rrableSmallPoints.addSphere( 211 | sp, 212 | minRadiusSmall + rnd.nextDouble() * (maxRadiusSmall - minRadiusSmall), 213 | new FloatType((float) ( minValueSmall + rnd.nextDouble() * (maxValueSmall - minValueSmall) )) ); 214 | } 215 | 216 | for (int i=0; i perlinScaled = Views.interval( Views.raster( RealViews.affineReal( rrablePerlinThrd, scalePerlin.inverse() ) ), new FinalInterval( new long[]{dim[0]/4, dim[1]/4, dim[2]/4} )); 229 | AffineRealRandomAccessible< FloatType, AffineGet > perlinUpsampled = RealViews.affineReal( Views.interpolate( Views.extendZero( perlinScaled ), new NLinearInterpolatorFactory<>()), scalePerlin ); 230 | */ 231 | 232 | RealRandomAccessible< FloatType > rrableFinal = new SimpleCalculatedRealRandomAccessible( new FloatType(), (a,b) -> { 233 | float res = 0; 234 | for (FloatType t: b ) 235 | res = Math.max( res, t.getRealFloat() ); 236 | a.setReal( res ); 237 | }, rrableBigPoints, rrableSmallPoints); 238 | 239 | /* 240 | rrableFinal = new SimpleCalculatedRealRandomAccessible( new FloatType(), (a,b) -> { 241 | a.setReal( b.iterator().next().get() > 50 ? 1.0 : 0); 242 | }, rrableFinal); 243 | 244 | rrableFinal = RealViews.affineReal( rrableFinal, new Scale( 1,1,1 ) ); 245 | */ 246 | 247 | IntervalView< FloatType > view = Views.interval( Views.raster( rrableFinal ), new FinalInterval( dim ) ); 248 | 249 | new ImageJ(); 250 | ImageJFunctions.show( view, Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ) ); 251 | 252 | 253 | } 254 | 255 | } 256 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/NumberGeneratorImage.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation; 24 | 25 | import net.imglib2.Cursor; 26 | import net.imglib2.RandomAccessibleInterval; 27 | import net.imglib2.type.numeric.RealType; 28 | import net.imglib2.view.Views; 29 | import net.preibisch.simulation.uncommons.NumberGenerator; 30 | 31 | //import org.uncommons.maths.number.NumberGenerator; 32 | 33 | /** 34 | * Helper class for the poisson process 35 | * 36 | * This software is free software: you can redistribute it and/or modify 37 | * it under the terms of the GNU General Public License as published by 38 | * the Free Software Foundation, either version 2 of the License, or 39 | * (at your option) any later version. 40 | 41 | * This software is distributed in the hope that it will be useful, 42 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | * GNU General Public License for more details. 45 | 46 | * You should have received a copy of the GNU General Public License 47 | * along with this software. If not, see http://www.gnu.org/licenses/. 48 | * 49 | * @author Stephan Preibisch (stephan.preibisch@gmx.de) 50 | */ 51 | public class NumberGeneratorImage< T extends RealType< T > > implements NumberGenerator< Double > 52 | { 53 | final Cursor< T > cursor; 54 | final double multiplicativeFactor; 55 | 56 | public NumberGeneratorImage( final RandomAccessibleInterval image, final double multiplicativeFactor ) 57 | { 58 | this.cursor = Views.iterable( image ).cursor(); 59 | this.multiplicativeFactor = multiplicativeFactor; 60 | } 61 | 62 | /** 63 | * Otherwise it gets out of sync for some reason 64 | */ 65 | public void fwd() 66 | { 67 | cursor.fwd(); 68 | } 69 | 70 | public void reset() 71 | { 72 | cursor.reset(); 73 | } 74 | 75 | @Override 76 | public Double nextValue() 77 | { 78 | return cursor.get().getRealDouble() * multiplicativeFactor; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/PerlinNoiseRealRandomAccessible.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Random; 8 | import java.util.concurrent.Executors; 9 | 10 | import ij.ImageJ; 11 | import net.imglib2.FinalInterval; 12 | import net.imglib2.RealInterval; 13 | import net.imglib2.RealPoint; 14 | import net.imglib2.RealRandomAccess; 15 | import net.imglib2.RealRandomAccessible; 16 | import net.imglib2.Sampler; 17 | import net.imglib2.img.display.imagej.ImageJFunctions; 18 | import net.imglib2.type.numeric.RealType; 19 | import net.imglib2.type.numeric.real.FloatType; 20 | import net.imglib2.view.IntervalView; 21 | import net.imglib2.view.Views; 22 | 23 | public class PerlinNoiseRealRandomAccessible> implements RealRandomAccessible< T > 24 | { 25 | 26 | private final int numDim; 27 | private final double[] scales; 28 | private final int[] loopExtents; 29 | private final int nVectors; 30 | private final T type; 31 | 32 | private final List gradients; 33 | private final List permuatation; 34 | 35 | public PerlinNoiseRealRandomAccessible(T type, double[] scales, int[] loopExtents, int nVectors, Random rng) 36 | { 37 | this.type = type.copy(); 38 | this.nVectors = nVectors; 39 | 40 | this.scales = scales.clone(); 41 | this.loopExtents = loopExtents.clone(); 42 | this.numDim = scales.length; 43 | 44 | gradients = new ArrayList<>(); 45 | permuatation = new ArrayList<>(); 46 | for (int i=0; i realRandomAccess() 62 | { 63 | return new PerlinNoiseRealRandomAccess(); 64 | } 65 | 66 | @Override 67 | public RealRandomAccess< T > realRandomAccess(RealInterval interval) 68 | { 69 | return realRandomAccess(); 70 | } 71 | 72 | public static double[] randomUnitVector(int nDim, Random rng) 73 | { 74 | double[] res = new double[nDim]; 75 | double sSum = 0.0; 76 | for (int d=0; d 87 | { 88 | 89 | private final T type; 90 | private final List neighbors; 91 | 92 | public PerlinNoiseRealRandomAccess() 93 | { 94 | super(numDim); 95 | this.type = PerlinNoiseRealRandomAccessible.this.type.copy(); 96 | neighbors = neighborOffsets( numDim ); 97 | } 98 | 99 | @Override 100 | public T get() 101 | { 102 | double[] posInGrid = position.clone(); 103 | int[] posInGridInt = new int[posInGrid.length]; 104 | for (int d=0; d dots = new ArrayList<>(); 112 | for(int[] off : neighbors) 113 | { 114 | int[] neighborPos = posInGridInt.clone(); 115 | double[] dist = posInGrid.clone(); 116 | for (int d=0; d copy() 137 | { 138 | return copyRealRandomAccess(); 139 | } 140 | 141 | @Override 142 | public RealRandomAccess< T > copyRealRandomAccess() 143 | { 144 | PerlinNoiseRealRandomAccess ra = new PerlinNoiseRealRandomAccess(); 145 | ra.setPosition( this ); 146 | return ra; 147 | } 148 | 149 | } 150 | 151 | private static double interpolateSmoothstep(List dots, double[] offs) 152 | { 153 | List interpolated = new ArrayList<>(); 154 | interpolated.addAll( dots ); 155 | for (int d=offs.length-1; d>=0; d--) 156 | { 157 | List interpolatedTemp = new ArrayList<>(); 158 | Iterator< Double > it = interpolated.iterator(); 159 | for (int i=0; i<(int)Math.pow( 2, d );i++) 160 | { 161 | Double a1 = it.next(); 162 | Double a2 = it.next(); 163 | interpolatedTemp.add( smoothstep(a1, a2, offs[d]) ); 164 | } 165 | interpolated = interpolatedTemp; 166 | } 167 | return interpolated.get( 0 ); 168 | } 169 | 170 | private static double smoothstep(double a1, double a2, double p) 171 | { 172 | double sstep = Math.pow( p, 3 ) * (10 - 15 * p + 6* Math.pow( p, 2 )); 173 | sstep = Math.min( 1, Math.max( sstep, 0 ) ); 174 | return (1.0 - sstep) * a1 + sstep * a2; 175 | } 176 | 177 | private static double dot(double[] a, double[] b) 178 | { 179 | double dot = 0; 180 | for (int d=0; d neighborOffsets(int numDim) 198 | { 199 | List res = new ArrayList<>(); 200 | for (int i=0; i=0;d--) 205 | { 206 | off[numDim - 1 - d] = it / (int) Math.pow( 2, d ); 207 | it = it % (int) Math.pow( 2, d ); 208 | } 209 | res.add( off ); 210 | } 211 | return res; 212 | } 213 | 214 | 215 | public static double fFloorMod(float a, float b) 216 | { 217 | float mod = a % b; 218 | return mod < 0 ? mod + b : mod; 219 | } 220 | 221 | public static void main(String[] args) 222 | { 223 | Random rng = new Random(42); 224 | PerlinNoiseRealRandomAccessible< FloatType > rrable = new PerlinNoiseRealRandomAccessible<>( new FloatType(), new double[] {512,1500,256}, new int[] {15, 15, 15}, 100, rng ); 225 | 226 | IntervalView< FloatType > view = Views.interval( Views.raster( rrable ), new FinalInterval( new long[] {2048, 2048, 256} ) ); 227 | new ImageJ(); 228 | ImageJFunctions.show( view , Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() )); 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/PointRejectionSampling.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | import net.imglib2.RealInterval; 8 | import net.imglib2.RealPoint; 9 | import net.imglib2.RealRandomAccess; 10 | import net.imglib2.RealRandomAccessible; 11 | import net.imglib2.type.numeric.RealType; 12 | 13 | public class PointRejectionSampling 14 | { 15 | public static > List sampleRealPoints(RealInterval interval, int nSamples, RealRandomAccessible< T > density, Random rnd) 16 | { 17 | final List samples = new ArrayList<>(); 18 | final int nDim = interval.numDimensions(); 19 | final RealRandomAccess< T > ra = density.realRandomAccess(); 20 | while(samples.size() < nSamples) 21 | { 22 | double[] pos = new double[nDim]; 23 | for (int d=0; d. 21 | * #L% 22 | */ 23 | package net.preibisch.simulation; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import net.imglib2.Dimensions; 29 | import net.imglib2.FinalInterval; 30 | import net.imglib2.realtransform.AffineTransform3D; 31 | import net.imglib2.util.Util; 32 | 33 | public class RegularTranformHelpers 34 | { 35 | private static int prod(int ... v) 36 | { 37 | int res = 1; 38 | for (int i = 0; i < v.length; ++i) 39 | res *= v[i]; 40 | return res; 41 | } 42 | 43 | public static class RegularTranslationParameters 44 | { 45 | public int nDimensions; 46 | public int[] nSteps; 47 | public double[] overlaps; 48 | public int[] dimensionOrder; 49 | public boolean[] alternating; 50 | public boolean[] increasing; 51 | } 52 | 53 | public static List< AffineTransform3D > generateRegularGrid(RegularTranslationParameters params, Dimensions dims) 54 | { 55 | 56 | final ArrayList< AffineTransform3D > transforms = new ArrayList<>(); 57 | int nTiles = prod(params.nSteps); 58 | for (int i = 0; i < nTiles; ++i) 59 | transforms.add(new AffineTransform3D()); 60 | 61 | int modulo = 1; 62 | for (int i = 0; i < params.nDimensions; ++i) 63 | { 64 | int d = params.dimensionOrder[i]; 65 | double moveSize = (1.0 - params.overlaps[d]) * dims.dimension( d ); 66 | 67 | 68 | moveD(transforms, d, moveSize, modulo, params.nSteps[d], params.alternating[d], params.increasing[d]); 69 | modulo *= params.nSteps[d]; 70 | 71 | } 72 | 73 | //transforms.forEach( ( t ) -> System.out.println( Util.printCoordinates( t.getTranslation() ))) ; 74 | return transforms; 75 | } 76 | 77 | private static void moveD( List< AffineTransform3D > transforms, 78 | int d, 79 | double moveSize, 80 | int modulo, 81 | int steps, 82 | boolean alternate, 83 | boolean increasing) 84 | { 85 | for (int i = 0; i < transforms.size(); ++i) 86 | { 87 | int stepNo = i / (modulo * steps) ; 88 | int inStep = alternate && stepNo % 2 != 0 ? steps - 1 - i / modulo % steps: i / modulo % steps; 89 | transforms.get( i ).set( (increasing ? 1.0 : -1.0) * inStep * moveSize, d, 3 ); 90 | } 91 | 92 | } 93 | 94 | public static void main(String[] args) 95 | { 96 | RegularTranslationParameters params = new RegularTranslationParameters(); 97 | params.nDimensions = 3; 98 | params.alternating = new boolean[] {true, true, true}; 99 | params.dimensionOrder = new int[] {1, 0, 2}; 100 | params.increasing = new boolean[] {true, true, true}; 101 | params.overlaps = new double[] {0.2, 0.2, 0.2}; 102 | params.nSteps = new int[] {3, 3, 2}; 103 | 104 | Dimensions dims = new FinalInterval( new long[] {100, 100, 100} ); 105 | 106 | generateRegularGrid( params, dims ); 107 | 108 | } 109 | 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/SimpleCalculatedRealRandomAccessible.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | import net.imglib2.RandomAccessible; 8 | import net.imglib2.RealInterval; 9 | import net.imglib2.RealPoint; 10 | import net.imglib2.RealRandomAccess; 11 | import net.imglib2.RealRandomAccessible; 12 | import net.imglib2.Sampler; 13 | import net.imglib2.type.Type; 14 | 15 | public class SimpleCalculatedRealRandomAccessible> implements RealRandomAccessible< T > 16 | { 17 | 18 | final private T type; 19 | final private List> in; 20 | final private Calculation< T > calc; 21 | final private int numDimensions; 22 | 23 | @FunctionalInterface 24 | interface Calculation 25 | { 26 | void calculate(T out, Collection in); 27 | } 28 | 29 | public SimpleCalculatedRealRandomAccessible(T type, Calculation calc, RealRandomAccessible< T > ... in) 30 | { 31 | this.type = type.copy(); 32 | this.in = new ArrayList<>(); 33 | for (RealRandomAccessible< T > i : in) 34 | this.in.add( i ); 35 | this.numDimensions = in[0].numDimensions(); 36 | this.calc = calc; 37 | } 38 | 39 | @Override 40 | public int numDimensions() 41 | { 42 | return numDimensions; 43 | } 44 | 45 | @Override 46 | public RealRandomAccess< T > realRandomAccess() 47 | { 48 | return new CalculatedRealRandomAccess(); 49 | } 50 | 51 | @Override 52 | public RealRandomAccess< T > realRandomAccess(RealInterval interval) 53 | { 54 | return realRandomAccess(); 55 | } 56 | 57 | private class CalculatedRealRandomAccess extends RealPoint implements RealRandomAccess< T > 58 | { 59 | 60 | final private T type; 61 | final private List inTypes; 62 | final private List> inRAs; 63 | 64 | public CalculatedRealRandomAccess() 65 | { 66 | super(numDimensions); 67 | this.type = SimpleCalculatedRealRandomAccessible.this.type.copy(); 68 | inTypes = new ArrayList<>(); 69 | inRAs = new ArrayList<>(); 70 | for (int i=0; i copy() 91 | { 92 | return copyRealRandomAccess(); 93 | } 94 | 95 | @Override 96 | public RealRandomAccess< T > copyRealRandomAccess() 97 | { 98 | return new CalculatedRealRandomAccess(); 99 | } 100 | 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/SimulateBeads.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Random; 27 | 28 | import mpicbg.models.AffineModel3D; 29 | import net.imglib2.Cursor; 30 | import net.imglib2.FinalInterval; 31 | import net.imglib2.Interval; 32 | import net.imglib2.IterableInterval; 33 | import net.imglib2.RandomAccessible; 34 | import net.imglib2.RandomAccessibleInterval; 35 | import net.imglib2.img.Img; 36 | import net.imglib2.img.array.ArrayImgs; 37 | import net.imglib2.type.numeric.real.FloatType; 38 | import net.imglib2.util.Util; 39 | import net.imglib2.view.Views; 40 | 41 | /** 42 | * Simulate Bead Images 43 | * 44 | * This software is free software: you can redistribute it and/or modify 45 | * it under the terms of the GNU General Public License as published by 46 | * the Free Software Foundation, either version 2 of the License, or 47 | * (at your option) any later version. 48 | 49 | * This software is distributed in the hope that it will be useful, 50 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 51 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 52 | * GNU General Public License for more details. 53 | 54 | * You should have received a copy of the GNU General Public License 55 | * along with this software. If not, see http://www.gnu.org/licenses/. 56 | * 57 | * @author Stephan Preibisch (stephan.preibisch@gmx.de) 58 | */ 59 | public class SimulateBeads 60 | { 61 | ArrayList< Img< FloatType > > imgs; 62 | public final int[] angles; 63 | public final int axis; 64 | public final int numPoints; 65 | public final Interval rangeSimulation; 66 | public final Interval intervalRender; 67 | public final double[] sigma; 68 | 69 | final Random rnd = new Random( 535 ); 70 | 71 | public SimulateBeads( final int[] angles, final int axis, final int numPoints, final Interval rangeSimulation, final Interval intervalRender, final double[] sigma ) 72 | { 73 | this.angles = angles; 74 | this.axis = axis; 75 | this.numPoints = numPoints; 76 | this.rangeSimulation = rangeSimulation; 77 | this.intervalRender = intervalRender; 78 | this.sigma = sigma; 79 | 80 | this.imgs = null; 81 | } 82 | 83 | public ArrayList< Img< FloatType > > getImgs() 84 | { 85 | if ( imgs == null ) 86 | { 87 | final ArrayList< double[] > points = randomPoints( numPoints, rangeSimulation, rnd ); 88 | 89 | final ArrayList< ArrayList< double[] > > lists = transformPoints( points, angles, axis, rangeSimulation ); 90 | 91 | imgs = renderPoints( lists, intervalRender, sigma ); 92 | } 93 | 94 | return imgs; 95 | } 96 | 97 | public static ArrayList< Img< FloatType > > renderPoints( final ArrayList< ArrayList< double[] > > lists, final Interval interval, final double[] sigma ) 98 | { 99 | final ArrayList< Img< FloatType > > images = new ArrayList< Img< FloatType > >(); 100 | 101 | for ( final ArrayList< double[] > list : lists ) 102 | { 103 | final long[] dim = new long[ interval.numDimensions() ]; 104 | 105 | for ( int d = 0; d < interval.numDimensions(); ++d ) 106 | dim[ d ] = interval.max( d ) - interval.min( d ); 107 | 108 | final Img< FloatType > img = ArrayImgs.floats( dim ); 109 | 110 | for ( final double[] p : list ) 111 | if ( isInsideAdjust( p, interval ) ) 112 | addGaussian( img, p, sigma ); 113 | 114 | images.add( img ); 115 | } 116 | 117 | return images; 118 | } 119 | 120 | protected static boolean isInsideAdjust( final double[] p, final Interval interval ) 121 | { 122 | for ( int d = 0; d < interval.numDimensions(); ++d ) 123 | { 124 | p[ d ] -= interval.min( d ); 125 | 126 | if ( p[ d ] < 0 || p[ d ] > interval.dimension( d ) - 1 ) 127 | return false; 128 | } 129 | 130 | return true; 131 | } 132 | public static ArrayList< ArrayList< double[] > > transformPoints( final ArrayList< double[] > points, final int[] angles, final int axis, final Interval range ) 133 | { 134 | final ArrayList< ArrayList< double[] > > transformedPoints = new ArrayList< ArrayList< double[] > >(); 135 | 136 | for ( final int angle : angles ) 137 | { 138 | final AffineModel3D t = SimulateMultiViewDataset.axisRotation( range, axis, angle ); 139 | 140 | final ArrayList< double[] > transformed = new ArrayList< double[] >(); 141 | 142 | for ( final double[] p : points ) 143 | transformed.add( t.apply( p ) ); 144 | 145 | transformedPoints.add( transformed ); 146 | } 147 | 148 | return transformedPoints; 149 | } 150 | 151 | public static ArrayList< double[] > randomPoints( final int numPoints, final Interval range, final Random rnd ) 152 | { 153 | final ArrayList< double[] > points = new ArrayList< double[] >(); 154 | 155 | for ( int i = 0; i < numPoints; ++i ) 156 | { 157 | final double[] p = new double[ range.numDimensions() ]; 158 | 159 | for ( int d = 0; d < range.numDimensions(); ++d ) 160 | p[ d ] = rnd.nextDouble() * ( range.max( d ) - range.min( d ) ) + range.min( d ); 161 | 162 | points.add( p ); 163 | } 164 | 165 | return points; 166 | } 167 | 168 | final public static void addGaussian( final Img< FloatType > image, final double[] location, final double[] sigma ) 169 | { 170 | final int numDimensions = image.numDimensions(); 171 | final int[] size = new int[ numDimensions ]; 172 | 173 | final long[] min = new long[ numDimensions ]; 174 | final long[] max = new long[ numDimensions ]; 175 | 176 | final double[] two_sq_sigma = new double[ numDimensions ]; 177 | 178 | for ( int d = 0; d < numDimensions; ++d ) 179 | { 180 | size[ d ] = Util.getSuggestedKernelDiameter( sigma[ d ] ) * 2; 181 | min[ d ] = (int)Math.round( location[ d ] ) - size[ d ]/2; 182 | max[ d ] = min[ d ] + size[ d ] - 1; 183 | two_sq_sigma[ d ] = 2 * sigma[ d ] * sigma[ d ]; 184 | } 185 | 186 | final RandomAccessible< FloatType > infinite = Views.extendZero( image ); 187 | final RandomAccessibleInterval< FloatType > interval = Views.interval( infinite, min, max ); 188 | final IterableInterval< FloatType > iterable = Views.iterable( interval ); 189 | final Cursor< FloatType > cursor = iterable.localizingCursor(); 190 | 191 | while ( cursor.hasNext() ) 192 | { 193 | cursor.fwd(); 194 | 195 | double value = 1; 196 | 197 | for ( int d = 0; d < numDimensions; ++d ) 198 | { 199 | final double x = location[ d ] - cursor.getIntPosition( d ); 200 | value *= Math.exp( -(x * x) / two_sq_sigma[ d ] ); 201 | } 202 | 203 | cursor.get().set( cursor.get().get() + ( (float)value * 1000.0f ) ); 204 | } 205 | } 206 | 207 | public static void main( String[] args ) 208 | { 209 | final int[] angles = new int[]{ 0, 45, 90, 135 }; 210 | final int axis = 0; 211 | final int numPoints = 1000; 212 | final double[] sigma = new double[]{ 1, 1, 3 }; 213 | final FinalInterval range = new FinalInterval( 512, 512, 200 ); 214 | 215 | final SimulateBeads sb = new SimulateBeads( angles, axis, numPoints, range, range, sigma ); 216 | 217 | for ( int i = 0; i < angles.length; ++i ) 218 | { 219 | //ImageJFunctions.wrap( sb.getImgs().get( i ), "Angle_" + angles[ i ] ).duplicate().show(); 220 | Tools.save( sb.getImgs().get( i ), "Angle_" + angles[ i ] + ".tif" ); 221 | } 222 | 223 | System.out.println( "done." ); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/SimulateBeads2.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Arrays; 27 | import java.util.HashMap; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.Random; 31 | 32 | import net.imglib2.Dimensions; 33 | import net.imglib2.FinalRealInterval; 34 | import net.imglib2.Interval; 35 | import net.imglib2.RealInterval; 36 | import net.imglib2.img.Img; 37 | import net.imglib2.img.display.imagej.ImageJFunctions; 38 | import net.imglib2.realtransform.AffineTransform3D; 39 | import net.imglib2.type.numeric.real.FloatType; 40 | import net.imglib2.util.Intervals; 41 | import net.imglib2.util.Util; 42 | 43 | public class SimulateBeads2 44 | { 45 | 46 | public final Map, Img< FloatType > > imgs; 47 | public final int numPoints; 48 | public final Interval rangeSimulation; 49 | public final Interval intervalRender; 50 | public final double[] sigma; 51 | 52 | public final Map angleTransforms; 53 | public final Map channelTransforms; 54 | public final Map illumTransforms; 55 | public final Map tpTransforms; 56 | public final Map tileTransforms; 57 | 58 | final Random rnd = new Random( 535 ); 59 | final ArrayList< double[] > points; 60 | 61 | public SimulateBeads2(int numPoints, double[] sigma, Interval rangeSimulation, Interval intervalRender) 62 | { 63 | this.numPoints = numPoints; 64 | this.rangeSimulation = rangeSimulation; 65 | this.intervalRender = intervalRender; 66 | this.sigma = sigma; 67 | 68 | imgs = new HashMap<>(); 69 | 70 | angleTransforms = new HashMap<>(); 71 | channelTransforms = new HashMap<>(); 72 | illumTransforms = new HashMap<>(); 73 | tpTransforms = new HashMap<>(); 74 | tileTransforms = new HashMap<>(); 75 | 76 | points = SimulateBeads.randomPoints( numPoints, rangeSimulation, rnd ); 77 | } 78 | 79 | // get min/max of all tiles 80 | public RealInterval getTilesExtent() 81 | { 82 | final Dimensions dims = intervalRender; 83 | double[] mins = Util.getArrayFromValue( Double.MAX_VALUE, dims.numDimensions() ); 84 | double[] maxs = Util.getArrayFromValue( -Double.MAX_VALUE, dims.numDimensions() ); 85 | 86 | for (AffineTransform3D tt : tileTransforms.values()) 87 | { 88 | for (int d = 0; d < dims.numDimensions(); d++) 89 | { 90 | mins[d] = Math.min( mins[d], -tt.getTranslation()[d] ); 91 | maxs[d] = Math.max( maxs[d], -tt.getTranslation()[d] + dims.dimension( d ) ); 92 | } 93 | } 94 | 95 | return new FinalRealInterval( mins, maxs ); 96 | 97 | } 98 | 99 | public Img< FloatType > getImg(int tp, int angle, int channel, int tile, int illumination) 100 | { 101 | List< Integer > key = Arrays.asList( new Integer[] {tp, angle, channel, tile, illumination} ); 102 | if (!imgs.containsKey( key )) 103 | { 104 | ArrayList< double[] > transformedPoints = transformedPoints( tp, angle, channel, tile, illumination ); 105 | ArrayList< ArrayList< double[] > > packed = new ArrayList<>(); 106 | packed.add( transformedPoints ); 107 | imgs.put( key, SimulateBeads.renderPoints( packed, intervalRender, sigma ).get( 0 )); 108 | } 109 | return imgs.get( key ); 110 | 111 | } 112 | 113 | public void addAngle(int id, int axis, double degrees) 114 | { 115 | AffineTransform3D t = new AffineTransform3D(); 116 | t.rotate( axis, Math.toRadians( degrees ) ); 117 | angleTransforms.put( id, t.copy() ); 118 | } 119 | 120 | public void addChannel(int id, double[] shift) 121 | { 122 | AffineTransform3D t = new AffineTransform3D(); 123 | t.translate( shift ); 124 | channelTransforms.put( id, t.copy()); 125 | } 126 | 127 | public void addIllumination(int id, double[] shift) 128 | { 129 | AffineTransform3D t = new AffineTransform3D(); 130 | t.translate( shift ); 131 | illumTransforms.put( id, t.copy() ); 132 | } 133 | 134 | public void addTimepoint(int id, double[] shift) 135 | { 136 | AffineTransform3D t = new AffineTransform3D(); 137 | t.translate( shift ); 138 | tpTransforms.put( id, t.copy()); 139 | } 140 | 141 | public void addTile(int id, double[] shift) 142 | { 143 | AffineTransform3D t = new AffineTransform3D(); 144 | t.translate( shift ); 145 | tileTransforms.put( id, t.copy().inverse() ); 146 | } 147 | 148 | private ArrayList< double[] > transformedPoints(int tp, int angle, int channel, int tile, int illumination) 149 | { 150 | 151 | AffineTransform3D transform = new AffineTransform3D(); 152 | 153 | // time 154 | if (tpTransforms.containsKey( tp )) 155 | transform.preConcatenate( tpTransforms.get( tp ) ); 156 | 157 | // angle 158 | if (angleTransforms.containsKey( angle )) 159 | transform.preConcatenate( angleTransforms.get( angle ) ); 160 | 161 | // channel 162 | if (channelTransforms.containsKey( channel )) 163 | transform.preConcatenate( channelTransforms.get( channel ) ); 164 | 165 | // illumination 166 | if (illumTransforms.containsKey( illumination )) 167 | transform.preConcatenate( illumTransforms.get( illumination ) ); 168 | 169 | // tile 170 | if (tileTransforms.containsKey( tile )) 171 | transform.preConcatenate( tileTransforms.get( tile ) ); 172 | 173 | final ArrayList< double[] > transformed = new ArrayList< double[] >(); 174 | 175 | for ( final double[] p : points ) 176 | { 177 | double[] pt = p.clone(); 178 | transform.apply( p, pt ); 179 | transformed.add( pt ); 180 | } 181 | 182 | return transformed; 183 | 184 | } 185 | 186 | public static void main(String[] args) 187 | { 188 | SimulateBeads2 sb = new SimulateBeads2( 2000, new double[]{1, 1, 3}, Intervals.createMinMax( 0,0,0, 512, 512, 200 ), Intervals.createMinMax( 0,0,0, 512, 512, 200 ) ); 189 | sb.addTile( 0, new double[]{0,0,0} ); 190 | sb.addTile( 1, new double[]{10,0,0} ); 191 | ImageJFunctions.show( sb.getImg( 0, 0, 0, 0, 0 ) ); 192 | ImageJFunctions.show( sb.getImg( 0, 0, 0, 1, 0 ) ); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/SimulateTileStitching.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Random; 27 | import java.util.concurrent.Callable; 28 | import java.util.concurrent.ExecutorService; 29 | import java.util.concurrent.Executors; 30 | 31 | import ij.IJ; 32 | import ij.ImageJ; 33 | import ij.ImagePlus; 34 | import net.imglib2.RandomAccessibleInterval; 35 | import net.imglib2.img.Img; 36 | import net.imglib2.img.display.imagej.ImageJFunctions; 37 | import net.imglib2.type.numeric.real.FloatType; 38 | import net.imglib2.util.Pair; 39 | import net.imglib2.util.Util; 40 | import net.imglib2.util.ValuePair; 41 | import net.imglib2.view.Views; 42 | 43 | public class SimulateTileStitching 44 | { 45 | final String dir = "src/main/resources/"; 46 | final ExecutorService service; 47 | 48 | int lightsheetSpacing = 3; 49 | float attenuation = 0.01f; 50 | 51 | final Random rnd; 52 | Img< FloatType > psf; 53 | Img< FloatType > con, conHalfPixel; 54 | long[] min, max; 55 | boolean halfPixelOffset; 56 | int[] overlap; 57 | 58 | public SimulateTileStitching( final boolean halfPixelOffset, final double[] overlapRatio, final ExecutorService service ) 59 | { 60 | this( null, halfPixelOffset, overlapRatio, service ); 61 | } 62 | 63 | public SimulateTileStitching( final Random rnd, final boolean halfPixelOffset, final double[] overlapRatio, final ExecutorService service ) 64 | { 65 | if ( rnd == null ) 66 | this.rnd = new Random( 464232194 ); 67 | else 68 | this.rnd = rnd; 69 | 70 | this.service = service; 71 | this.psf = Tools.open( dir + "Angle0.tif", true ); 72 | 73 | init( overlapRatio, halfPixelOffset ); 74 | } 75 | 76 | public void init( final double[] overlapRatio, boolean halfPixelOffset ) 77 | { 78 | this.halfPixelOffset = halfPixelOffset; 79 | 80 | // artificially rendered object based on which everything is computed, 81 | // including the ground-truth image, which is rotated once by the angle offset 82 | // so that it is realistic 83 | final int seed = rnd.nextInt(); // same result for half pixel and not 84 | 85 | final ArrayList< Callable< Void > > tasks = new ArrayList< Callable< Void > >(); 86 | 87 | tasks.add( new Callable< Void >() 88 | { 89 | @Override 90 | public Void call() throws Exception 91 | { 92 | System.out.println( "Thread 1: simulate " ); 93 | final Img< FloatType > groundTruth = SimulateMultiViewDataset.simulate( false, new Random( seed ) ); 94 | final Img< FloatType > att = SimulateMultiViewDataset.attenuate3d( groundTruth, attenuation ); 95 | con = SimulateMultiViewDataset.convolve( att, psf, service ); 96 | Tools.adjustImage( con, SimulateMultiViewDataset.minValue, SimulateMultiViewDataset.avgIntensity ); 97 | 98 | return null; 99 | } 100 | }); 101 | 102 | tasks.add( new Callable< Void >() 103 | { 104 | @Override 105 | public Void call() throws Exception 106 | { 107 | System.out.println( "Thread 2: simulate " ); 108 | final Img< FloatType > groundTruthHalfPixel = SimulateMultiViewDataset.simulate( true, new Random( seed ) ); 109 | final Img< FloatType > attHalfPixel = SimulateMultiViewDataset.attenuate3d( groundTruthHalfPixel, attenuation ); 110 | conHalfPixel = SimulateMultiViewDataset.convolve( attHalfPixel, psf, service ); 111 | Tools.adjustImage( conHalfPixel, SimulateMultiViewDataset.minValue, SimulateMultiViewDataset.avgIntensity ); 112 | 113 | return null; 114 | } 115 | }); 116 | 117 | runThreads( tasks, service ); 118 | 119 | this.overlap = new int[ con.numDimensions() ]; 120 | for ( int d = 0; d < con.numDimensions(); ++d ) 121 | this.overlap[ d ] = (int)Math.round( con.dimension( d ) * overlapRatio[ d ] / 2 ); 122 | 123 | System.out.println( "Overlap: " + Util.printCoordinates( this.overlap ) ); 124 | 125 | this.min = new long[ con.numDimensions() ]; 126 | this.max = new long[ con.numDimensions() ]; 127 | } 128 | 129 | private Img< FloatType > split0, split1; 130 | 131 | public Pair< Img< FloatType >, Img< FloatType > > getNextPair( final float snr ) 132 | { 133 | final Thread[] threads = new Thread[ 2 ]; 134 | 135 | final int seed0 = rnd.nextInt(); 136 | final int seed1 = rnd.nextInt(); 137 | 138 | final ArrayList< Callable< Void > > tasks = new ArrayList< Callable< Void > >(); 139 | 140 | // tile 0 141 | tasks.add( new Callable< Void >() 142 | { 143 | @Override 144 | public Void call() throws Exception 145 | { 146 | final long[] min1 = min.clone(); 147 | final long[] max1 = max.clone(); 148 | 149 | getInterval( min1, max1, 0 ); 150 | 151 | //System.out.println( new Date( System.currentTimeMillis() ) + ": extracting slices tile " + tile + " snr=" +snr ); 152 | split0 = SimulateMultiViewDataset.extractSlices( 153 | Views.zeroMin( Views.interval( con, min1, max1 ) ), 154 | lightsheetSpacing, 155 | snr, 156 | new Random( seed0 ) ); 157 | 158 | return null; 159 | } 160 | }); 161 | 162 | // tile 1 163 | tasks.add( new Callable< Void >() 164 | { 165 | @Override 166 | public Void call() throws Exception 167 | { 168 | final long[] min1 = min.clone(); 169 | final long[] max1 = max.clone(); 170 | 171 | getInterval( min1, max1, 1 ); 172 | 173 | if ( halfPixelOffset ) 174 | split1 = SimulateMultiViewDataset.extractSlices( 175 | Views.zeroMin( Views.interval( conHalfPixel, min1, max1 ) ), 176 | lightsheetSpacing, snr, new Random( seed1 ) ); 177 | else 178 | split1 = SimulateMultiViewDataset.extractSlices( 179 | Views.zeroMin( Views.interval( con, min1, max1 ) ), 180 | lightsheetSpacing, snr, new Random( seed1 ) ); 181 | 182 | return null; 183 | } 184 | }); 185 | 186 | runThreads( tasks, service ); 187 | 188 | return new ValuePair<>( split0, split1 ); 189 | } 190 | 191 | public double[] getCorrectTranslation() 192 | { 193 | final double[] translation = new double[ con.numDimensions() ]; 194 | 195 | getInterval( min, max, 1 ); 196 | 197 | for ( int d = 0; d < con.numDimensions(); ++d ) 198 | translation[ d ] = min[ d ]; 199 | 200 | if ( halfPixelOffset ) 201 | { 202 | // unintutive, but true. If the content of the right image is shifted 203 | // more to the right (by 0.5 pixels), means that in order to match it 204 | // has to be shifted less to the left (take to sheets of paper to understand :) 205 | translation[ 0 ] -= 0.5; 206 | translation[ 1 ] -= 0.5; 207 | } 208 | 209 | translation[ 2 ] /= lightsheetSpacing; 210 | 211 | return translation; 212 | } 213 | 214 | protected void getInterval( final long[] min, final long[] max, final int tile ) 215 | { 216 | con.min( min ); 217 | con.max( max ); 218 | 219 | if ( tile == 0 ) 220 | { 221 | for ( int d = 0; d < min.length; ++d ) 222 | max[ d ] = (int)con.dimension( d ) / 2 + overlap[ d ]; 223 | 224 | System.out.println( "Tile0: " + Util.printCoordinates( min ) + " >> " + Util.printCoordinates( max ) ); 225 | } 226 | else 227 | { 228 | for ( int d = 0; d < min.length; ++d ) 229 | min[ d ] = (int)con.dimension( 0 ) / 2 - overlap[ d ]; 230 | 231 | System.out.println( "Tile1: " + Util.printCoordinates( min ) + " >> " + Util.printCoordinates( max ) ); 232 | } 233 | 234 | } 235 | 236 | public static void show( final RandomAccessibleInterval< FloatType > img, final String title ) 237 | { 238 | ImagePlus imp = ImageJFunctions.wrapFloat( img, title ); 239 | 240 | imp.setDimensions( 1, imp.getStackSize(), 1 ); 241 | imp.setSlice( imp.getStackSize() / 2 ); 242 | imp.resetDisplayRange(); 243 | imp.show(); 244 | } 245 | 246 | public static void runThreads( final ArrayList< Callable< Void > > tasks, final ExecutorService service ) 247 | { 248 | try 249 | { 250 | // invokeAll() returns when all tasks are complete 251 | service.invokeAll( tasks ); 252 | } 253 | catch ( final InterruptedException e ) 254 | { 255 | e.printStackTrace(); 256 | return; 257 | } 258 | } 259 | 260 | public static void main( String[] args ) 261 | { 262 | new ImageJ(); 263 | 264 | final double overlap = 0.2; 265 | final float snr = 8; 266 | 267 | final SimulateTileStitching sts = new SimulateTileStitching( 268 | new Random( System.currentTimeMillis() ), 269 | true, 270 | Util.getArrayFromValue( overlap, 3 ), 271 | Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ) ); 272 | 273 | IJ.log( "Known shift (right relative to left): " + Util.printCoordinates( sts.getCorrectTranslation() ) ); 274 | 275 | final Pair< Img< FloatType >, Img< FloatType > > pair = sts.getNextPair( snr ); 276 | 277 | show( pair.getA(), "left" ); 278 | show( pair.getB(), "right" ); 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/Tools.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation; 24 | 25 | import java.awt.Image; 26 | import java.io.File; 27 | import java.io.IOException; 28 | import java.util.Random; 29 | 30 | import ij.IJ; 31 | import ij.ImagePlus; 32 | import ij.io.FileSaver; 33 | import ij.io.Opener; 34 | import ij.process.ImageProcessor; 35 | import loci.formats.ChannelSeparator; 36 | import loci.formats.FormatException; 37 | import loci.formats.FormatTools; 38 | import loci.formats.IFormatReader; 39 | import mpicbg.util.RealSum; 40 | import net.imglib2.Cursor; 41 | import net.imglib2.IterableInterval; 42 | import net.imglib2.RandomAccess; 43 | import net.imglib2.RandomAccessibleInterval; 44 | import net.imglib2.img.Img; 45 | import net.imglib2.img.ImgFactory; 46 | import net.imglib2.img.array.ArrayImgFactory; 47 | import net.imglib2.img.display.imagej.ImageJFunctions; 48 | import net.imglib2.type.numeric.real.FloatType; 49 | import net.imglib2.view.Views; 50 | import net.preibisch.simulation.uncommons.PoissonGenerator; 51 | 52 | /** 53 | * static helper methods 54 | * 55 | * This software is free software: you can redistribute it and/or modify 56 | * it under the terms of the GNU General Public License as published by 57 | * the Free Software Foundation, either version 2 of the License, or 58 | * (at your option) any later version. 59 | 60 | * This software is distributed in the hope that it will be useful, 61 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 62 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 63 | * GNU General Public License for more details. 64 | 65 | * You should have received a copy of the GNU General Public License 66 | * along with this software. If not, see http://www.gnu.org/licenses/. 67 | * 68 | * @author Stephan Preibisch (stephan.preibisch@gmx.de) 69 | * 70 | */ 71 | public class Tools 72 | { 73 | public static void poissonProcess( final RandomAccessibleInterval img, final double SNR, final Random rnd ) 74 | { 75 | // based on an average intensity of 5, a multiplicator of 1 corresponds to a SNR of 2.23 = sqrt( 5 ); 76 | final double mul = Math.pow( SNR / Math.sqrt( 5 ), 2 ); 77 | 78 | final NumberGeneratorImage< FloatType> ng = new NumberGeneratorImage< FloatType>( img, mul ); 79 | final PoissonGenerator pg = new PoissonGenerator( ng, rnd ); 80 | 81 | for ( final FloatType v : Views.iterable( img ) ) 82 | { 83 | ng.fwd(); 84 | v.set( pg.nextValue().floatValue() ); 85 | } 86 | } 87 | 88 | public static void save( final RandomAccessibleInterval< FloatType > img, final String file ) 89 | { 90 | final ImagePlus imp = ImageJFunctions.wrap( img, "" ).duplicate(); 91 | 92 | final FileSaver s = new FileSaver( imp ); 93 | 94 | if ( img.numDimensions() == 3 ) 95 | { 96 | imp.setDimensions( 1, (int)img.dimension( 2 ), 1 ); 97 | s.saveAsTiffStack( file ); 98 | } 99 | else 100 | { 101 | s.saveAsTiff( file ); 102 | } 103 | 104 | imp.close(); 105 | } 106 | 107 | /** 108 | * Norms an image so that the sum over all pixels is 1. 109 | * 110 | * @param img - the {@link Image} to normalize 111 | */ 112 | final public static void normImage( final Iterable img ) 113 | { 114 | final double sum = sumImage( img ); 115 | 116 | for ( final FloatType t : img ) 117 | t.set( (float) ((double)t.get() / sum) ); 118 | } 119 | 120 | /** 121 | * @param img - the input {@link Image} 122 | * @return - the sum of all pixels using {@link RealSum} 123 | */ 124 | final public static double sumImage( final Iterable img ) 125 | { 126 | final RealSum sum = new RealSum(); 127 | 128 | for ( final FloatType t : img ) 129 | sum.add( t.get() ); 130 | 131 | return sum.getSum(); 132 | } 133 | 134 | /** 135 | * Adjusts an image so that the minimal intensity is minValue and the average is average 136 | * 137 | * @param image - the image to norm 138 | * @param minValue - the minimal value 139 | * @param targetAverage - the average that we want to have 140 | * 141 | * @return by which number all intensities were multiplied 142 | */ 143 | public static double adjustImage( final IterableInterval image, final float minValue, final float targetAverage ) 144 | { 145 | // first norm the image to an average of (targetAverage - minValue) 146 | final double avg = sumImage( image )/(double)image.size(); 147 | final double correction = ( targetAverage - minValue ) / avg; 148 | 149 | // correct 150 | for ( final FloatType t : image ) 151 | t.set( (float)( t.get() * correction ) ); 152 | 153 | // now add minValue to all pixels 154 | for ( final FloatType t : image ) 155 | t.set( t.get() + minValue ); 156 | 157 | //System.out.println( sumImage( image )/(double)image.getNumPixels() ); 158 | return correction; 159 | } 160 | 161 | 162 | public static Img< FloatType > open( final String name, final ImgFactory< FloatType > factory ) 163 | { 164 | final IFormatReader r = new ChannelSeparator(); 165 | 166 | final String id = new File( name ).getAbsolutePath(); 167 | 168 | try 169 | { 170 | r.setId( id ); 171 | 172 | final boolean isLittleEndian = r.isLittleEndian(); 173 | final int width = r.getSizeX(); 174 | final int height = r.getSizeY(); 175 | final int depth = r.getSizeZ(); 176 | int timepoints = r.getSizeT(); 177 | int channels = r.getSizeC(); 178 | final int tiles = r.getSeriesCount(); 179 | final int pixelType = r.getPixelType(); 180 | final int bytesPerPixel = FormatTools.getBytesPerPixel( pixelType ); 181 | final String pixelTypeString = FormatTools.getPixelTypeString( pixelType ); 182 | 183 | if ( pixelType != FormatTools.FLOAT ) 184 | { 185 | System.out.println( "StackImgLoaderLOCI.openLOCI(): PixelType " + pixelTypeString + " not supported, returning. "); 186 | 187 | r.close(); 188 | 189 | return null; 190 | } 191 | 192 | System.out.println( "w: " + width ); 193 | System.out.println( "h: " + height ); 194 | System.out.println( "d: " + depth ); 195 | System.out.println( "t: " + timepoints ); 196 | System.out.println( "c: " + channels ); 197 | 198 | final Img< FloatType > img = factory.create( new long[] { width, height, depth }, new FloatType() ); 199 | 200 | final byte[] b = new byte[width * height * bytesPerPixel]; 201 | 202 | final int planeX = 0; 203 | final int planeY = 1; 204 | 205 | for ( int z = 0; z < depth; ++z ) 206 | { 207 | final Cursor< FloatType > cursor = Views.iterable( Views.hyperSlice( img, 2, z ) ).localizingCursor(); 208 | 209 | r.openBytes( r.getIndex( z, 0, 0 ), b ); 210 | 211 | while( cursor.hasNext() ) 212 | { 213 | cursor.fwd(); 214 | cursor.get().setReal( getFloatValue( b, ( cursor.getIntPosition( planeX )+ cursor.getIntPosition( planeY )*width )*4, isLittleEndian ) ); 215 | } 216 | } 217 | 218 | r.close(); 219 | 220 | return img; 221 | 222 | } catch ( FormatException | IOException e ) 223 | { 224 | // TODO Auto-generated catch block 225 | e.printStackTrace(); 226 | } 227 | 228 | 229 | return null; 230 | } 231 | 232 | public static final float getFloatValue( final byte[] b, final int i, final boolean isLittleEndian ) 233 | { 234 | if ( isLittleEndian ) 235 | return Float.intBitsToFloat( ((b[i+3] & 0xff) << 24) + ((b[i+2] & 0xff) << 16) + ((b[i+1] & 0xff) << 8) + (b[i] & 0xff) ); 236 | else 237 | return Float.intBitsToFloat( ((b[i] & 0xff) << 24) + ((b[i+1] & 0xff) << 16) + ((b[i+2] & 0xff) << 8) + (b[i+3] & 0xff) ); 238 | } 239 | 240 | 241 | public static Img< FloatType > openIJ( final String name, final ImgFactory< FloatType > factory ) 242 | { 243 | if ( !new File( name ).exists() ) 244 | throw new RuntimeException( "file '" + name + "' does not exisit." ); 245 | 246 | final Opener io = new Opener(); 247 | ImagePlus imp = io.openImage( name ); 248 | 249 | if ( imp.getStack().getSize() > 1 ) 250 | { 251 | final int depth = imp.getStack().getSize(); 252 | 253 | final Img img = factory.create( new int[]{ imp.getWidth(), imp.getHeight(), depth }, new FloatType() ); 254 | 255 | final RandomAccess< FloatType > r = img.randomAccess(); 256 | final int[] tmp = new int[]{ 0, 0, 0 }; 257 | 258 | for ( int i = 0; i < depth; ++i ) 259 | { 260 | final ImageProcessor ip = imp.getStack().getProcessor( i + 1 ); 261 | tmp[ 2 ] = i; 262 | tmp[ 0 ] = tmp[ 1 ] = 0; 263 | 264 | r.setPosition( tmp ); 265 | 266 | for ( int y = 0; y < imp.getHeight(); ++y ) 267 | { 268 | r.setPosition( y, 1 ); 269 | for ( int x = 0; x < imp.getWidth(); ++x ) 270 | { 271 | r.setPosition( x, 0 ); 272 | r.get().set( ip.getPixelValue( x, y ) ); 273 | } 274 | } 275 | } 276 | 277 | return img; 278 | } 279 | else 280 | { 281 | final Img img = factory.create( new int[]{ imp.getWidth(), imp.getHeight() }, new FloatType() ); 282 | 283 | final ImageProcessor ip = imp.getProcessor(); 284 | 285 | final Cursor cursorOut = img.cursor(); 286 | 287 | while ( cursorOut.hasNext() ) 288 | { 289 | cursorOut.fwd(); 290 | cursorOut.get().set( ip.getPixelValue( cursorOut.getIntPosition( 0 ), cursorOut.getIntPosition( 1 ) ) ); 291 | } 292 | 293 | return img; 294 | } 295 | } 296 | 297 | public static Img< FloatType > open( final String file, final boolean square ) 298 | { 299 | if ( square ) 300 | { 301 | return Tools.makeSquare( open( file, new ArrayImgFactory() ) ); 302 | } 303 | else 304 | { 305 | return open( file, new ArrayImgFactory() ); 306 | } 307 | } 308 | 309 | /** 310 | * Make quadratic image, pad with minimal intensity 311 | * 312 | * @param img - the input 313 | * @return - the squared image 314 | */ 315 | public static Img< FloatType > makeSquare( final Img< FloatType > img ) 316 | { 317 | final long[] tmp = new long[ img.numDimensions() ]; 318 | long maxSize = 0; 319 | 320 | for ( int d = 0; d < img.numDimensions(); ++d ) 321 | maxSize = Math.max( maxSize, img.dimension( d ) ); 322 | 323 | for ( int d = 0; d < img.numDimensions(); ++d ) 324 | tmp[ d ] = maxSize; 325 | 326 | float min = Float.MAX_VALUE; 327 | 328 | for ( final FloatType f : img ) 329 | min = Math.min( min, f.get() ); 330 | 331 | final Img< FloatType > square = img.factory().create( tmp, img.firstElement() ); 332 | 333 | final Cursor< FloatType > squareCursor = square.localizingCursor(); 334 | final RandomAccess< FloatType > inputCursor = Views.extendValue( img, new FloatType( min ) ).randomAccess(); 335 | 336 | while ( squareCursor.hasNext() ) 337 | { 338 | squareCursor.fwd(); 339 | squareCursor.localize( tmp ); 340 | 341 | for ( int d = 0; d < img.numDimensions(); ++d ) 342 | tmp[ d ] = tmp[ d ] - square.dimension( d )/2 + img.dimension( d )/2; 343 | 344 | inputCursor.setPosition( tmp ); 345 | squareCursor.get().set( inputCursor.get().get() ); 346 | } 347 | 348 | return square; 349 | } 350 | 351 | } 352 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/VolumeInjection.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation; 2 | 3 | import net.imglib2.Cursor; 4 | import net.imglib2.RandomAccess; 5 | import net.imglib2.RandomAccessible; 6 | import net.imglib2.RandomAccessibleInterval; 7 | import net.imglib2.img.Img; 8 | import net.imglib2.img.array.ArrayImgs; 9 | import net.imglib2.type.numeric.real.FloatType; 10 | import net.imglib2.util.Util; 11 | import net.imglib2.view.Views; 12 | 13 | public class VolumeInjection 14 | { 15 | final RandomAccessibleInterval< FloatType > image, weight; 16 | final RandomAccessible< FloatType > infinite, infWeight; 17 | final int numDimensions; 18 | final int[] size; 19 | final double[] two_sq_sigma; 20 | final double sumWeights; 21 | final int numPixels; 22 | 23 | public VolumeInjection( 24 | final RandomAccessibleInterval< FloatType > image, 25 | final RandomAccessibleInterval< FloatType > weight, 26 | final double[] sigma ) 27 | { 28 | this.numDimensions = sigma.length; 29 | this.image = image; 30 | this.weight = weight; 31 | this.infinite = Views.extendZero( image ); 32 | this.infWeight = Views.extendZero( weight ); 33 | 34 | this.size = new int[ numDimensions ]; 35 | 36 | this.two_sq_sigma = new double[ numDimensions ]; 37 | 38 | for ( int d = 0; d < numDimensions; ++d ) 39 | { 40 | if ( sigma[ d ] == 0 ) 41 | { 42 | size[ d ] = 1; 43 | two_sq_sigma[ d ] = 1; 44 | } 45 | else 46 | { 47 | size[ d ] = Util.getSuggestedKernelDiameter( sigma[ d ] ); 48 | two_sq_sigma[ d ] = 2 * sigma[ d ] * sigma[ d ]; 49 | } 50 | } 51 | 52 | double sumWeights = 0; 53 | int numPixels = 0; 54 | 55 | final Cursor< FloatType > cursor = getCursor( new double[] { 0.0, 0.0, 0.0 } ); 56 | 57 | while ( cursor.hasNext() ) 58 | { 59 | cursor.fwd(); 60 | 61 | double value = 1; 62 | 63 | for ( int d = 0; d < numDimensions; ++d ) 64 | value *= getGaussValue( 0, cursor.getLongPosition( d ), two_sq_sigma[ d ] ); 65 | 66 | sumWeights += value; 67 | ++numPixels; 68 | } 69 | 70 | this.sumWeights = sumWeights; 71 | this.numPixels = numPixels; 72 | } 73 | 74 | public int[] getSize() { return size; } 75 | 76 | public RandomAccessibleInterval< FloatType > getImage() { return image; } 77 | public RandomAccessibleInterval< FloatType > getWeight() { return weight; } 78 | 79 | public Img< FloatType > normalize() 80 | { 81 | return normalize( image, weight ); 82 | } 83 | 84 | public static Img< FloatType > normalize( final RandomAccessibleInterval< FloatType > image, final RandomAccessibleInterval< FloatType > weight) 85 | { 86 | final Img< FloatType > normed = ArrayImgs.floats( image.dimension( 0 ), image.dimension( 1 ), image.dimension( 2 ) ); 87 | 88 | normalize( normed, image, weight ); 89 | 90 | return normed; 91 | } 92 | 93 | public static void normalize( final RandomAccessibleInterval< FloatType > normed, final RandomAccessibleInterval< FloatType > image, final RandomAccessibleInterval< FloatType > weight ) 94 | { 95 | final Cursor< FloatType > c = Views.iterable( normed ).localizingCursor(); 96 | final RandomAccess< FloatType > rI = image.randomAccess(); 97 | final RandomAccess< FloatType > rW = weight.randomAccess(); 98 | 99 | while ( c.hasNext() ) 100 | { 101 | final FloatType pixel = c.next(); 102 | rI.setPosition( c ); 103 | rW.setPosition( c ); 104 | 105 | final float w = rW.get().get(); 106 | final float v = rI.get().get(); 107 | 108 | if ( w > 1.0f ) 109 | pixel.set( v / w ); 110 | else 111 | pixel.set( v ); 112 | } 113 | } 114 | 115 | public double getSumWeights() 116 | { 117 | return sumWeights; 118 | } 119 | 120 | public int getNumPixels() 121 | { 122 | return numPixels; 123 | } 124 | 125 | public final Cursor< FloatType > getCursor( final double[] location ) 126 | { 127 | final long[] min = new long[ numDimensions ]; 128 | final long[] max = new long[ numDimensions ]; 129 | 130 | for ( int d = 0; d < numDimensions; ++d ) 131 | { 132 | min[ d ] = Math.round( location[ d ] ) - size[ d ]/2; 133 | max[ d ] = min[ d ] + size[ d ] - 1; 134 | } 135 | 136 | final RandomAccessibleInterval< FloatType > interval = Views.interval( infinite, min, max ); 137 | return Views.iterable( interval ).localizingCursor(); 138 | } 139 | 140 | private static final double getGaussValue( final double gaussLocation, final long cursorLocation, final double two_sq_sigma ) 141 | { 142 | final double x = gaussLocation - cursorLocation; 143 | return Math.exp( -(x * x) / two_sq_sigma ); 144 | } 145 | 146 | public void addNormalizedGaussian( 147 | final double intensity, 148 | final double[] location ) 149 | { 150 | addGaussian( intensity / sumWeights, location ); 151 | } 152 | 153 | public void addGaussian( 154 | final double intensity, 155 | final double[] location ) 156 | { 157 | final Cursor< FloatType > cursor = getCursor( location ); 158 | final RandomAccess< FloatType > ra = infWeight.randomAccess(); 159 | 160 | while ( cursor.hasNext() ) 161 | { 162 | final FloatType pixel = cursor.next(); 163 | 164 | ra.setPosition( cursor ); 165 | final FloatType weight = ra.get(); 166 | 167 | double value = 1; 168 | 169 | for ( int d = 0; d < numDimensions; ++d ) 170 | value *= getGaussValue( location[ d ], cursor.getLongPosition( d ), two_sq_sigma[ d ] ); 171 | 172 | pixel.set( pixel.get() + (float)( value * intensity ) ); 173 | weight.set( weight.get() + (float)value ); 174 | } 175 | } 176 | 177 | public Img< FloatType > project() 178 | { 179 | final Img< FloatType > proj = ArrayImgs.floats( image.dimension( 0 ), image.dimension( 1 ) ); 180 | 181 | final RandomAccess< FloatType > ra = image.randomAccess(); 182 | final RandomAccess< FloatType > raW = weight.randomAccess(); 183 | final Cursor< FloatType > c = proj.localizingCursor(); 184 | 185 | while ( c.hasNext() ) 186 | { 187 | c.fwd(); 188 | ra.setPosition( c.getIntPosition( 0 ), 0 ); 189 | ra.setPosition( c.getIntPosition( 1 ), 1 ); 190 | 191 | double sum = 0; 192 | double count = 0; 193 | 194 | for ( int z = 0; z < image.dimension( 2 ); ++z ) 195 | { 196 | ra.setPosition( z, 2 ); 197 | raW.setPosition( ra ); 198 | 199 | if ( ra.get().get() > 0 ) 200 | { 201 | sum += ra.get().get() * raW.get().get(); 202 | count += raW.get().get(); 203 | } 204 | } 205 | 206 | c.get().setReal( sum / count ); 207 | } 208 | 209 | return proj; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/cluster/CreateScripts.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.cluster; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.FileWriter; 7 | import java.io.IOException; 8 | import java.io.PrintWriter; 9 | 10 | public class CreateScripts 11 | { 12 | public static void main( String[] args ) 13 | { 14 | createScripts(); 15 | } 16 | 17 | public static void createScripts() 18 | { 19 | PrintWriter f = openFileWrite( new File( "submitAll.sh" ) ); 20 | 21 | for ( int z = 0; z < 289; ++z ) 22 | { 23 | for ( int i = 0; i <= 1; ++i ) 24 | { 25 | String illum = i == 0 ? "false" : "true"; 26 | String jobFilename = "./job_"+ z + "_" + illum + ".sh"; 27 | String command = "./java -Xms4000M -Xmx4000M -jar multiview-simulation-0.2.1-SNAPSHOT-jar-with-dependencies.jar /fast/AG_Preibisch/Stephan/ " + z + " 3.0 1.0 1.1 " + illum; 28 | 29 | PrintWriter file = openFileWrite( new File( jobFilename ) ); 30 | file.println( "#!/bin/sh" ); 31 | file.println( command ); 32 | file.close(); 33 | 34 | f.println( "qsub -l h_vmem=34G " + jobFilename ); 35 | } 36 | } 37 | 38 | f.close(); 39 | } 40 | 41 | public static BufferedReader openFileRead(final File file) 42 | { 43 | BufferedReader inputFile; 44 | try 45 | { 46 | inputFile = new BufferedReader(new FileReader(file)); 47 | } 48 | catch (IOException e) 49 | { 50 | System.out.println("TextFileAccess.openFileRead(): " + e); 51 | inputFile = null; 52 | } 53 | return (inputFile); 54 | } 55 | 56 | public static PrintWriter openFileWrite(final File file) 57 | { 58 | PrintWriter outputFile; 59 | try 60 | { 61 | outputFile = new PrintWriter(new FileWriter(file)); 62 | } 63 | catch (IOException e) 64 | { 65 | System.out.println("TextFileAccess.openFileWrite(): " + e); 66 | outputFile = null; 67 | } 68 | return (outputFile); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/cluster/RunJob.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.cluster; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.FileWriter; 7 | import java.io.IOException; 8 | import java.io.PrintWriter; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | 12 | import ij.ImagePlus; 13 | import net.imglib2.RandomAccessibleInterval; 14 | import net.imglib2.img.display.imagej.ImageJFunctions; 15 | import net.imglib2.type.numeric.real.FloatType; 16 | import net.preibisch.simulation.SimulateMultiViewAberrations; 17 | 18 | public class RunJob 19 | { 20 | public static boolean isCluster = false; 21 | 22 | public static void display( final RandomAccessibleInterval< FloatType > image, final String name ) 23 | { 24 | if ( !isCluster ) 25 | { 26 | ImagePlus imp = ImageJFunctions.wrapFloat( image, name ).duplicate(); 27 | imp.setDimensions( 1, (int)image.dimension( 2 ), 1 ); 28 | imp.show(); 29 | } 30 | } 31 | 32 | public static void main( String[] args ) 33 | { 34 | isCluster = true; 35 | 36 | final String dir = args[ 0 ].trim(); 37 | final int zPlane = Integer.parseInt( args[ 1 ] ); 38 | final double lsMiddle = Double.parseDouble( args[ 2 ] ); 39 | final double lsEdge = Double.parseDouble( args[ 3 ] ); 40 | final double ri = Double.parseDouble( args[ 4 ] ); 41 | final boolean illum = Boolean.parseBoolean( args[ 5 ] ); // true > bottom, false > top 42 | 43 | //final double lsMiddle = 1.0; 44 | //final double lsEdge = 3.0; 45 | //final double ri = 1.005; 46 | 47 | final ExecutorService service = Executors.newFixedThreadPool( 1 ); 48 | 49 | System.out.println( "dir=" + dir ); 50 | System.out.println( "zPlane=" + zPlane ); 51 | System.out.println( "lsMiddle=" + lsMiddle ); 52 | System.out.println( "lsEdge=" + lsEdge ); 53 | System.out.println( "ri=" + ri ); 54 | System.out.println( "illum=" + illum ); 55 | 56 | SimulateMultiViewAberrations.simulate( illum, lsMiddle, lsEdge, ri, dir, service, zPlane ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/imgloader/LegacySimulatedBeadsImgLoader.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.imgloader; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | 29 | import mpicbg.spim.data.legacy.LegacyImgLoader; 30 | import mpicbg.spim.data.registration.ViewRegistration; 31 | import mpicbg.spim.data.registration.ViewRegistrations; 32 | import mpicbg.spim.data.registration.ViewTransform; 33 | import mpicbg.spim.data.registration.ViewTransformAffine; 34 | import mpicbg.spim.data.sequence.Angle; 35 | import mpicbg.spim.data.sequence.Channel; 36 | import mpicbg.spim.data.sequence.FinalVoxelDimensions; 37 | import mpicbg.spim.data.sequence.Illumination; 38 | import mpicbg.spim.data.sequence.TimePoint; 39 | import mpicbg.spim.data.sequence.TimePoints; 40 | import mpicbg.spim.data.sequence.ViewDescription; 41 | import mpicbg.spim.data.sequence.ViewId; 42 | import mpicbg.spim.data.sequence.ViewSetup; 43 | import mpicbg.spim.data.sequence.VoxelDimensions; 44 | import net.imglib2.Cursor; 45 | import net.imglib2.Dimensions; 46 | import net.imglib2.FinalDimensions; 47 | import net.imglib2.Interval; 48 | import net.imglib2.RandomAccessibleInterval; 49 | import net.imglib2.img.Img; 50 | import net.imglib2.img.array.ArrayImgs; 51 | import net.imglib2.realtransform.AffineTransform3D; 52 | import net.imglib2.type.numeric.integer.UnsignedShortType; 53 | import net.imglib2.type.numeric.real.FloatType; 54 | import net.preibisch.simulation.SimulateBeads; 55 | 56 | public class LegacySimulatedBeadsImgLoader implements LegacyImgLoader< UnsignedShortType > 57 | { 58 | final SimulateBeads sb; 59 | 60 | public LegacySimulatedBeadsImgLoader( 61 | final int[] angles, 62 | final int axis, 63 | final int numPoints, 64 | final Interval rangeSimulation, 65 | final Interval intervalRender, 66 | final double[] sigma ) 67 | { 68 | this( new SimulateBeads( angles, axis, numPoints, rangeSimulation, intervalRender, sigma ) ); 69 | } 70 | 71 | public LegacySimulatedBeadsImgLoader( final SimulateBeads sb ) { this.sb = sb; } 72 | 73 | public SimulateBeads getSimulateBeads() { return sb; } 74 | 75 | @Override 76 | public RandomAccessibleInterval< UnsignedShortType > getImage( final ViewId view ) 77 | { 78 | final long[] dim = new long[ sb.getImgs().get( view.getViewSetupId() ).numDimensions() ]; 79 | 80 | for ( int d = 0; d < dim.length; ++d ) 81 | dim[ d ] = sb.getImgs().get( view.getViewSetupId() ).dimension( d ); 82 | 83 | final Img< UnsignedShortType > img = ArrayImgs.unsignedShorts( dim ); 84 | 85 | final Cursor< FloatType > in = sb.getImgs().get( view.getViewSetupId() ).cursor(); 86 | final Cursor< UnsignedShortType > out = img.cursor(); 87 | 88 | while ( in.hasNext() ) 89 | out.next().set( Math.round( in.next().get() ) ); 90 | 91 | return img; 92 | } 93 | 94 | @Override 95 | public UnsignedShortType getImageType() { return new UnsignedShortType(); } 96 | 97 | @Override 98 | public RandomAccessibleInterval getFloatImage( final ViewId view, boolean normalize ) 99 | { 100 | if ( normalize ) 101 | { 102 | return normalize( sb.getImgs().get( view.getViewSetupId() ).copy() ); 103 | } 104 | else 105 | { 106 | return sb.getImgs().get( view.getViewSetupId() ).copy(); 107 | } 108 | } 109 | 110 | @Override 111 | public Dimensions getImageSize( final ViewId view ) { return sb.getImgs().get( view.getViewSetupId() ); } 112 | 113 | @Override 114 | public VoxelDimensions getVoxelSize( final ViewId view ) { return new FinalVoxelDimensions( "pixel", 1, 1, 1 ); } 115 | 116 | protected static final Img< FloatType > normalize( final Img< FloatType > img ) 117 | { 118 | float min = Float.MAX_VALUE; 119 | float max = -Float.MAX_VALUE; 120 | 121 | for ( final FloatType t : img ) 122 | { 123 | final float v = t.get(); 124 | 125 | if ( v < min ) 126 | min = v; 127 | 128 | if ( v > max ) 129 | max = v; 130 | } 131 | 132 | for ( final FloatType t : img ) 133 | t.set( ( t.get() - min ) / ( max - min ) ); 134 | 135 | return img; 136 | } 137 | 138 | public static ViewRegistrations createViewRegistrations( final Map< ViewId, ViewDescription > viewDescriptionList, final double minResolution ) 139 | { 140 | final HashMap< ViewId, ViewRegistration > viewRegistrationList = new HashMap< ViewId, ViewRegistration >(); 141 | 142 | for ( final ViewDescription viewDescription : viewDescriptionList.values() ) 143 | if ( viewDescription.isPresent() ) 144 | { 145 | final ViewRegistration viewRegistration = new ViewRegistration( viewDescription.getTimePointId(), viewDescription.getViewSetupId() ); 146 | 147 | final VoxelDimensions voxelSize = viewDescription.getViewSetup().getVoxelSize(); 148 | 149 | final double calX = voxelSize.dimension( 0 ) / minResolution; 150 | final double calY = voxelSize.dimension( 1 ) / minResolution; 151 | final double calZ = voxelSize.dimension( 2 ) / minResolution; 152 | 153 | final AffineTransform3D m = new AffineTransform3D(); 154 | m.set( calX, 0.0f, 0.0f, 0.0f, 155 | 0.0f, calY, 0.0f, 0.0f, 156 | 0.0f, 0.0f, calZ, 0.0f ); 157 | final ViewTransform vt = new ViewTransformAffine( "calibration", m ); 158 | viewRegistration.preconcatenateTransform( vt ); 159 | 160 | viewRegistrationList.put( viewRegistration, viewRegistration ); 161 | } 162 | 163 | return new ViewRegistrations( viewRegistrationList ); 164 | } 165 | 166 | public static TimePoints createTimepoints() 167 | { 168 | final ArrayList< TimePoint > timepointList = new ArrayList< TimePoint >(); 169 | timepointList.add( new TimePoint( 0 ) ); 170 | return new TimePoints( timepointList ); 171 | } 172 | 173 | public static ArrayList< ViewSetup > createViewSetups( final int[] rotations, final int rotationAxis, final Interval range ) 174 | { 175 | final ArrayList< Channel > channels = new ArrayList< Channel >(); 176 | channels.add( new Channel( 0, "Channel1" ) ); 177 | 178 | final ArrayList< Illumination > illuminations = new ArrayList< Illumination >(); 179 | illuminations.add( new Illumination( 0, "Illum1" ) ); 180 | 181 | final ArrayList< Angle > angles = new ArrayList< Angle >(); 182 | for ( int a = 0; a < rotations.length; ++a ) 183 | { 184 | final Angle angle = new Angle( a, String.valueOf( rotations[ a ] ) ); 185 | 186 | final double degrees = rotations[ a ]; 187 | double[] axis = new double[ 3 ]; 188 | 189 | axis[ rotationAxis ] = 1; 190 | angle.setRotation( axis, degrees ); 191 | 192 | angles.add( angle ); 193 | } 194 | 195 | final ArrayList< ViewSetup > viewSetups = new ArrayList< ViewSetup >(); 196 | for ( final Channel c : channels ) 197 | for ( final Illumination i : illuminations ) 198 | for ( final Angle a : angles ) 199 | { 200 | final VoxelDimensions voxelSize = new FinalVoxelDimensions( "pixels", 1, 1, 1 ); 201 | final Dimensions dim = new FinalDimensions( new long[]{ range.max( 0 ) - range.min( 0 ), range.max( 1 ) - range.min( 1 ), range.max( 2 ) - range.min( 2 ) } ); 202 | viewSetups.add( new ViewSetup( viewSetups.size(), null, dim, voxelSize, c, a, i ) ); 203 | } 204 | 205 | return viewSetups; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/imgloader/LegacySimulatedBeadsImgLoader2.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.imgloader; 24 | 25 | import java.util.Arrays; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | import mpicbg.spim.data.legacy.LegacyImgLoader; 31 | import mpicbg.spim.data.sequence.FinalVoxelDimensions; 32 | import mpicbg.spim.data.sequence.ViewId; 33 | import mpicbg.spim.data.sequence.VoxelDimensions; 34 | import net.imglib2.Cursor; 35 | import net.imglib2.Dimensions; 36 | import net.imglib2.RandomAccessibleInterval; 37 | import net.imglib2.img.Img; 38 | import net.imglib2.img.array.ArrayImgs; 39 | import net.imglib2.type.numeric.integer.UnsignedShortType; 40 | import net.imglib2.type.numeric.real.FloatType; 41 | import net.preibisch.simulation.SimulateBeads; 42 | import net.preibisch.simulation.SimulateBeads2; 43 | 44 | public class LegacySimulatedBeadsImgLoader2 implements LegacyImgLoader< UnsignedShortType > 45 | { 46 | final SimulateBeads2 sb; 47 | final Map> vidToDescription; 48 | 49 | public LegacySimulatedBeadsImgLoader2( final SimulateBeads2 sb ) 50 | { 51 | this.sb = sb; 52 | this.vidToDescription = new HashMap<>(); 53 | } 54 | 55 | 56 | public void addViewId(int idx, int tp, int angle, int channel, int tile, int illumination) 57 | { 58 | List< Integer > val = Arrays.asList( new Integer[] {tp, angle, channel, tile, illumination} ); 59 | vidToDescription.put( new ViewId(tp, idx), val ); 60 | } 61 | 62 | public SimulateBeads2 getSimulateBeads() { return sb; } 63 | 64 | @Override 65 | public RandomAccessibleInterval< UnsignedShortType > getImage(ViewId view) 66 | { 67 | List< Integer > key = vidToDescription.get( view ); 68 | System.out.println( key ); 69 | Img< FloatType > imgF = sb.getImg(key.get( 0 ), key.get( 1 ), key.get( 2 ), key.get( 3 ), key.get( 4 )); 70 | final long[] dim = new long[ imgF.numDimensions() ]; 71 | 72 | for ( int d = 0; d < dim.length; ++d ) 73 | dim[ d ] = imgF.dimension( d ); 74 | 75 | final Img< UnsignedShortType > img = ArrayImgs.unsignedShorts( dim ); 76 | 77 | final Cursor< FloatType > in = imgF.cursor(); 78 | final Cursor< UnsignedShortType > out = img.cursor(); 79 | 80 | while ( in.hasNext() ) 81 | out.next().set( Math.round( in.next().get() ) ); 82 | 83 | return img; 84 | } 85 | 86 | @Override 87 | public UnsignedShortType getImageType() 88 | { 89 | return new UnsignedShortType(); 90 | } 91 | 92 | 93 | @Override 94 | public RandomAccessibleInterval< FloatType > getFloatImage(ViewId view, boolean normalize) 95 | { 96 | List< Integer > key = vidToDescription.get( view ); 97 | Img< FloatType > imgF = sb.getImg(key.get( 0 ), key.get( 1 ), key.get( 2 ), key.get( 3 ), key.get( 4 )); 98 | if ( normalize ) 99 | { 100 | return LegacySimulatedBeadsImgLoader.normalize( imgF.copy() ); 101 | } 102 | else 103 | { 104 | return imgF.copy(); 105 | } 106 | } 107 | 108 | @Override 109 | public Dimensions getImageSize(ViewId view) 110 | { 111 | List< Integer > key = vidToDescription.get( view ); 112 | Img< FloatType > imgF = sb.getImg(key.get( 0 ), key.get( 1 ), key.get( 2 ), key.get( 3 ), key.get( 4 )); 113 | return imgF; 114 | } 115 | 116 | @Override 117 | public VoxelDimensions getVoxelSize(ViewId view) 118 | { 119 | return new FinalVoxelDimensions( "pixel", 1, 1, 1 ); 120 | } 121 | 122 | 123 | 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/imgloader/SimulatedBeadsImgLoader.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.imgloader; 24 | 25 | import java.io.File; 26 | import java.util.ArrayList; 27 | 28 | import mpicbg.spim.data.SpimData; 29 | import mpicbg.spim.data.SpimDataException; 30 | import mpicbg.spim.data.XmlIoSpimData; 31 | import mpicbg.spim.data.legacy.LegacyImgLoaderWrapper; 32 | import mpicbg.spim.data.registration.ViewRegistrations; 33 | import mpicbg.spim.data.sequence.ImgLoader; 34 | import mpicbg.spim.data.sequence.MissingViews; 35 | import mpicbg.spim.data.sequence.SequenceDescription; 36 | import mpicbg.spim.data.sequence.TimePoints; 37 | import mpicbg.spim.data.sequence.ViewSetup; 38 | import net.imglib2.FinalInterval; 39 | import net.imglib2.Interval; 40 | import net.imglib2.type.numeric.integer.UnsignedShortType; 41 | import net.preibisch.simulation.SimulateBeads; 42 | 43 | public class SimulatedBeadsImgLoader extends LegacyImgLoaderWrapper< UnsignedShortType, LegacySimulatedBeadsImgLoader > 44 | { 45 | public SimulatedBeadsImgLoader( final SimulateBeads sb ) 46 | { 47 | super( new LegacySimulatedBeadsImgLoader( sb ) ); 48 | } 49 | 50 | public SimulateBeads getSimulateBeads() { return legacyImgLoader.getSimulateBeads(); } 51 | 52 | @Override 53 | public String toString() { 54 | return legacyImgLoader.toString(); 55 | } 56 | 57 | public static void save( final SpimData spimData, final String xmlFilename ) throws SpimDataException 58 | { 59 | XmlIoSpimData xml = new XmlIoSpimData(); 60 | xml.save( spimData, xmlFilename ); 61 | } 62 | 63 | public static SpimData spimdataExample( final int[] angles ) 64 | { 65 | final int axis = 0; 66 | final int numPoints = 1000; 67 | final double[] sigma = new double[]{ 1, 1, 3 }; 68 | final FinalInterval range = new FinalInterval( 512, 512, 200 ); 69 | 70 | return spimdataExample( angles, axis, numPoints, sigma, range ); 71 | } 72 | 73 | public static SpimData spimdataExample() 74 | { 75 | final int[] angles = new int[]{ 0, 45, 90, 135 }; 76 | 77 | return spimdataExample( angles ); 78 | } 79 | 80 | public static SpimData spimdataExample( final int[] angles, final int axis, final int numPoints, final double[] sigma, final Interval range ) 81 | { 82 | final TimePoints timepoints = LegacySimulatedBeadsImgLoader.createTimepoints(); 83 | final ArrayList< ViewSetup > setups = LegacySimulatedBeadsImgLoader.createViewSetups( angles, axis, range ); 84 | final MissingViews missingViews = null; 85 | 86 | final SimulateBeads sb = new SimulateBeads( angles, axis, numPoints, range, range, sigma ); 87 | 88 | final SequenceDescription sequenceDescription = new SequenceDescription( timepoints, setups, null, missingViews ); 89 | final ImgLoader imgLoader = new SimulatedBeadsImgLoader( sb ); 90 | sequenceDescription.setImgLoader( imgLoader ); 91 | 92 | // get the minimal resolution of all calibrations 93 | final double minResolution = 1.0; 94 | 95 | final ViewRegistrations viewRegistrations = LegacySimulatedBeadsImgLoader.createViewRegistrations( sequenceDescription.getViewDescriptions(), minResolution ); 96 | 97 | // finally create the SpimData itself based on the sequence description and the view registration 98 | final SpimData spimData = new SpimData( new File( "" ), sequenceDescription, viewRegistrations ); 99 | 100 | return spimData; 101 | } 102 | 103 | public static void main( String[] args ) throws SpimDataException 104 | { 105 | final SpimData d = SimulatedBeadsImgLoader.spimdataExample(); 106 | save( d, new File( "simulated.xml" ).getAbsolutePath() ); 107 | System.out.println( "done" ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/imgloader/SimulatedBeadsImgLoader2.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.imgloader; 24 | 25 | import java.io.File; 26 | import java.util.ArrayList; 27 | import java.util.Arrays; 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.concurrent.atomic.AtomicInteger; 31 | import java.util.stream.Collectors; 32 | 33 | import ij.gui.GenericDialog; 34 | import mpicbg.spim.data.SpimData; 35 | import mpicbg.spim.data.legacy.LegacyImgLoaderWrapper; 36 | import mpicbg.spim.data.registration.ViewRegistration; 37 | import mpicbg.spim.data.registration.ViewRegistrations; 38 | import mpicbg.spim.data.registration.ViewTransform; 39 | import mpicbg.spim.data.registration.ViewTransformAffine; 40 | import mpicbg.spim.data.sequence.Angle; 41 | import mpicbg.spim.data.sequence.Channel; 42 | import mpicbg.spim.data.sequence.FinalVoxelDimensions; 43 | import mpicbg.spim.data.sequence.Illumination; 44 | import mpicbg.spim.data.sequence.MissingViews; 45 | import mpicbg.spim.data.sequence.SequenceDescription; 46 | import mpicbg.spim.data.sequence.Tile; 47 | import mpicbg.spim.data.sequence.TimePoint; 48 | import mpicbg.spim.data.sequence.TimePoints; 49 | import mpicbg.spim.data.sequence.ViewDescription; 50 | import mpicbg.spim.data.sequence.ViewId; 51 | import mpicbg.spim.data.sequence.ViewSetup; 52 | import mpicbg.spim.data.sequence.VoxelDimensions; 53 | import net.imglib2.Dimensions; 54 | import net.imglib2.FinalDimensions; 55 | import net.imglib2.Interval; 56 | import net.imglib2.RandomAccessibleInterval; 57 | import net.imglib2.RealInterval; 58 | import net.imglib2.img.display.imagej.ImageJFunctions; 59 | import net.imglib2.realtransform.AffineTransform3D; 60 | import net.imglib2.realtransform.Translation; 61 | import net.imglib2.realtransform.Translation3D; 62 | import net.imglib2.type.numeric.integer.UnsignedShortType; 63 | import net.imglib2.util.Intervals; 64 | import net.imglib2.util.Util; 65 | import net.preibisch.simulation.RegularTranformHelpers; 66 | import net.preibisch.simulation.SimulateBeads2; 67 | import net.preibisch.simulation.RegularTranformHelpers.RegularTranslationParameters; 68 | 69 | public class SimulatedBeadsImgLoader2 extends LegacyImgLoaderWrapper< UnsignedShortType, LegacySimulatedBeadsImgLoader2 > 70 | { 71 | 72 | public SimulatedBeadsImgLoader2(final SimulateBeads2 sb, 73 | int rotAxis, 74 | double[] ratations, 75 | List channelShifts, 76 | List illumShifts, 77 | List timeShifts, 78 | List tileShifts 79 | ) 80 | { 81 | super( new LegacySimulatedBeadsImgLoader2( sb ) ); 82 | 83 | for (int tp = 0; tp createViewSetupsFromImgLoader(SimulatedBeadsImgLoader2 imgLoader) 116 | { 117 | final ArrayList< ViewSetup > viewSetups = new ArrayList< ViewSetup >(); 118 | SimulateBeads2 sb = imgLoader.getSimulateBeads(); 119 | int vid = 0; 120 | for (int a : new ArrayList<>(sb.angleTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 121 | for (int channel : new ArrayList<>(sb.channelTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 122 | for (int illum : new ArrayList<>(sb.illumTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 123 | for (int tile : new ArrayList<>(sb.tileTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 124 | { 125 | final VoxelDimensions voxelSize = new FinalVoxelDimensions( "pixels", 1, 1, 1 ); 126 | final Dimensions dim = imgLoader.getSimulateBeads().getImg( 0, a, channel, tile, illum ); 127 | 128 | viewSetups.add( new ViewSetup( vid++, Integer.toString( vid ), dim, voxelSize, new Tile(tile), new Channel(channel), new Angle(a), new Illumination(illum) ) ); 129 | } 130 | 131 | return viewSetups; 132 | } 133 | 134 | public static TimePoints createTimePointsFromImgLoader(SimulatedBeadsImgLoader2 imgLoader) 135 | { 136 | final ArrayList< TimePoint > timepointList = new ArrayList< TimePoint >(); 137 | SimulateBeads2 sb = imgLoader.getSimulateBeads(); 138 | for (int tp : new ArrayList<>(sb.tpTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 139 | timepointList.add( new TimePoint( tp ) ); 140 | return new TimePoints( timepointList ); 141 | 142 | } 143 | 144 | public static ViewRegistrations createViewRegistrationsFromImgLoader(SimulatedBeadsImgLoader2 imgLoader, double relativeTileError, boolean centerAngles) 145 | { 146 | SimulateBeads2 sb = imgLoader.getSimulateBeads(); 147 | final HashMap< ViewId, ViewRegistration > viewRegistrationList = new HashMap< ViewId, ViewRegistration >(); 148 | final RealInterval tilesExtent = sb.getTilesExtent(); 149 | double[] center = new double[tilesExtent.numDimensions()]; 150 | tilesExtent.realMax( center ); 151 | 152 | for (int d = 0; d < center.length; d++) 153 | center[d] /= -2.0; 154 | 155 | for (int tp : new ArrayList<>(sb.tpTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 156 | { 157 | int vid = 0; 158 | for (int a : new ArrayList<>(sb.angleTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 159 | for (int channel : new ArrayList<>(sb.channelTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 160 | for (int illum : new ArrayList<>(sb.illumTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 161 | for (int tile : new ArrayList<>(sb.tileTransforms.keySet()).stream().sorted().collect( Collectors.toList() )) 162 | { 163 | final VoxelDimensions voxelSize = new FinalVoxelDimensions( "pixels", 1, 1, 1 ); 164 | final Dimensions dim = imgLoader.getSimulateBeads().getImg( 0, a, channel, tile, illum ); 165 | 166 | 167 | 168 | 169 | final ViewRegistration viewRegistration = new ViewRegistration( tp, vid++ ); 170 | 171 | 172 | final double calX = voxelSize.dimension( 0 ); 173 | final double calY = voxelSize.dimension( 1 ); 174 | final double calZ = voxelSize.dimension( 2 ); 175 | 176 | final AffineTransform3D m = new AffineTransform3D(); 177 | m.set( calX, 0.0f, 0.0f, 0.0f, 178 | 0.0f, calY, 0.0f, 0.0f, 179 | 0.0f, 0.0f, calZ, 0.0f ); 180 | final ViewTransform vt = new ViewTransformAffine( "calibration", m ); 181 | viewRegistration.preconcatenateTransform( vt ); 182 | 183 | double[] translation = sb.tileTransforms.get( tile ).inverse().getTranslation(); 184 | for (int i = 0; i < translation.length; i++) 185 | translation[i] *= relativeTileError; 186 | 187 | AffineTransform3D atr = new AffineTransform3D(); 188 | atr.translate( translation ); 189 | final ViewTransform vtT = new ViewTransformAffine("translation" , atr.copy() ); 190 | viewRegistration.preconcatenateTransform( vtT ); 191 | 192 | if (centerAngles) 193 | { 194 | AffineTransform3D centerTr = new AffineTransform3D(); 195 | centerTr.translate( center ); 196 | final ViewTransform centerVt = new ViewTransformAffine("center angle" , centerTr.copy() ); 197 | viewRegistration.preconcatenateTransform( centerVt ); 198 | } 199 | 200 | final ViewTransform vtA = new ViewTransformAffine("rotation" , sb.angleTransforms.get( a )); 201 | viewRegistration.preconcatenateTransform( vtA ); 202 | 203 | 204 | 205 | 206 | 207 | viewRegistrationList.put( viewRegistration, viewRegistration ); 208 | 209 | 210 | } 211 | } 212 | return new ViewRegistrations( viewRegistrationList ); 213 | } 214 | 215 | public static SpimData createSpimData( 216 | int numPoints, 217 | double[] sigma, 218 | Interval rangeSimulation, 219 | Interval intervalRender, 220 | int rotAxis, 221 | double[] ratations, 222 | List channelShifts, 223 | List illumShifts, 224 | List timeShifts, 225 | List tileShifts, 226 | double relativeTileError, 227 | boolean centerAngles 228 | ) 229 | { 230 | SimulateBeads2 sb = new SimulateBeads2( numPoints, sigma, rangeSimulation, intervalRender ); 231 | SimulatedBeadsImgLoader2 loader = new SimulatedBeadsImgLoader2( sb, rotAxis, ratations, channelShifts, illumShifts, timeShifts, tileShifts ); 232 | 233 | 234 | SequenceDescription sd = new SequenceDescription( createTimePointsFromImgLoader( loader ), createViewSetupsFromImgLoader( loader ), 235 | null, new MissingViews( new ArrayList<>() ) ); 236 | 237 | sd.setImgLoader( loader ); 238 | SpimData res = new SpimData( new File(""), sd, createViewRegistrationsFromImgLoader( loader, relativeTileError, centerAngles ) ); 239 | 240 | return res; 241 | 242 | } 243 | 244 | 245 | public static SpimData createSpimDataFromUserInput() 246 | { 247 | GenericDialog gd = new GenericDialog( "Simulated SpimData Parameters" ); 248 | 249 | gd.addNumericField( "number of points", 2000, 0 ); 250 | gd.addStringField( "Gaussian sigmas", "1,1,3" ); 251 | 252 | gd.addMessage( "Please enter Intervals in the form: min1,...,mini,max1,...maxi" ); 253 | gd.addStringField( "Simulation Interval", "-512,-512,-512,512,512,512", 35 ); 254 | gd.addStringField( "Viewport Interval", "0,0,0,256,256,100", 35 ); 255 | 256 | 257 | gd.addNumericField( "Number of TimePoints", 1, 0 ); 258 | gd.addNumericField( "Number of Channels", 1, 0 ); 259 | gd.addNumericField( "Number of Illuminations", 1, 0 ); 260 | 261 | gd.addNumericField( "Number of Tiles X", 1, 0 ); 262 | gd.addNumericField( "Number of Tiles Y", 1, 0 ); 263 | gd.addNumericField( "Tile Overlap", 0.15, 3); 264 | gd.addMessage( "Actual tile shifts will be multiplied by relative error in metadata" ); 265 | gd.addNumericField( "Tile Metadata Error", 1, 3); 266 | 267 | gd.addStringField( "Angles", "0,90" ); 268 | gd.addNumericField( "Angle Axis of Rotation", 1, 0 ); 269 | 270 | gd.addCheckbox( "center angles before rotation", true ); 271 | 272 | 273 | gd.showDialog(); 274 | if (gd.wasCanceled()) 275 | return null; 276 | 277 | int numPoints = (int) gd.getNextNumber(); 278 | String[] sigmasString = gd.getNextString().split( "," ); 279 | double[] sigmas = new double[sigmasString.length]; 280 | { 281 | AtomicInteger i = new AtomicInteger( 0 ); 282 | Arrays.asList( sigmasString ).forEach( (s) -> sigmas[i.getAndIncrement()] = Double.parseDouble( s ) ); 283 | } 284 | String[] simMinMaxString = gd.getNextString().split( "," ); 285 | long[] simMinMax = new long[simMinMaxString.length]; 286 | { 287 | AtomicInteger i = new AtomicInteger( 0 ); 288 | Arrays.asList( simMinMaxString ).forEach( (s) -> simMinMax[i.getAndIncrement()] = Long.parseLong( s ) ); 289 | } 290 | String[] vpMinMaxString = gd.getNextString().split( "," ); 291 | long[] vpMinMax = new long[vpMinMaxString.length]; 292 | { 293 | AtomicInteger i = new AtomicInteger( 0 ); 294 | Arrays.asList( vpMinMaxString ).forEach( (s) -> vpMinMax[i.getAndIncrement()] = Long.parseLong( s ) ); 295 | } 296 | 297 | int numTP = Math.max(1, (int) gd.getNextNumber()); 298 | int numChannels = Math.max(1, (int) gd.getNextNumber()); 299 | int numIllums = Math.max(1, (int) gd.getNextNumber()); 300 | 301 | int numTilesX = Math.max(1, (int) gd.getNextNumber()); 302 | int numTilesY = Math.max(1, (int) gd.getNextNumber()); 303 | 304 | double overlap = gd.getNextNumber(); 305 | double relError = gd.getNextNumber(); 306 | 307 | String[] anglesString = gd.getNextString().split( "," ); 308 | double[] angles = new double[anglesString.length]; 309 | { 310 | AtomicInteger i = new AtomicInteger( 0 ); 311 | Arrays.asList( anglesString ).forEach( (s) -> angles[i.getAndIncrement()] = Double.parseDouble( s ) ); 312 | } 313 | 314 | int rotAxis = (int) gd.getNextNumber(); 315 | 316 | boolean center = gd.getNextBoolean(); 317 | 318 | 319 | 320 | GenericDialog gd2 = new GenericDialog("View Errors"); 321 | 322 | for (int i = 0 ; i < numTP; i++) 323 | gd2.addStringField( "TP " + i + " error", "0,0,0" ); 324 | 325 | for (int i = 0 ; i < numChannels; i++) 326 | gd2.addStringField( "Channel " + i + " error", "0,0,0" ); 327 | 328 | for (int i = 0 ; i < numIllums; i++) 329 | gd2.addStringField( "Illumination " + i + " error", "0,0,0" ); 330 | 331 | gd2.showDialog(); 332 | if (gd2.wasCanceled()) 333 | return null; 334 | 335 | List channelShifts = new ArrayList<>(); 336 | List illumShifts = new ArrayList<>(); 337 | List timeShifts = new ArrayList<>(); 338 | 339 | for (int i = 0 ; i < numTP; i++) 340 | { 341 | String[] shiftString = gd2.getNextString().split( "," ); 342 | double[] shift = new double[shiftString.length]; 343 | { 344 | AtomicInteger j = new AtomicInteger( 0 ); 345 | Arrays.asList( shiftString ).forEach( (s) -> shift[j.getAndIncrement()] = Double.parseDouble( s ) ); 346 | } 347 | timeShifts.add( shift ); 348 | } 349 | 350 | for (int i = 0 ; i < numChannels; i++) 351 | { 352 | String[] shiftString = gd2.getNextString().split( "," ); 353 | double[] shift = new double[shiftString.length]; 354 | { 355 | AtomicInteger j = new AtomicInteger( 0 ); 356 | Arrays.asList( shiftString ).forEach( (s) -> shift[j.getAndIncrement()] = Double.parseDouble( s ) ); 357 | } 358 | channelShifts.add( shift ); 359 | } 360 | 361 | for (int i = 0 ; i < numIllums; i++) 362 | { 363 | String[] shiftString = gd2.getNextString().split( "," ); 364 | double[] shift = new double[shiftString.length]; 365 | { 366 | AtomicInteger j = new AtomicInteger( 0 ); 367 | Arrays.asList( shiftString ).forEach( (s) -> shift[j.getAndIncrement()] = Double.parseDouble( s ) ); 368 | } 369 | illumShifts.add( shift ); 370 | } 371 | 372 | RegularTranslationParameters params = new RegularTranslationParameters(); 373 | params.nDimensions = 3; 374 | params.alternating = new boolean[] {true, true, true}; 375 | params.dimensionOrder = new int[] {0, 1, 2}; 376 | params.increasing = new boolean[] {true, true, true}; 377 | params.overlaps = new double[] {overlap, overlap, overlap}; 378 | params.nSteps = new int[] {numTilesX, numTilesY, 1}; 379 | List< AffineTransform3D > generateRegularGrid = RegularTranformHelpers.generateRegularGrid( params, Intervals.createMinMax( vpMinMax ) ); 380 | 381 | List tileShifts = new ArrayList<>(); 382 | generateRegularGrid.forEach( ( t ) -> tileShifts.add( t.getTranslation() )); 383 | 384 | 385 | return createSpimData( numPoints, sigmas, Intervals.createMinMax( simMinMax ), Intervals.createMinMax( vpMinMax ), rotAxis, angles, channelShifts, illumShifts, timeShifts, tileShifts, relError, center ); 386 | } 387 | 388 | public static void main(String[] args) 389 | { 390 | SpimData sd2 = createSpimDataFromUserInput(); 391 | RandomAccessibleInterval< UnsignedShortType > img2 = (RandomAccessibleInterval< UnsignedShortType >) sd2.getSequenceDescription().getImgLoader().getSetupImgLoader( 0 ).getImage( 0, null ); 392 | ImageJFunctions.show( img2 ); 393 | if (true) 394 | return; 395 | 396 | List channelShifts = new ArrayList<>(); 397 | channelShifts.add( new double[3] ); 398 | List illumShifts = new ArrayList<>(); 399 | illumShifts.add( new double[3] ); 400 | List timeShifts = new ArrayList<>(); 401 | timeShifts.add( new double[3] ); 402 | timeShifts.add( new double[3] ); 403 | List tileShifts = new ArrayList<>(); 404 | tileShifts.add( new double[3] ); 405 | 406 | SpimData sd = createSpimData( 1000, new double[] {1, 1, 3 }, Intervals.createMinMax( 0,0,0,256,256,100 ), 407 | Intervals.createMinMax( 0,0,0,256,256,100 ), 1, new double[] {0, 90}, channelShifts, illumShifts, timeShifts, tileShifts , 0.9, true); 408 | 409 | RandomAccessibleInterval< UnsignedShortType > img = (RandomAccessibleInterval< UnsignedShortType >) sd.getSequenceDescription().getImgLoader().getSetupImgLoader( 0 ).getImage( 1, null ); 410 | ImageJFunctions.show( img ); 411 | } 412 | 413 | } 414 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/imgloader/XmlIoSimulatedBeadsImgLoader.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.imgloader; 24 | 25 | import static mpicbg.spim.data.XmlKeys.IMGLOADER_FORMAT_ATTRIBUTE_NAME; 26 | 27 | import java.io.File; 28 | 29 | import mpicbg.spim.data.XmlHelpers; 30 | import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription; 31 | import mpicbg.spim.data.generic.sequence.ImgLoaderIo; 32 | import mpicbg.spim.data.generic.sequence.XmlIoBasicImgLoader; 33 | import net.imglib2.FinalInterval; 34 | import net.preibisch.simulation.SimulateBeads; 35 | 36 | import org.jdom2.Element; 37 | 38 | @ImgLoaderIo( format = "spimreconstruction.simulatedbeads", type = SimulatedBeadsImgLoader.class ) 39 | public class XmlIoSimulatedBeadsImgLoader implements XmlIoBasicImgLoader< SimulatedBeadsImgLoader > 40 | { 41 | public static final String DIRECTORY_TAG = "imagedirectory"; 42 | public static final String MASTER_FILE_TAG = "masterfile"; 43 | public static final String IMGLIB2CONTAINER_PATTERN_TAG = "imglib2container"; 44 | 45 | @Override 46 | public Element toXml( final SimulatedBeadsImgLoader imgLoader, final File basePath ) 47 | { 48 | final Element elem = new Element( "ImageLoader" ); 49 | elem.setAttribute( IMGLOADER_FORMAT_ATTRIBUTE_NAME, this.getClass().getAnnotation( ImgLoaderIo.class ).format() ); 50 | 51 | final SimulateBeads sb = imgLoader.getSimulateBeads(); 52 | 53 | final int[] rangeSimulation = new int[ 6 ]; 54 | final int[] intervalRender = new int[ 6 ]; 55 | 56 | for ( int d = 0; d < 3; ++d ) 57 | { 58 | rangeSimulation[ d ] = (int)sb.rangeSimulation.min( d ); 59 | intervalRender[ d ] = (int)sb.intervalRender.min( d ); 60 | 61 | rangeSimulation[ d + 3 ] = (int)sb.rangeSimulation.max( d ); 62 | intervalRender[ d + 3 ] = (int)sb.intervalRender.max( d ); 63 | } 64 | 65 | elem.addContent( XmlHelpers.intArrayElement( "rotation_angles", sb.angles ) ); 66 | elem.addContent( XmlHelpers.intElement( "axis", sb.axis ) ); 67 | elem.addContent( XmlHelpers.intElement( "num_points", sb.numPoints ) ); 68 | elem.addContent( XmlHelpers.intArrayElement( "range_simulation", rangeSimulation ) ); 69 | elem.addContent( XmlHelpers.intArrayElement( "interval_render", intervalRender ) ); 70 | elem.addContent( XmlHelpers.doubleArrayElement( "sigma", sb.sigma ) ); 71 | 72 | return elem; 73 | } 74 | 75 | @Override 76 | public SimulatedBeadsImgLoader fromXml( 77 | final Element elem, File basePath, 78 | final AbstractSequenceDescription sequenceDescription ) 79 | { 80 | final int[] angles = XmlHelpers.getIntArray( elem, "rotation_angles" ); 81 | final int axis = XmlHelpers.getInt( elem, "axis" ); 82 | final int numPoints = XmlHelpers.getInt( elem, "num_points" ); 83 | final int[] rs = XmlHelpers.getIntArray( elem, "range_simulation" ); 84 | final int[] ir = XmlHelpers.getIntArray( elem, "interval_render" ); 85 | final double[] sigma = XmlHelpers.getDoubleArray( elem, "sigma" ); 86 | 87 | final FinalInterval rangeSimulation = new FinalInterval( new long[]{ rs[ 0 ], rs[ 1 ], rs[ 2 ] }, new long[]{ rs[ 3 ], rs[ 4 ], rs[ 5 ] } ); 88 | final FinalInterval intervalRender = new FinalInterval( new long[]{ ir[ 0 ], ir[ 1 ], ir[ 2 ] }, new long[]{ ir[ 3 ], ir[ 4 ], ir[ 5 ] } ); 89 | 90 | final SimulateBeads sb = new SimulateBeads( angles, axis, numPoints, rangeSimulation, intervalRender, sigma ); 91 | return new SimulatedBeadsImgLoader( sb ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/raytracing/ClearingMap.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.raytracing; 2 | 3 | public class ClearingMap implements RefractiveIndexMap 4 | { 5 | 6 | @Override 7 | public double getRI( final double intensity ) 8 | { 9 | return 0; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/raytracing/Lightsheet.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.raytracing; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | 6 | import mpicbg.models.IllDefinedDataPointsException; 7 | import mpicbg.models.NoninvertibleModelException; 8 | import mpicbg.models.NotEnoughDataPointsException; 9 | import mpicbg.models.Point; 10 | 11 | /** 12 | * @author Stephan Preibisch and Varun Kapoor 13 | */ 14 | public class Lightsheet 15 | { 16 | final int minNumPoints = 3; 17 | double a, b, c; // a*x*x + b*x + c 18 | 19 | public Lightsheet( 20 | final double center, 21 | final double thicknessCenter, 22 | final double length, 23 | final double thickNessEdges ) 24 | { 25 | final ArrayList< Point > points = new ArrayList<>(); 26 | points.add( new Point( new double[] { center, thicknessCenter } ) ); 27 | points.add( new Point( new double[] { center - length/2, thickNessEdges } ) ); 28 | points.add( new Point( new double[] { center + length/2, thickNessEdges } ) ); 29 | 30 | try 31 | { 32 | fit( points ); 33 | 34 | System.out.println( center - length/2 + ": " + predict( center - length/2 ) ); 35 | System.out.println( center + ": " + predict( center ) ); 36 | System.out.println( center + length/2 + ": " + predict( center + length/2 ) ); 37 | } 38 | catch ( NotEnoughDataPointsException | IllDefinedDataPointsException e ) 39 | { 40 | throw new RuntimeException( "Could not fit quadratic function for lightsheet: " + e ); 41 | } 42 | } 43 | 44 | public Lightsheet( final double a, final double b, final double c ) 45 | { 46 | this.a = a; 47 | this.b = b; 48 | this.c = c; 49 | } 50 | 51 | public double getA(){ return a; } 52 | public double getB(){ return b; } 53 | public double getC(){ return c; } 54 | 55 | public double predict( final double x ) { return a*x*x + b*x + c; } 56 | 57 | public void fit( final Collection< Point > points ) throws NotEnoughDataPointsException, IllDefinedDataPointsException 58 | { 59 | final int numPoints = points.size(); 60 | 61 | if ( numPoints < minNumPoints ) 62 | throw new NotEnoughDataPointsException( "Not enough points, at least " + minNumPoints + " are necessary and available are: " + numPoints ); 63 | 64 | // compute matrices 65 | final double[] delta = new double[ 9 ]; 66 | final double[] tetha = new double[ 3 ]; 67 | 68 | for ( final Point p : points ) 69 | { 70 | final double x = p.getW()[ 0 ]; 71 | final double y = p.getW()[ 1 ]; 72 | 73 | final double xx = x*x; 74 | final double xxx = xx*x; 75 | 76 | delta[ 0 ] += xx * xx; 77 | delta[ 1 ] += xxx; 78 | delta[ 2 ] += xx; 79 | 80 | delta[ 3 ] += xxx; 81 | delta[ 4 ] += xx; 82 | delta[ 5 ] += x; 83 | 84 | delta[ 6 ] += xx; 85 | delta[ 7 ] += x; 86 | delta[ 8 ] += 1; 87 | 88 | tetha[ 0 ] += xx * y; 89 | tetha[ 1 ] += x * y; 90 | tetha[ 2 ] += y; 91 | } 92 | 93 | // invert matrix 94 | try 95 | { 96 | invert3x3( delta ); 97 | } 98 | catch ( final NoninvertibleModelException e ) 99 | { 100 | this.a = this.b = this.c = 0; 101 | throw new IllDefinedDataPointsException( "Cannot not invert Delta-Matrix, failed to fit function" ); 102 | } 103 | 104 | this.a = delta[ 0 ] * tetha[ 0 ] + delta[ 1 ] * tetha[ 1 ] + delta[ 2 ] * tetha[ 2 ]; 105 | this.b = delta[ 3 ] * tetha[ 0 ] + delta[ 4 ] * tetha[ 1 ] + delta[ 5 ] * tetha[ 2 ]; 106 | this.c = delta[ 6 ] * tetha[ 0 ] + delta[ 7 ] * tetha[ 1 ] + delta[ 8 ] * tetha[ 2 ]; 107 | } 108 | 109 | final static public double det3x3( final double[] a ) 110 | { 111 | assert a.length == 9 : "Matrix3x3 supports 3x3 double[][] only."; 112 | 113 | return 114 | a[ 0 ] * a[ 4 ] * a[ 8 ] + 115 | a[ 3 ] * a[ 7 ] * a[ 2 ] + 116 | a[ 6 ] * a[ 1 ] * a[ 5 ] - 117 | a[ 2 ] * a[ 4 ] * a[ 6 ] - 118 | a[ 5 ] * a[ 7 ] * a[ 0 ] - 119 | a[ 8 ] * a[ 1 ] * a[ 3 ]; 120 | } 121 | 122 | final static public void invert3x3( final double[] m ) throws NoninvertibleModelException 123 | { 124 | assert m.length == 9 : "Matrix3x3 supports 3x3 double[][] only."; 125 | 126 | final double det = det3x3( m ); 127 | if ( det == 0 ) throw new NoninvertibleModelException( "Matrix not invertible." ); 128 | 129 | final double i00 = ( m[ 4 ] * m[ 8 ] - m[ 5 ] * m[ 7 ] ) / det; 130 | final double i01 = ( m[ 2 ] * m[ 7 ] - m[ 1 ] * m[ 8 ] ) / det; 131 | final double i02 = ( m[ 1 ] * m[ 5 ] - m[ 2 ] * m[ 4 ] ) / det; 132 | 133 | final double i10 = ( m[ 5 ] * m[ 6 ] - m[ 3 ] * m[ 8 ] ) / det; 134 | final double i11 = ( m[ 0 ] * m[ 8 ] - m[ 2 ] * m[ 6 ] ) / det; 135 | final double i12 = ( m[ 2 ] * m[ 3 ] - m[ 0 ] * m[ 5 ] ) / det; 136 | 137 | final double i20 = ( m[ 3 ] * m[ 7 ] - m[ 4 ] * m[ 6 ] ) / det; 138 | final double i21 = ( m[ 1 ] * m[ 6 ] - m[ 0 ] * m[ 7 ] ) / det; 139 | final double i22 = ( m[ 0 ] * m[ 4 ] - m[ 1 ] * m[ 3 ] ) / det; 140 | 141 | m[ 0 ] = i00; 142 | m[ 1 ] = i01; 143 | m[ 2 ] = i02; 144 | 145 | m[ 3 ] = i10; 146 | m[ 4 ] = i11; 147 | m[ 5 ] = i12; 148 | 149 | m[ 6 ] = i20; 150 | m[ 7 ] = i21; 151 | m[ 8 ] = i22; 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/raytracing/RayTracingTest.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.raytracing; 2 | 3 | import java.awt.Color; 4 | import java.io.File; 5 | import java.text.DecimalFormat; 6 | import java.util.Random; 7 | 8 | import ij.IJ; 9 | import ij.ImageJ; 10 | import ij.ImagePlus; 11 | import ij.ImageStack; 12 | import ij.gui.TextRoi; 13 | import ij.gui.Toolbar; 14 | import ij.process.FloatProcessor; 15 | import net.imglib2.Cursor; 16 | import net.imglib2.RandomAccess; 17 | import net.imglib2.RandomAccessibleInterval; 18 | import net.imglib2.RealRandomAccess; 19 | import net.imglib2.img.Img; 20 | import net.imglib2.img.array.ArrayImgFactory; 21 | import net.imglib2.img.array.ArrayImgs; 22 | import net.imglib2.img.display.imagej.ImageJFunctions; 23 | import net.imglib2.interpolation.randomaccess.NLinearInterpolatorFactory; 24 | import net.imglib2.type.numeric.real.FloatType; 25 | import net.imglib2.util.Util; 26 | import net.imglib2.view.Views; 27 | import net.preibisch.simulation.Hessian; 28 | import net.preibisch.simulation.SimulateMultiViewAberrations; 29 | import net.preibisch.simulation.VolumeInjection; 30 | 31 | public class RayTracingTest 32 | { 33 | public static Img< FloatType > hessian( final Img< FloatType > img, final int z ) 34 | { 35 | final Img< FloatType > hessian = img.copy(); 36 | 37 | final Cursor< FloatType > cursor = img.localizingCursor(); 38 | final RandomAccess< FloatType > ra = Views.extendMirrorSingle( img ).randomAccess(); 39 | final RandomAccess< FloatType > raH = hessian.randomAccess(); 40 | 41 | final double[][] matrix = new double[ 3 ][ 3 ]; // row, column 42 | final double[] eigenVector = new double[ 3 ]; 43 | 44 | while( cursor.hasNext() ) 45 | { 46 | cursor.fwd(); 47 | if ( cursor.getIntPosition( 2 ) != z ) 48 | continue; 49 | 50 | ra.setPosition( cursor ); 51 | Hessian.computeHessianMatrix3D( ra, matrix ); 52 | final double ev = Hessian.computeLargestEigenVectorAndValue3d( matrix, eigenVector ); 53 | 54 | if ( cursor.getIntPosition( 0 ) == 85 && cursor.getIntPosition( 1 ) == 85 ) 55 | System.out.println( Util.printCoordinates( eigenVector ) ); 56 | 57 | raH.setPosition( cursor ); 58 | raH.get().set( (float) ev); 59 | } 60 | 61 | return hessian; 62 | } 63 | 64 | public static VolumeInjection drawMultipleRays( final RandomAccessibleInterval< FloatType > imgIn, final int z, final int x, final int numRays ) 65 | { 66 | // the refracted image 67 | final Img< FloatType > imgOut = new ArrayImgFactory< FloatType >( new FloatType() ).create( imgIn ); 68 | final Img< FloatType > weightOut = new ArrayImgFactory< FloatType >( new FloatType() ).create( imgIn ); 69 | 70 | final double[] sigma = new double[] { 0.5, 0.5, 0.5 }; 71 | final VolumeInjection inject = new VolumeInjection( imgOut, weightOut, sigma ); 72 | 73 | // the incoming direction of the light 74 | final double[] rayVector = new double[ 3 ]; 75 | 76 | // the outgoing, refracted direction of the light 77 | final double[] refractedRay = new double[ 3 ]; 78 | 79 | // the current position of the ray 80 | final double[] rayPosition = new double[ imgIn.numDimensions() ]; 81 | 82 | final double[][] matrix = new double[ 3 ][ 3 ]; // row, column 83 | final double[] eigenVector = new double[ 3 ]; 84 | 85 | //final RandomAccess< FloatType > ra = img.randomAccess(); 86 | final RealRandomAccess< FloatType > rr = Views.interpolate( Views.extendMirrorSingle( imgIn ), new NLinearInterpolatorFactory<>() ).realRandomAccess(); 87 | 88 | final Random rnd = new Random( 234345 ); 89 | final double valueIm = 1.0; 90 | 91 | for ( int n = 0; n < numRays; ++n ) 92 | { 93 | rayVector[ 0 ] = 0; 94 | rayVector[ 1 ] = -1; 95 | rayVector[ 2 ] = 0; 96 | 97 | Raytrace.norm( rayVector ); 98 | 99 | rayPosition[ 0 ] = x + rnd.nextDouble() - 0.5; 100 | rayPosition[ 1 ] = imgIn.dimension( 1 ) - 1; 101 | rayPosition[ 2 ] = z + rnd.nextDouble() - 0.5; 102 | 103 | while ( SimulateMultiViewAberrations.inside( rayPosition, imgIn ) ) 104 | { 105 | rr.setPosition( rayPosition ); 106 | 107 | // normal vector of refraction plane (still maybe needs to be inverted to point towards the incoming signal) 108 | Hessian.computeHessianMatrix3D( rr, matrix ); 109 | 110 | double ev = Hessian.computeLargestEigenVectorAndValue3d( matrix, eigenVector ); 111 | 112 | if ( Math.abs( ev ) > 0.01 ) 113 | { 114 | // compute refractive index change 115 | rr.setPosition( rayPosition ); 116 | 117 | rr.move( -rayVector[ 0 ], 0 ); 118 | rr.move( -rayVector[ 1 ], 1 ); 119 | rr.move( -rayVector[ 2 ], 2 ); 120 | 121 | // refractive index at the origin of the ray 122 | final double n0 = rr.get().get(); 123 | 124 | rr.move( 2*rayVector[ 0 ], 0 ); 125 | rr.move( 2*rayVector[ 1 ], 1 ); 126 | rr.move( 2*rayVector[ 2 ], 2 ); 127 | 128 | // refractive index at the projected location of the ray 129 | final double n1 = rr.get().get(); 130 | 131 | final double thetaI = Raytrace.incidentAngle( rayVector, eigenVector ); 132 | final double thetaT = Raytrace.refract( rayVector, eigenVector, n0, n1, thetaI, refractedRay ); 133 | 134 | // total reflection 135 | if ( Double.isNaN( thetaT ) ) 136 | { 137 | refractedRay[ 0 ] = rayVector[ 0 ]; 138 | refractedRay[ 1 ] = rayVector[ 1 ]; 139 | refractedRay[ 2 ] = rayVector[ 2 ]; 140 | 141 | //continue; // that's an expensive getting stuck 142 | //Raytrace.reflect( rayVector, eigenVector, refractedRay ); 143 | } 144 | 145 | Raytrace.norm( refractedRay ); 146 | 147 | // update the ray vector 148 | rayVector[ 0 ] = refractedRay[ 0 ]; 149 | rayVector[ 1 ] = refractedRay[ 1 ]; 150 | rayVector[ 2 ] = refractedRay[ 2 ]; 151 | } 152 | 153 | // place a gaussian sphere 154 | inject.addNormalizedGaussian( valueIm, rayPosition ); 155 | 156 | /* 157 | // for drawing individual rays ... 158 | intPos[ 0 ] = Math.round( rayPosition[ 0 ] ); 159 | intPos[ 1 ] = Math.round( rayPosition[ 1 ] ); 160 | intPos[ 2 ] = Math.round( rayPosition[ 2 ] ); 161 | rOut.setPosition( intPos ); 162 | rOut.get().set( value ); 163 | */ 164 | 165 | rayPosition[ 0 ] += rayVector[ 0 ]; 166 | rayPosition[ 1 ] += rayVector[ 1 ]; 167 | rayPosition[ 2 ] += rayVector[ 2 ]; 168 | } 169 | } 170 | 171 | return inject; 172 | } 173 | 174 | public static ImagePlus drawSingleRay( final RandomAccessibleInterval< FloatType > imgIn, final int z, final int x ) 175 | { 176 | final ImageStack stack = new ImageStack( (int)imgIn.dimension( 0 ), (int)imgIn.dimension( 1 ) ); 177 | 178 | // the refracted image 179 | final Img< FloatType > imgOut = new ArrayImgFactory< FloatType >( new FloatType() ).create( imgIn ); 180 | final Img< FloatType > weightOut = new ArrayImgFactory< FloatType >( new FloatType() ).create( imgIn ); 181 | 182 | final double[] sigma = new double[] { 0.5, 0.5, 0.5 }; 183 | final VolumeInjection inject = new VolumeInjection( imgOut, weightOut, sigma ); 184 | 185 | // the incoming direction of the light 186 | final double[] rayVector = new double[ 3 ]; 187 | 188 | // the outgoing, refracted direction of the light 189 | final double[] refractedRay = new double[ 3 ]; 190 | 191 | // the current position of the ray 192 | final double[] rayPosition = new double[ imgIn.numDimensions() ]; 193 | 194 | final double[][] matrix = new double[ 3 ][ 3 ]; // row, column 195 | final double[] eigenVector = new double[ 3 ]; 196 | 197 | //final RandomAccess< FloatType > ra = img.randomAccess(); 198 | final RealRandomAccess< FloatType > rr = Views.interpolate( Views.extendMirrorSingle( imgIn ), new NLinearInterpolatorFactory<>() ).realRandomAccess(); 199 | 200 | final double valueIm = 1.0; 201 | 202 | rayVector[ 0 ] = 0; 203 | rayVector[ 1 ] = -1; 204 | rayVector[ 2 ] = 0; 205 | 206 | Raytrace.norm( rayVector ); 207 | 208 | rayPosition[ 0 ] = x; 209 | rayPosition[ 1 ] = imgIn.dimension( 1 ) - 25; 210 | rayPosition[ 2 ] = z; 211 | 212 | while ( SimulateMultiViewAberrations.inside( rayPosition, imgIn ) ) 213 | { 214 | rr.setPosition( rayPosition ); 215 | 216 | // normal vector of refraction plane (still maybe needs to be inverted to point towards the incoming signal) 217 | Hessian.computeHessianMatrix3D( rr, matrix ); 218 | 219 | double ev = Hessian.computeLargestEigenVectorAndValue3d( matrix, eigenVector ); 220 | 221 | if ( Math.abs( ev ) > 0.01 ) 222 | { 223 | // compute refractive index change 224 | rr.setPosition( rayPosition ); 225 | 226 | rr.move( -rayVector[ 0 ], 0 ); 227 | rr.move( -rayVector[ 1 ], 1 ); 228 | rr.move( -rayVector[ 2 ], 2 ); 229 | 230 | // refractive index at the origin of the ray 231 | final double n0 = rr.get().get(); 232 | 233 | rr.move( 2*rayVector[ 0 ], 0 ); 234 | rr.move( 2*rayVector[ 1 ], 1 ); 235 | rr.move( 2*rayVector[ 2 ], 2 ); 236 | 237 | // refractive index at the projected location of the ray 238 | final double n1 = rr.get().get(); 239 | 240 | final double thetaI = Raytrace.incidentAngle( rayVector, eigenVector ); 241 | final double thetaT = Raytrace.refract( rayVector, eigenVector, n0, n1, thetaI, refractedRay ); 242 | 243 | // total reflection 244 | if ( Double.isNaN( thetaT ) ) 245 | { 246 | refractedRay[ 0 ] = rayVector[ 0 ]; 247 | refractedRay[ 1 ] = rayVector[ 1 ]; 248 | refractedRay[ 2 ] = rayVector[ 2 ]; 249 | 250 | //continue; // that's an expensive getting stuck 251 | //Raytrace.reflect( rayVector, eigenVector, refractedRay ); 252 | } 253 | 254 | Raytrace.norm( refractedRay ); 255 | 256 | // update the ray vector 257 | rayVector[ 0 ] = refractedRay[ 0 ]; 258 | rayVector[ 1 ] = refractedRay[ 1 ]; 259 | rayVector[ 2 ] = refractedRay[ 2 ]; 260 | } 261 | 262 | // place a gaussian sphere 263 | inject.addNormalizedGaussian( valueIm, rayPosition ); 264 | 265 | final FloatProcessor fp = getProcessor( inject.getWeight(), z ); 266 | 267 | DecimalFormat df = new DecimalFormat("####0.00"); 268 | 269 | Toolbar.setForegroundColor(java.awt.Color.WHITE); 270 | TextRoi tr = new TextRoi( 10,imgIn.dimension( 1 )-20,"vec=[" + df.format( eigenVector[ 0 ] ) + "," + df.format( eigenVector[ 0 ] ) + "], ev="+ df.format( ev ) ); 271 | tr.setStrokeColor(Color.white); 272 | tr.setNonScalable(true); 273 | tr.drawPixels(fp); 274 | 275 | stack.addSlice( fp ); 276 | 277 | System.out.println( Util.printCoordinates( rayPosition ) ); 278 | rayPosition[ 0 ] += rayVector[ 0 ]; 279 | rayPosition[ 1 ] += rayVector[ 1 ]; 280 | rayPosition[ 2 ] += rayVector[ 2 ]; 281 | } 282 | 283 | return new ImagePlus( "", stack ); 284 | } 285 | 286 | public static VolumeInjection drawRays( final RandomAccessibleInterval< FloatType > imgIn, final int z, final int spacing ) 287 | { 288 | // the refracted image 289 | final Img< FloatType > imgOut = new ArrayImgFactory< FloatType >( new FloatType() ).create( imgIn ); 290 | final Img< FloatType > weightOut = new ArrayImgFactory< FloatType >( new FloatType() ).create( imgIn ); 291 | 292 | final double[] sigma = new double[] { 0.5, 0.5, 0.5 }; 293 | final VolumeInjection inject = new VolumeInjection( imgOut, weightOut, sigma ); 294 | 295 | // the incoming direction of the light 296 | final double[] rayVector = new double[ 3 ]; 297 | 298 | // the outgoing, refracted direction of the light 299 | final double[] refractedRay = new double[ 3 ]; 300 | 301 | // the current position of the ray 302 | final double[] rayPosition = new double[ imgIn.numDimensions() ]; 303 | 304 | final double[][] matrix = new double[ 3 ][ 3 ]; // row, column 305 | final double[] eigenVector = new double[ 3 ]; 306 | 307 | //final RandomAccess< FloatType > ra = img.randomAccess(); 308 | final RealRandomAccess< FloatType > rr = Views.interpolate( Views.extendMirrorSingle( imgIn ), new NLinearInterpolatorFactory<>() ).realRandomAccess(); 309 | 310 | final double valueIm = 1.0; 311 | 312 | for ( int x = spacing; x <= imgIn.dimension( 0 ); x += spacing ) 313 | { 314 | rayVector[ 0 ] = 0; 315 | rayVector[ 1 ] = -1; 316 | rayVector[ 2 ] = 0; 317 | 318 | Raytrace.norm( rayVector ); 319 | 320 | rayPosition[ 0 ] = x; 321 | rayPosition[ 1 ] = imgIn.dimension( 1 ) - 25; 322 | rayPosition[ 2 ] = z; 323 | 324 | while ( SimulateMultiViewAberrations.inside( rayPosition, imgIn ) ) 325 | { 326 | rr.setPosition( rayPosition ); 327 | 328 | // normal vector of refraction plane (still maybe needs to be inverted to point towards the incoming signal) 329 | Hessian.computeHessianMatrix3D( rr, matrix ); 330 | 331 | double ev = Hessian.computeLargestEigenVectorAndValue3d( matrix, eigenVector ); 332 | 333 | if ( Math.abs( ev ) > 0.01 ) 334 | { 335 | // compute refractive index change 336 | rr.setPosition( rayPosition ); 337 | 338 | rr.move( -rayVector[ 0 ], 0 ); 339 | rr.move( -rayVector[ 1 ], 1 ); 340 | rr.move( -rayVector[ 2 ], 2 ); 341 | 342 | // refractive index at the origin of the ray 343 | final double n0 = rr.get().get(); 344 | 345 | rr.move( 2*rayVector[ 0 ], 0 ); 346 | rr.move( 2*rayVector[ 1 ], 1 ); 347 | rr.move( 2*rayVector[ 2 ], 2 ); 348 | 349 | // refractive index at the projected location of the ray 350 | final double n1 = rr.get().get(); 351 | 352 | final double thetaI = Raytrace.incidentAngle( rayVector, eigenVector ); 353 | final double thetaT = Raytrace.refract( rayVector, eigenVector, n0, n1, thetaI, refractedRay ); 354 | 355 | // total reflection 356 | if ( Double.isNaN( thetaT ) ) 357 | { 358 | refractedRay[ 0 ] = rayVector[ 0 ]; 359 | refractedRay[ 1 ] = rayVector[ 1 ]; 360 | refractedRay[ 2 ] = rayVector[ 2 ]; 361 | 362 | //continue; // that's an expensive getting stuck 363 | //Raytrace.reflect( rayVector, eigenVector, refractedRay ); 364 | } 365 | 366 | Raytrace.norm( refractedRay ); 367 | 368 | // update the ray vector 369 | rayVector[ 0 ] = refractedRay[ 0 ]; 370 | rayVector[ 1 ] = refractedRay[ 1 ]; 371 | rayVector[ 2 ] = refractedRay[ 2 ]; 372 | } 373 | 374 | // place a gaussian sphere 375 | inject.addNormalizedGaussian( valueIm, rayPosition ); 376 | 377 | /* 378 | // for drawing individual rays ... 379 | intPos[ 0 ] = Math.round( rayPosition[ 0 ] ); 380 | intPos[ 1 ] = Math.round( rayPosition[ 1 ] ); 381 | intPos[ 2 ] = Math.round( rayPosition[ 2 ] ); 382 | rOut.setPosition( intPos ); 383 | rOut.get().set( value ); 384 | */ 385 | 386 | rayPosition[ 0 ] += rayVector[ 0 ]; 387 | rayPosition[ 1 ] += rayVector[ 1 ]; 388 | rayPosition[ 2 ] += rayVector[ 2 ]; 389 | } 390 | } 391 | 392 | return inject; 393 | } 394 | 395 | public static FloatProcessor getProcessor( final RandomAccessibleInterval< FloatType > img, final int z ) 396 | { 397 | final RandomAccess< FloatType > ra = Views.zeroMin( img ).randomAccess(); 398 | ra.setPosition( z, 2 ); 399 | 400 | final FloatProcessor fp = new FloatProcessor( (int)img.dimension( 0 ), (int)img.dimension( 1 )); 401 | 402 | for ( int y = 0; y < img.dimension( 1 ); ++y ) 403 | { 404 | ra.setPosition( y, 1 ); 405 | 406 | for ( int x = 0; x < img.dimension( 0 ); ++x ) 407 | { 408 | ra.setPosition( x, 0 ); 409 | 410 | fp.setf( x, y, ra.get().get() ); 411 | } 412 | } 413 | 414 | return fp; 415 | } 416 | 417 | public static void renderDifferentNAs() 418 | { 419 | final ImageStack stack = new ImageStack( 300, 300 ); 420 | 421 | for ( double na = 1.0; na <= 2; na += 0.01 ) 422 | { 423 | final Img< FloatType > img1 = ArrayImgs.floats( 300, 300, 10 ); 424 | Raytrace.drawSimpleImage( img1, 1.0f, (float)na ); 425 | 426 | final VolumeInjection rays = drawRays( img1, 5, 8 ); 427 | 428 | final FloatProcessor fp = getProcessor( rays.getWeight(), 5 ); 429 | 430 | Toolbar.setForegroundColor(java.awt.Color.WHITE); 431 | TextRoi tr = new TextRoi( 10,280,"NA="+ na ); 432 | tr.setStrokeColor(Color.white); 433 | tr.setNonScalable(true); 434 | tr.drawPixels(fp); 435 | 436 | stack.addSlice( fp ); 437 | } 438 | 439 | 440 | new ImagePlus( "", stack ).show(); 441 | } 442 | 443 | public static void main( String[] args ) 444 | { 445 | new ImageJ(); 446 | 447 | //renderDifferentNAs(); 448 | 449 | final Img< FloatType > img1 = ImageJFunctions.wrap( new ImagePlus( new File("spheres2b.tif").getAbsolutePath() ) ); 450 | //final Img< FloatType > img1 = ArrayImgs.floats( 300, 300, 10 ); 451 | //Raytrace.drawSimpleImage( img1, 1.0f, 1.33f ); 452 | //drawSingleRay( img1, 150, 150 ).show(); 453 | final VolumeInjection rays = drawMultipleRays( img1, 150, 150, 100 ); 454 | ImageJFunctions.show( rays.getWeight() ); 455 | 456 | /* 457 | 458 | final Img< FloatType > img1 = ArrayImgs.floats( 300, 300, 300 ); 459 | Raytrace.drawSimpleImage( img1, 1.0f, 1.33f ); 460 | //ImageJFunctions.show( img1 ); 461 | 462 | //final Img< FloatType > img2 = hessian( ImageJFunctions.wrap( new ImagePlus( new File("neuron.tif").getAbsolutePath() ) ), 0 ); 463 | //final Img< FloatType > img2 = hessian( img1, 0 ); 464 | //ImageJFunctions.show( img2 ); 465 | 466 | final VolumeInjection rays = drawRays( img1, 5, 8 ); 467 | ImageJFunctions.show( rays.getWeight() );*/ 468 | } 469 | 470 | } 471 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/raytracing/Raytrace.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.raytracing; 2 | 3 | import net.imglib2.Cursor; 4 | import net.imglib2.RandomAccessibleInterval; 5 | import net.imglib2.type.numeric.real.FloatType; 6 | import net.imglib2.view.Views; 7 | 8 | public class Raytrace 9 | { 10 | public static void reflect( final double[] i, final double[] n, final double[] r ) 11 | { 12 | // r = i−2(i·n)n 13 | final double dotP = i[0]*n[0] + i[1]*n[1] + i[2]*n[2]; 14 | 15 | r[ 0 ] = i[ 0 ] - 2*dotP*n[ 0 ]; 16 | r[ 1 ] = i[ 1 ] - 2*dotP*n[ 1 ]; 17 | r[ 2 ] = i[ 2 ] - 2*dotP*n[ 2 ]; 18 | } 19 | 20 | public static double refract( final double[] i, final double[] n, final double n0, final double n1, final double thetaI, final double[] t ) 21 | { 22 | final double deltaN = n0 / n1; 23 | final double thetaT = Math.asin( deltaN * Math.sin( thetaI ) ); 24 | 25 | // total internal reflection 26 | if ( Double.isNaN( thetaT ) ) 27 | return thetaT; 28 | 29 | final double cosThetaI = Math.cos( thetaI ); 30 | final double sinThetaT = Math.sin( thetaT ); 31 | 32 | t[ 0 ] = deltaN * i[ 0 ] - n[ 0 ] * ( deltaN * cosThetaI - Math.sqrt( 1 - sinThetaT*sinThetaT )); 33 | t[ 1 ] = deltaN * i[ 1 ] - n[ 1 ] * ( deltaN * cosThetaI - Math.sqrt( 1 - sinThetaT*sinThetaT )); 34 | t[ 2 ] = deltaN * i[ 2 ] - n[ 2 ] * ( deltaN * cosThetaI - Math.sqrt( 1 - sinThetaT*sinThetaT )); 35 | 36 | return thetaT; 37 | } 38 | 39 | public static double length( final double[] v ) 40 | { 41 | return Math.sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ); 42 | } 43 | 44 | public static void norm( final double[] v ) 45 | { 46 | final double l = length( v ); 47 | 48 | v[ 0 ] /= l; 49 | v[ 1 ] /= l; 50 | v[ 2 ] /= l; 51 | } 52 | 53 | public static double incidentAngle( final double[] i, final double[] n ) 54 | { 55 | double thetaI = Math.acos( ( n[0]*i[0] + n[1]*i[1] + n[2]*i[2]) / ( Math.sqrt( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] ) * Math.sqrt( i[0]*i[0] + i[1]*i[1] + i[2]*i[2] ) ) ); 56 | 57 | if ( thetaI >= Math.PI / 2 ) 58 | { 59 | // invert normal vector & eigenvalue 60 | n[ 0 ] *= -1; 61 | n[ 1 ] *= -1; 62 | n[ 2 ] *= -1; 63 | //ev *= -1; 64 | 65 | // adjust angle 66 | thetaI -= Math.PI / 2; 67 | //dotP = Math.acos( ( nx*bx + ny*by + nz*bz) / ( Math.sqrt( nx*nx + ny*ny + nz*nz ) * Math.sqrt( bx*bx + by*by + bz*bz ) ) ); 68 | } 69 | 70 | return thetaI; 71 | } 72 | 73 | 74 | public static void drawSimpleImage( final RandomAccessibleInterval< FloatType > randomAccessible, final float low, final float high ) 75 | { 76 | final Cursor< FloatType > c = Views.iterable( randomAccessible ).localizingCursor(); 77 | 78 | while( c.hasNext() ) 79 | { 80 | c.fwd(); 81 | boolean all = true; 82 | //for ( int d = 0; d < n; ++d ) 83 | // if ( c.getIntPosition( d ) > 100 || c.getIntPosition( d ) < 10 ) 84 | // all = false; 85 | 86 | if ( c.getIntPosition( 0 ) < randomAccessible.dimension( 0 ) / 2 ) 87 | { 88 | if ( c.getIntPosition( 0 ) > c.getIntPosition( 1 ) ) 89 | all = true; 90 | else 91 | all = false; 92 | } 93 | else 94 | { 95 | if ( randomAccessible.dimension( 0 ) - c.getIntPosition( 0 ) > c.getIntPosition( 1 ) ) 96 | all = true; 97 | else 98 | all = false; 99 | } 100 | 101 | if ( all ) 102 | c.get().set( high ); 103 | else 104 | c.get().set( low ); 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/raytracing/RefractiveIndexMap.java: -------------------------------------------------------------------------------- 1 | package net.preibisch.simulation.raytracing; 2 | 3 | public interface RefractiveIndexMap 4 | { 5 | public double getRI( final double intensity ); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/uncommons/ConstantGenerator.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.uncommons; 24 | 25 | /** 26 | * Convenience implementation of {@link NumberGenerator} that always 27 | * returns the same value. 28 | * @param The numeric type (Integer, Long, Double, etc.) of the constant. 29 | * @author Daniel Dyer 30 | */ 31 | public class ConstantGenerator implements NumberGenerator 32 | { 33 | private final T constant; 34 | 35 | /** 36 | * Creates a number generator that always returns the same 37 | * values. 38 | * @param constant The value to be returned by all invocations 39 | * of the {@link #nextValue()} method. 40 | */ 41 | public ConstantGenerator(T constant) 42 | { 43 | this.constant = constant; 44 | } 45 | 46 | /** 47 | * @return The constant value specified when the generator was constructed. 48 | */ 49 | public T nextValue() 50 | { 51 | return constant; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/uncommons/NumberGenerator.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.uncommons; 24 | 25 | /** 26 | * Interface for providing different types of sequences of numbers. This is 27 | * a simple but powerful abstraction that provides considerable flexibility 28 | * in implementing classes that require numeric configuration. Refer to the 29 | * implementations in this package for examples of how it can be used. 30 | * @param The type (Integer, Long, Double, etc.) of number to generate. 31 | * @author Daniel Dyer 32 | */ 33 | public interface NumberGenerator 34 | { 35 | /** 36 | * @return The next value from the generator. 37 | */ 38 | T nextValue(); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/preibisch/simulation/uncommons/PoissonGenerator.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Library for simulating a multi-view acquisition including 4 | * attenuation, convolution, reduced sampling and poission noise. 5 | * %% 6 | * Copyright (C) 2014 - 2017 Multiview Simulation developers. 7 | * %% 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation, either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this program. If not, see 20 | * . 21 | * #L% 22 | */ 23 | package net.preibisch.simulation.uncommons; 24 | //============================================================================ 25 | //Copyright 2006-2010 Daniel W. Dyer 26 | // 27 | //Licensed under the Apache License, Version 2.0 (the "License"); 28 | //you may not use this file except in compliance with the License. 29 | //You may obtain a copy of the License at 30 | // 31 | // http://www.apache.org/licenses/LICENSE-2.0 32 | // 33 | //Unless required by applicable law or agreed to in writing, software 34 | //distributed under the License is distributed on an "AS IS" BASIS, 35 | //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 36 | //See the License for the specific language governing permissions and 37 | //limitations under the License. 38 | //============================================================================ 39 | 40 | import java.util.Random; 41 | 42 | /** 43 | * Discrete random sequence that follows a 44 | * Poisson 45 | * distribution. 46 | * @author Daniel Dyer 47 | */ 48 | public class PoissonGenerator implements NumberGenerator 49 | { 50 | private final Random rng; 51 | private final NumberGenerator mean; 52 | 53 | 54 | /** 55 | *

Creates a generator of Poisson-distributed values. The mean is 56 | * determined by the provided {org.uncommons.maths.number.NumberGenerator}. This means that 57 | * the statistical parameters of this generator may change over time. 58 | * One example of where this is useful is if the mean generator is attached 59 | * to a GUI control that allows a user to tweak the parameters while a 60 | * program is running.

61 | *

To create a Poisson generator with a constant mean, use the 62 | * {@link #PoissonGenerator(double, Random)} constructor instead.

63 | * @param mean A {@link NumberGenerator} that provides the mean of the 64 | * Poisson distribution used for the next generated value. 65 | * @param rng The source of randomness. 66 | */ 67 | public PoissonGenerator(NumberGenerator mean, 68 | Random rng) 69 | { 70 | this.mean = mean; 71 | this.rng = rng; 72 | } 73 | 74 | 75 | /** 76 | * Creates a generator of Poisson-distributed values from a distribution 77 | * with the specified mean. 78 | * @param mean The mean of the values generated. 79 | * @param rng The source of randomness. 80 | */ 81 | public PoissonGenerator(double mean, 82 | Random rng) 83 | { 84 | this(new ConstantGenerator(mean), rng); 85 | if (mean <= 0) 86 | { 87 | throw new IllegalArgumentException("Mean must be a positive value."); 88 | } 89 | } 90 | 91 | 92 | /** 93 | * {@inheritDoc} 94 | */ 95 | public Integer nextValue() 96 | { 97 | int x = 0; 98 | double t = 0.0; 99 | while (true) 100 | { 101 | t -= Math.log(rng.nextDouble()) / mean.nextValue(); 102 | if (t > 1.0) 103 | { 104 | break; 105 | } 106 | ++x; 107 | } 108 | return x; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/resources/Angle0.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle0.tif -------------------------------------------------------------------------------- /src/main/resources/Angle104.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle104.tif -------------------------------------------------------------------------------- /src/main/resources/Angle120.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle120.tif -------------------------------------------------------------------------------- /src/main/resources/Angle135.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle135.tif -------------------------------------------------------------------------------- /src/main/resources/Angle156.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle156.tif -------------------------------------------------------------------------------- /src/main/resources/Angle180.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle180.tif -------------------------------------------------------------------------------- /src/main/resources/Angle208.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle208.tif -------------------------------------------------------------------------------- /src/main/resources/Angle225.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle225.tif -------------------------------------------------------------------------------- /src/main/resources/Angle240.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle240.tif -------------------------------------------------------------------------------- /src/main/resources/Angle260.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle260.tif -------------------------------------------------------------------------------- /src/main/resources/Angle270.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle270.tif -------------------------------------------------------------------------------- /src/main/resources/Angle300.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle300.tif -------------------------------------------------------------------------------- /src/main/resources/Angle312.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle312.tif -------------------------------------------------------------------------------- /src/main/resources/Angle315.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle315.tif -------------------------------------------------------------------------------- /src/main/resources/Angle45.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle45.tif -------------------------------------------------------------------------------- /src/main/resources/Angle52.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle52.tif -------------------------------------------------------------------------------- /src/main/resources/Angle60.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle60.tif -------------------------------------------------------------------------------- /src/main/resources/Angle90.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PreibischLab/multiview-simulation/37cf879923a0c3515679cc0f66f7651636e91b61/src/main/resources/Angle90.tif --------------------------------------------------------------------------------