├── README.md ├── code ├── MCCovHetro.m ├── MCcov.m ├── MCfield.m ├── MCfieldFourierQuad.m ├── MCfieldFourierQuadOnWave.asv ├── MCfieldFourierQuadOnWave.m ├── MCfieldOnWave.m ├── MCsampleFourier.m ├── MCsampleHetro.m ├── coreFunctions │ ├── cubeDist.m │ ├── cubeProj.m │ ├── evalampfunc_amplitude.m │ ├── evalampfunc_general.m │ ├── evalphaseatt.m │ ├── evalphaseattHetro.m │ ├── evaluateHG.m │ ├── expSmpX.m │ ├── expSmpXHetro.m │ ├── findBin.m │ ├── invCDF.m │ ├── invCDFvec.m │ ├── ismonotonic.m │ ├── rotateBytheta.m │ ├── sampleHG.m │ ├── smpWoodcock.m │ ├── smpampfunc.m │ ├── smpampfunc_general.m │ └── smpicdf.m ├── evalMeanUnifCtr.m ├── refocus.m ├── test3DFourierSmpQuad.m └── test3DFourierSmpQuadOnWave.m ├── examples ├── buildFarFieldCovMatrix │ ├── farFieldCov.m │ ├── farFieldCov.pdf │ └── scatteringAmplitude.mat ├── buildNearFieldCovMatrix │ ├── nearFieldCov.m │ └── nearFieldCov.pdf ├── evaluateTabulatedScatterVsHG │ ├── evaluateTabulatedScatterVsHG.m │ └── evaluateTabulatedScatterVsHG.pdf ├── memoryEffectMeasurements │ ├── memoryEffectMeasurements.m │ └── memoryEffectMeasurements.pdf ├── multipleAndSingleScattering │ ├── multipleAndSingleScattering.m │ └── multipleAndSingleScattering.pdf ├── renderSpecklesImages │ ├── renderSpecklesImages.m │ └── renderSpecklesImages.pdf ├── sampleTabulatedScatterVsHG │ ├── sampleTabulatedScatterVsHG.m │ └── sampleTabulatedScatterVsHG.pdf ├── samplingFromCovMatrix │ ├── samplingFromCovMatrix.m │ └── samplingFromCovMatrix.pdf └── testHetro │ ├── testHetroCov.m │ ├── testRefocus.m │ ├── testRefocus3D.m │ ├── testSmpXHetro.m │ └── testWoodcock.m ├── interface ├── scatter │ ├── HGScatter.m │ ├── isotropicScatter.m │ └── tabulatedAmplitudeScatter.m ├── source │ ├── farFieldSource.m │ └── nearFieldSource.m └── targetArea │ └── boxArea.m └── scmc.m /README.md: -------------------------------------------------------------------------------- 1 | # SCMC: Speckle Covariance and rendering Monte-Carlo solver 2 | 3 | A Monte Carlo rendering framework for the physically-accurate simulation of speckle patterns and statistics 4 | arising from volumetric scattering of coherent waves. 5 | This framework allows efficient computation of speckle mean and covariance as well as direct rendering of speckle fields, 6 | for user defined light source directions and detector views. 7 | Only bulk parameters of the scattering volume are required as input, 8 | and there is no need to know the specific positions of wavelength-size scatterers in the medium. 9 | 10 | Based on : ["A Monte Carlo Framework for Rendering Speckle Statistics in Scattering Media", Bar et.al. (2019)](https://arxiv.org/abs/1901.06931). 11 | 12 | ## Getting Started 13 | 14 | These instructions will get your copy of the SCMC solver up and running on your local machine. 15 | 16 | ### Prerequisites 17 | 18 | The SCMC solver requires MATLAB, available at: 19 | 20 | [https://www.mathworks.com/products/matlab.html](https://www.mathworks.com/products/matlab.html) 21 | 22 | The solver was tested on MATLAB 2017b. 23 | 24 | ### Installing 25 | 26 | Download the project code (available in github) to your local machine, and unzip all the files. 27 | 28 | **For permanent installation**, add the SCMC folder and all its sub folders to the path, by 29 | 30 | ``` 31 | home -> environment -> set path -> add with Subfolders... 32 | ``` 33 | 34 | and select the SCMC folder. Then, restart MATLAB software. 35 | 36 | **For temporal installation**, it is possible to add temporally the SCMS to the path, by adding the line 37 | 38 | ``` 39 | addpath(genpath(' ')); 40 | ``` 41 | 42 | to your code, where the path to SCMC folder is inside the quotation marks. 43 | 44 | ## Running the code 45 | 46 | ### Interface 47 | 48 | The scmc.m is the interface function of the solver. 49 | Refer to the help of scmc.m and the examples folder for proper parameter specifications and usage. 50 | 51 | ### Examples 52 | 53 | Several usage examples and applications are located in the examples subfolder. 54 | It is recommended to start with these basic examples. 55 | 56 | ### Assumptions 57 | - The following scattering functions are supported: isotropic, Henyey-Greenstein (HG), 58 | and a user defined tabulated function. 59 | - This code does not compute speckle mean. As the mean decays exponentially with the optical depth, in most cases it is negligible. 60 | 61 | ### Core code 62 | 63 | The core algorithms are implemented in MCcov.m (evaluating speckle covariance) and MCfield.m (sampling a spackle field), which are located in code subfolder. 64 | 65 | ## Authors 66 | 67 | * **Chen Bar** - *Department of Electrical Engeneering, Technion, Israel* 68 | * **Marina Alterman** - *Department of Electrical Engeneering, Technion, Israel* 69 | * [**Ioannis Gkioulekas**](http://www.cs.cmu.edu/~igkioule/) - *Robotics Institute, CMU, USA.* 70 | * [**Anat Levin**](http://webee.technion.ac.il/people/anat.levin/) - *Department of Electrical Engeneering, Technion, Israel* 71 | 72 | ## License 73 | 74 | This project is licensed under the ??? 75 | 76 | ## Acknowledgments 77 | 78 | * ?!?!? -------------------------------------------------------------------------------- /code/MCCovHetro.m: -------------------------------------------------------------------------------- 1 | function [Ms,Mm,mean1]=MCCovHetro( sigt, albedo, box_min,box_max,box_bin, l, v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0,lrad) 2 | % is_ff_l: (binary) illumination in far field. 3 | % is_ff_v: (binary) viewing in far field 4 | % l: illumination direction 3xNl or 2xNl or 1xNl(this case is interperated 5 | % as angles and converted to 6 | % 2D vectors) 7 | % if in far field this are assumed to be unit norm vector. In near field 8 | % sensor points 9 | % v: viewing directions 1xNv or 2xNv or 3xNv, directions or points 10 | % sct_type=1 isotropic sct_type=2 parametric amplitude function provided 11 | % sct_type=3 HG, amp_func= g param 12 | % box_min, box_max: 2D or 3D vectors lower and upper bounds on box 13 | %doCBS=1; 14 | Nl=size(l,2); 15 | Nv=size(v,2); 16 | 17 | dim=size(box_min,1); 18 | 19 | 20 | if size(l,1)==1 21 | l=[sin(l); cos(l)]; 22 | end 23 | if size(v,1)==1 24 | v=[sin(v); cos(v)]; 25 | end 26 | 27 | if (length(albedo)==1) 28 | albedo=albedo*ones(size(sigt)); 29 | end 30 | 31 | 32 | Ms=zeros(Nv,Nv,Nl,Nl); 33 | Mm=zeros(Nv,Nv,Nl,Nl); 34 | 35 | mean1=zeros(Nv,Nl); 36 | 37 | 38 | unmeanl=mean(l,2); 39 | meanl=unmeanl/norm(unmeanl); 40 | box_w=box_max-box_min; 41 | 42 | 43 | if exist('lrad','var') 44 | lstart=(box_min+box_max)/2; 45 | lstart(end)=(l(end)>0)*box_min(end)+(l(end)<=0)*box_max(end); 46 | end 47 | if (is_ff_v*is_ff_l) 48 | for j=1:Nl 49 | af_ang_vl(:,j)=evalampfunc_general(l(:,j)'*v,sct_type,ampfunc,dim); 50 | end 51 | end 52 | 53 | if is_ff_v 54 | rv=v; 55 | end 56 | if is_ff_l 57 | rl=l; 58 | end 59 | 60 | ff_sign=-2*(is_ff_v)+1; 61 | 62 | bin_prob=sigt(:)'/sum(sigt(:)); 63 | inv_bin_prob=invCDFvec(cumsum(bin_prob),length(sigt(:))*100); 64 | V=sum(sigt(:))*prod(box_bin);%/mean(sigt(:)); 65 | 66 | 67 | if (dim==2) 68 | %[gz,gx]=ndgrid([box_min(2):box_bin(2):box_max(2)],[box_min(1):box_bin(1):box_max(1)] ); 69 | [gx,gz]=ndgrid([box_min(1):box_bin(1):box_max(1)],[box_min(2):box_bin(2):box_max(2)] ); 70 | 71 | gx_min=gx(1:end-1,1:end-1); 72 | gz_min=gz(1:end-1,1:end-1); 73 | 74 | bin_min=[gx_min(:)';gz_min(:)']; 75 | bin_max=bin_min+box_bin; 76 | else 77 | [gx,gy,gz]=ndgrid([box_min(1):box_bin(1):box_max(1)],[box_min(2):box_bin(2):box_max(2)], [box_min(3):box_bin(3):box_max(3)] ); 78 | gx_min=gx(1:end-1,1:end-1,1:end-1); 79 | gy_min=gy(1:end-1,1:end-1,1:end-1); 80 | gz_min=gz(1:end-1,1:end-1,1:end-1); 81 | 82 | bin_min=[gx_min(:)';gy_min(:)';gz_min(:)']; 83 | bin_max=bin_min+box_bin; 84 | end 85 | 86 | %x1L=zeros(dim,maxItr); 87 | for itr=1:maxItr 88 | %itr/maxItr 89 | 90 | switch smpFlg 91 | case 1 92 | 93 | bin_ind=smpicdf(inv_bin_prob); 94 | 95 | x=rand(dim,1).*(box_bin)+bin_min(:,bin_ind); px=1/V;%sigt(bin_ind); 96 | if exist('lrad','var') 97 | r=norm(x-(l'*x)*l-lstart); 98 | while r>lrad 99 | x=rand(dim,1).*(box_w)+box_min; px=1; 100 | r=norm(x-(l'*x)*l-lstart); 101 | end 102 | end 103 | case 2 104 | %error('not implemented yet') 105 | %[x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 106 | if ~exist('lrad','var') 107 | lrad=[]; 108 | end 109 | [x,px]=expSmpXHetro(box_min,box_max,box_bin,meanl,sigt,lrad); 110 | 111 | 112 | end 113 | if(max(x>box_max)|max(x1) 174 | 175 | e_v=evalphaseattHetro(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max,box_bin); 176 | af_v=evalampfunc_general((ow'*rv),sct_type,ampfunc,dim); 177 | e_v_ms=e_v.*af_v; 178 | 179 | if doCBS 180 | 181 | e_l=evalphaseattHetro(x,l,is_ff_l,sigt,lambda,box_min,box_max,box_bin); 182 | af_l=evalampfunc_general((-ow'*rl),sct_type,ampfunc,dim); 183 | e_l_ms=e_l.*af_l; 184 | 185 | Mn0=e_v_ms(:)*e_v0_ms(:)'; 186 | M0n=e_v0_ms(:)*e_v_ms(:)'; 187 | end 188 | Mnn=e_v_ms(:)*e_v_ms(:)'; 189 | end 190 | if ((pL==2)&(doCBS)) 191 | M00=e_v0_ms(:)*e_v0_ms(:)'; 192 | 193 | end 194 | 195 | 196 | if (pL==1) 197 | 198 | mean1=mean1+weight./px*af_ang_vl.*(e_v0(:)*conj(u_l0(:))'); 199 | 200 | for j1=1:Nl 201 | for j2=1:Nl 202 | Ms(:,:,j1,j2)=Ms(:,:,j1,j2)+... 203 | weight/px*M00*(conj(e_l0(j2))*e_l0(j1)).*(af_ang_vl(:,j1)*af_ang_vl(:,j2)'); 204 | if max(max(isnan(Ms(:,:,j1,j2)))) 205 | keyboard 206 | end 207 | end 208 | end 209 | else 210 | 211 | if doCBS 212 | for j1=1:Nl 213 | for j2=1:Nl 214 | Mm(:,:,j1,j2)=Mm(:,:,j1,j2)+... 215 | weight/px*(... 216 | M00*(conj(e_l_ms(j2))*e_l_ms(j1))+... 217 | Mnn*(conj(e_l0_ms(j2))*e_l0_ms(j1))+... 218 | Mn0*(conj(e_l_ms(j2))*e_l0_ms(j1))+... 219 | M0n*(conj(e_l0_ms(j2))*e_l_ms(j1))); 220 | 221 | 222 | end 223 | end 224 | else 225 | for j1=1:Nl 226 | for j2=1:Nl 227 | Mm(:,:,j1,j2)=Mm(:,:,j1,j2)+... 228 | weight/px*(Mnn*(conj(e_l0_ms(j2))*e_l0_ms(j1))); 229 | 230 | end 231 | end 232 | end 233 | end 234 | if 0 235 | break 236 | end 237 | %d=-log(-rand+1)/(sigt); 238 | d=smpWoodcock(x,box_min,box_max,box_bin,sigt,w); 239 | 240 | x=x+d*w; 241 | 242 | if(max(x>box_max)|max(xalbedo(findBin(x,box_min,box_max,box_bin)) 248 | break 249 | end 250 | else 251 | weight=weight*albedo(findBin(x,box_min,box_max,box_bin)); 252 | end 253 | ow=w; 254 | w= smpampfunc_general(ow, sct_type,ampfunc); 255 | 256 | end 257 | 258 | end 259 | 260 | 261 | 262 | if doCBS 263 | Mm=Mm/2; 264 | end 265 | %V=prod(box_w); 266 | 267 | 268 | Mm=Mm/(maxItr); 269 | Ms=Ms/(maxItr); 270 | 271 | if sct_type==2 272 | cs=mean(ampfunc.pdf)*2*pi; 273 | else 274 | cs=1; 275 | end 276 | mean1=mean1/maxItr/sqrt(cs); 277 | -------------------------------------------------------------------------------- /code/MCcov.m: -------------------------------------------------------------------------------- 1 | function [Ms,Mm]=MCcov(sigt,albedo,box_min,box_max,l,v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0) 2 | %MCCOV MC rendering of covariance algorithm 3 | % 4 | % Calculate the speckle covaraince of far field or near field views and 5 | % lights. 6 | % 7 | % [Ms,Mm]=MCcov(sigt,albedo,box_min,box_max,l,v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0,lrad) 8 | % 9 | % INPUT: 10 | % * 'sigt' - extinction coefficient. 11 | % * 'albedo' - chance to absorption event, number between 0 to 1. also 12 | % defined as sigs/sigt, where sigs is the scattering coefficient. 13 | % * 'box_min' - 2D or 3D vector for lower bound on box. 14 | % * 'box_max' - 2D or 3D vector for upper bound on box. 15 | % * 'l' - illumination direction or points 3xNl (for 3D) or 2xNl (for 16 | % 2D). can be defined also as 1xNl vector, in this case is interperated 17 | % as angles and converted to 2D vectors. 18 | % * 'v' - viewing directions 1xNv or 2xNv or 3xNv, directions or 19 | % points, defined the same as 'l'. 20 | % * 'is_ff_l' - true for illumination in far field, and false for 21 | % illumination in near field. 22 | % * 'is_ff_v' - true for view in far field, and false for view in near 23 | % field. 24 | % * 'maxItr' - number of iterations to run MC algorithm. 25 | % * 'lambda' - the wavelength. 26 | % * 'doCBS' - true for activating Coherent Backscattering. 27 | % * 'smpFlg' - sampling method for first particle. 1 for unifrom 28 | % distribted sampling, and 2 for exponential sampling. 29 | % * 'sct_type' - scattering event type. 1 for isotropic, 2 for 30 | % tabulated amplitude function, 3 for Henyey-Greenstein (HG) function. 31 | % * 'ampfunc' - scattering function parameter. for amplitude function 32 | % a constructed table with the needed parameters (see 33 | % measuredFarField), for HG the g parameter. 34 | % * 'ampfunc0' - (optinal) scattering function for first scattering 35 | % event. 36 | % 37 | % OUTPUT: 38 | % * 'Ms' - speckle covaraince matrix due to single scattering. 4D 39 | % matrix of size |Nv|x|Nv|x|Nl|x|Nl|. 40 | % * 'Mm' - speckle covaraince matrix due to multiple scattering. 4D 41 | % matrix of size |Nv|x|Nv|x|Nl|x|Nl|. The total covariance matrix 42 | % is Ms + Mm. 43 | 44 | %% Check validity of some of the input 45 | narginchk(14,15); 46 | 47 | % get the dimensions 48 | if((numel(box_max) ~= 2 && numel(box_max) ~= 3) || ... 49 | (size(box_max,2) ~= 1) || (any(size(box_max) ~= size(box_min)))) 50 | error('Invalid box size'); 51 | end 52 | 53 | dim = size(box_min,1); 54 | 55 | % get number of sources 56 | if(size(l,1) ~= dim) 57 | if(dim == 2 && size(l,1) == 1) 58 | l = [sin(l); cos(l)]; 59 | else 60 | error('Invalid light source input'); 61 | end 62 | end 63 | 64 | if(size(v,1) ~= dim) 65 | if(dim == 2 && size(v,1) == 1) 66 | v = [sin(v); cos(v)]; 67 | else 68 | error('Invalid view source input'); 69 | end 70 | end 71 | 72 | Nl = size(l,2); 73 | Nv = size(v,2); 74 | 75 | %% Prepare for algorithm 76 | 77 | % Initiate output parameters 78 | Ms = zeros(Nv,Nv,Nl,Nl); 79 | Mm = zeros(Nv,Nv,Nl,Nl); 80 | 81 | % Scattering direction of first scattering event 82 | unmeanl = mean(l,2); 83 | meanl = unmeanl/norm(unmeanl); 84 | 85 | % Box size 86 | box_w = box_max - box_min; 87 | 88 | % Pre-calculate single scattering rotation amplitude, only possible when 89 | % both light and view are far field (otherwise it also dependent on the 90 | % first scatter position) 91 | af_ang_vl = zeros(Nv, Nl); 92 | if (is_ff_v && is_ff_l) 93 | for j=1:Nl 94 | af_ang_vl(:,j) = evalampfunc_general(l(:,j)'*v,sct_type,ampfunc,dim); 95 | end 96 | end 97 | 98 | % in far field, the entrance direction to the box is fixed 99 | if is_ff_v 100 | rv = v; 101 | end 102 | 103 | if is_ff_l 104 | rl = l; 105 | end 106 | 107 | ff_sign=-2*(is_ff_v)+1; 108 | 109 | % threshold to begin kill particles with low weight 110 | killThr=0.2; 111 | %% Begin the main loop 112 | for itr=1:maxItr 113 | 114 | % Sample the first scatter 115 | % x: first scattering point 116 | % px: probability by which first point was sampled. Needed so that 117 | % importance sampling integration is weighted properly 118 | switch smpFlg 119 | case 1 120 | % uniform distribution 121 | x=rand(dim,1).*(box_w)+box_min; px=1; 122 | case 2 123 | % exponential distribution 124 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 125 | end 126 | 127 | % entrance directions for near-field sources 128 | if ~is_ff_v 129 | rv=v-repmat(x,1,Nv); 130 | rv=rv./repmat(sum(rv.^2,1).^0.5,dim,1); 131 | end 132 | if ~is_ff_l 133 | rl=repmat(x,1,Nl)-l; 134 | rl=rl./repmat(sum(rl.^2,1).^0.5,dim,1); 135 | end 136 | 137 | % single scattering rotation amplitude 138 | if ~(is_ff_v && is_ff_l) 139 | for j=1:Nl 140 | af_ang_vl(:,j)=evalampfunc_general(rl(:,j)'*rv,sct_type,ampfunc,dim); 141 | end 142 | end 143 | 144 | % First scattering direction 145 | % w - sampled direction. 146 | % w0p - probability of the sampled direction, needed to compute inportance sampling integral correctly. 147 | if ~exist('ampfunc0','var') 148 | w=randn(dim,1); w=w/norm(w); 149 | w0p=1/sqrt(2^(dim-1)*pi); 150 | else 151 | w=smpampfunc_general(meanl, sct_type,ampfunc0); 152 | w0p=(evalampfunc_general(meanl'*w,sct_type,ampfunc0,dim)); 153 | end 154 | 155 | % rotation due to first scattering in multiple scattering case (s 156 | % function in article). 157 | af_l=evalampfunc_general((w'*rl),sct_type,ampfunc,dim)./w0p; 158 | 159 | % complex transmission (xi function in article) and attenuation term 160 | % in multiple scattering (tau function in article) between first scattering 161 | % particle and the light source 162 | e_l0=evalphaseatt(x,l,is_ff_l,sigt,lambda,box_min,box_max); 163 | 164 | % complex volumetric throughput (ni function in article) of first 165 | % scattering event to be used with paths of length >1 ( the multiple scattering 166 | % case) 167 | e_l0_ms=e_l0.*af_l; 168 | 169 | % complex volumetric throughput connecting first scattering particle 170 | % and the sensors 171 | e_v0=evalphaseatt(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max); 172 | 173 | % in case of coherent backscattering, calculate also the complex 174 | % volumetric throughput where the path begins from the view to the 175 | % first scatter 176 | if doCBS 177 | af_v=evalampfunc_general((-w'*rv),sct_type,ampfunc,dim)./w0p; 178 | e_v0_ms=e_v0.*af_v; 179 | end 180 | 181 | % all possible volumetric throughput pair of viewing directions 182 | % to be used when path length=1 183 | % Below we will define the matrices M00 M0n Mn0 Mnn corresponding to 184 | % all 4 combinations of forward and reversed paths. 185 | % M00: 2 reversed paths connecting the first node on the path to v1 v2 186 | % M0n: reversed +forward, first node connected to v1, last node to v2 187 | % Mn0: forward + reversed, last node connected to v1, first node to v2 188 | % Mnn: forward +forward, last node connected to v1 and v2 189 | 190 | M00=e_v0(:)*e_v0(:)'; 191 | 192 | % number of scattering events 193 | pL=0; 194 | 195 | % intensity loss due to albedo 196 | weight=albedo; 197 | 198 | % begin paths sampling loop 199 | while 1 200 | 201 | pL=pL+1; 202 | 203 | % calculate the complex volumetric throughput for the last 204 | % scattering event in case of path length >1 205 | if (pL>1) 206 | 207 | e_v=evalphaseatt(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max); 208 | af_v=evalampfunc_general((ow'*rv),sct_type,ampfunc,dim); 209 | e_v_ms=e_v.*af_v; 210 | 211 | if doCBS 212 | 213 | e_l=evalphaseatt(x,l,is_ff_l,sigt,lambda,box_min,box_max); 214 | af_l=evalampfunc_general((-ow'*rl),sct_type,ampfunc,dim); 215 | e_l_ms=e_l.*af_l; 216 | 217 | Mn0=e_v_ms(:)*e_v0_ms(:)'; 218 | M0n=e_v0_ms(:)*e_v_ms(:)'; 219 | end 220 | 221 | Mnn=e_v_ms(:)*e_v_ms(:)'; 222 | end 223 | 224 | 225 | % in cbs, the complex volumetric throughput of the views in case of 226 | % the reverse path can be pre-calculated 227 | if ((pL==2) && (doCBS)) 228 | M00=e_v0_ms(:)*e_v0_ms(:)'; 229 | end 230 | 231 | % Update covariance with next-event estimation 232 | if (pL==1) 233 | % speckle covaraince matrix due to single scattering 234 | for j1=1:Nl 235 | for j2=1:Nl 236 | Ms(:,:,j1,j2)=Ms(:,:,j1,j2)+... 237 | weight/px*M00 * ... 238 | (conj(e_l0(j2))*e_l0(j1)) .* ... 239 | (af_ang_vl(:,j1)*af_ang_vl(:,j2)'); 240 | end 241 | end 242 | else 243 | % speckle covaraince matrix due to multiple scattering 244 | if doCBS 245 | for j1=1:Nl 246 | for j2=1:Nl 247 | Mm(:,:,j1,j2)=Mm(:,:,j1,j2)+... 248 | weight/px*(... 249 | M00*(conj(e_l_ms(j2))*e_l_ms(j1))+... 250 | Mnn*(conj(e_l0_ms(j2))*e_l0_ms(j1))+... 251 | Mn0*(conj(e_l_ms(j2))*e_l0_ms(j1))+... 252 | M0n*(conj(e_l0_ms(j2))*e_l_ms(j1))); 253 | end 254 | end 255 | else 256 | for j1=1:Nl 257 | for j2=1:Nl 258 | Mm(:,:,j1,j2)=Mm(:,:,j1,j2)+... 259 | weight/px*(Mnn*(conj(e_l0_ms(j2))*e_l0_ms(j1))); 260 | 261 | end 262 | end 263 | end 264 | end 265 | 266 | % advance to the next scattering event 267 | d=-log(-rand+1)/(sigt); 268 | x=x+d*w; 269 | 270 | % Terminate the path if the next scattering event that was sampled 271 | % is outside the box 272 | if(max(x>box_max) || max(xalbedo 280 | break 281 | end 282 | else 283 | weight=weight*albedo; 284 | end 285 | 286 | % sample new scatteing direction 287 | ow=w; 288 | w=smpampfunc_general(ow, sct_type,ampfunc); 289 | end 290 | end 291 | 292 | %% Normalization 293 | if doCBS 294 | Mm=Mm/2; 295 | end 296 | 297 | V=prod(box_w); 298 | Mm=Mm/(maxItr)*V*sigt; 299 | Ms=Ms/(maxItr)*V*sigt; 300 | 301 | -------------------------------------------------------------------------------- /code/MCfield.m: -------------------------------------------------------------------------------- 1 | function [u]=MCfield(sigt,albedo,box_min,box_max,l,v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0,lmean0) 2 | %MCFIELD MC rendering field algorithm 3 | % 4 | % render a speckle field for Nv viewings and Nl lights 5 | % 6 | % u=MCfield(sigt,albedo,box_min,box_max,l,v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0,lmean0) 7 | % 8 | % INPUT: 9 | % * 'sigt' - extinction coefficient. 10 | % * 'albedo' - chance to absorption event, number between 0 to 1. also 11 | % defined as sigs/sigt, where sigs is the scattering coefficient. 12 | % * 'box_min' - 2D or 3D vector for lower bound on box. 13 | % * 'box_max' - 2D or 3D vector for upper bound on box. 14 | % * 'l' - illumination direction or points 3xNl (for 3D) or 2xNl (for 15 | % 2D). can be defined also as 1xNl vector, in this case is interperated 16 | % as angles and converted to 2D vectors. 17 | % * 'v' - viewing directions 1xNv or 2xNv or 3xNv, directions or 18 | % points, defined the same as 'l'. 19 | % * 'is_ff_l' - true for illumination in far field, and false for 20 | % illumination in near field. 21 | % * 'is_ff_v' - true for view in far field, and false for view in near 22 | % field. 23 | % * 'maxItr' - number of iterations to run MC algorithm. 24 | % * 'lambda' - the wavelength. 25 | % * 'doCBS' - true for activating Coherent Backscattering. 26 | % * 'smpFlg' - sampling method for first particle. 1 for unifrom 27 | % distribted sampling, and 2 for exponential distribution sampling. 28 | % * 'sct_type' - scattering event type. 1 for isotropic, 2 for tabulated 29 | % amplitude function, 3 for Henyey-Greenstein (HG) function. 30 | % * 'ampfunc' - scattering function parameter. for amplitude function 31 | % is a constructed table with the needed parameters (see 32 | % measuredFarField), for HG the g parameter. 33 | % * 'ampfunc0' - (optinal) scattering function for first scattering 34 | % event. 35 | % * 'lmean0' - (optional) direction of first scattering event 36 | % 37 | % OUTPUT: 38 | % * 'u' - rendered field in size of |Nv|x|Nl| 39 | 40 | %% Check validity of some of the input 41 | narginchk(14,16); 42 | 43 | % get the dimensions size 44 | if((numel(box_max) ~= 2 && numel(box_max) ~= 3) || ... 45 | (size(box_max,2) ~= 1) || (any(size(box_max) ~= size(box_min)))) 46 | error('Invalid box size'); 47 | end 48 | 49 | dim = size(box_min,1); 50 | 51 | % get number of sources 52 | if(size(l,1) ~= dim) 53 | if(dim == 2 && size(l,1) == 1) 54 | l = [sin(l); cos(l)]; 55 | else 56 | error('Invalid light source input'); 57 | end 58 | end 59 | 60 | if(size(v,1) ~= dim) 61 | if(dim == 2 && size(v,1) == 1) 62 | v = [sin(v); cos(v)]; 63 | else 64 | error('Invalid view source input'); 65 | end 66 | end 67 | 68 | Nl = size(l,2); 69 | Nv = size(v,2); 70 | 71 | %% Prepare for algorithm 72 | 73 | % Initiate output parameters 74 | u = zeros(Nv,Nl); 75 | 76 | % first scattering event direction 77 | if ~exist('lmean0','var') 78 | unmeanl = mean(l,2); 79 | else 80 | unmeanl = lmean0; 81 | end 82 | meanl = unmeanl/norm(unmeanl); 83 | 84 | % Box size 85 | box_w = box_max-box_min; 86 | 87 | % Pre-calculate single scattering rotation amplitude, only possible when 88 | % both light and view are far field (otherwise it also dependent on the 89 | % first scatter position) 90 | af_ang_vl = zeros(Nv, Nl); 91 | if (is_ff_v && is_ff_l) 92 | for j=1:Nl 93 | af_ang_vl(:,j)=evalampfunc_general(l(:,j)'*v,sct_type,ampfunc,dim); 94 | end 95 | end 96 | 97 | % in far field, the entrance direction to the box is fixed 98 | if is_ff_v 99 | rv=v; 100 | end 101 | 102 | if is_ff_l 103 | rl=l; 104 | end 105 | 106 | ff_sign=-2*(is_ff_v)+1; 107 | 108 | % threshold to begin kill particles with low weight 109 | killThr=0.2; 110 | 111 | %% Begin the main loop 112 | for itr=1:maxItr 113 | %itr 114 | % Sample the first scatter 115 | % x: first scattering point 116 | % px: probability by which first point was sampled. Needed so that 117 | % importance sampling integration is weighted properly 118 | switch smpFlg 119 | case 1 120 | % uniform distribution 121 | x=rand(dim,1).*(box_w)+box_min; px=1; 122 | case 2 123 | % exponential distribution 124 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 125 | end 126 | %x=[0;30;0.0000001]; 127 | %x=[-30;0;50]; 128 | %x 129 | % entrance directions for near-field sources 130 | if ~is_ff_v 131 | rv=v-repmat(x,1,Nv); 132 | rv=rv./repmat(sum(rv.^2,1).^0.5,dim,1); 133 | end 134 | if ~is_ff_l 135 | rl=repmat(x,1,Nl)-l; 136 | rl=rl./repmat(sum(rl.^2,1).^0.5,dim,1); 137 | end 138 | 139 | % single scattering rotation amplitude 140 | if ~(is_ff_v && is_ff_l) 141 | for j=1:Nl 142 | af_ang_vl(:,j)=evalampfunc_general(rl(:,j)'*rv,sct_type,ampfunc,dim); 143 | end 144 | end 145 | 146 | % First scattering direction 147 | % w - sampled direction. 148 | % w0p - probability of the sampled direction, needed to compute inportance sampling integral correctly. 149 | if ~exist('ampfunc0','var') 150 | w=randn(dim,1); w=w/norm(w); 151 | w0p=1/sqrt(2^(dim-1)*pi); 152 | else 153 | w=smpampfunc_general(meanl, sct_type,ampfunc0); 154 | w0p=(evalampfunc_general(meanl'*w,sct_type,ampfunc0,dim)); 155 | end 156 | 157 | % rotation due to first scattering in multiple scattering case (s 158 | % function in article). 159 | af_l=evalampfunc_general((w'*rl),sct_type,ampfunc,dim)./w0p; 160 | 161 | % complex transmission (xi function in article) and attenuation term 162 | % in multiple scattering (tau function in article) between first scattering 163 | % particle and the light source 164 | e_l0=evalphaseatt(x,l,is_ff_l,sigt,lambda,box_min,box_max); 165 | 166 | % complex volumetric throughput (ni function in article) of first 167 | % scattering event to be used with paths of length >1 (the multiple scattering 168 | % case) 169 | e_l0_ms=e_l0.*af_l; 170 | 171 | % complex volumetric throughput connecting first scattering particle 172 | % and the sensors 173 | e_v0=evalphaseatt(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max); 174 | 175 | % in case of coherent backscattering, calculate also the complex 176 | % volumetric throughput where the path begins from the view to the 177 | % first scatter 178 | if doCBS 179 | af_v=evalampfunc_general((-w'*rv),sct_type,ampfunc,dim)./w0p; 180 | e_v0_ms=e_v0.*af_v; 181 | end 182 | 183 | % number of scattering events 184 | pL=0; 185 | 186 | % intensity loss due to albedo 187 | weight=albedo; 188 | 189 | % begin paths sampling loop 190 | while 1 191 | 192 | pL=pL+1; 193 | 194 | % calculate the complex volumetric throughput for the last 195 | % scattering event in case of multiple scattering 196 | if (pL>1) 197 | e_v=evalphaseatt(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max); 198 | af_v=evalampfunc_general((ow'*rv),sct_type,ampfunc,dim); 199 | e_v_ms=e_v.*af_v; 200 | if doCBS 201 | e_l=evalphaseatt(x,l,is_ff_l,sigt,lambda,box_min,box_max); 202 | af_l=evalampfunc_general((-ow'*rl),sct_type,ampfunc,dim); 203 | e_l_ms=e_l.*af_l; 204 | end 205 | end 206 | 207 | % Update field with next-event estimation 208 | if (pL==1) 209 | tpath=af_ang_vl.*(e_v0(:)*conj(e_l0(:))'); 210 | else 211 | tpath=(e_v_ms(:)*conj(e_l0_ms(:))'); 212 | if doCBS 213 | tpath=1/sqrt(2)*(tpath+(e_v0_ms(:)*conj(e_l_ms(:))')); 214 | end 215 | end 216 | 217 | % weight path 218 | tpath=sqrt(weight./px)*tpath; 219 | % sample random phase for path 220 | tpath=tpath*exp(2*pi*1i*rand); 221 | %add path to field 222 | u=u+tpath; 223 | 224 | % advance to the next scattering event 225 | d=-log(-rand+1)/(sigt); 226 | x=x+d*w; 227 | 228 | % move to the next particle if the next scattering event is outside 229 | % the box 230 | if(max(x>box_max) || max(xalbedo 238 | break 239 | end 240 | else 241 | weight=weight*albedo; 242 | end 243 | 244 | % Sample new scatteing direction 245 | ow=w; 246 | w=smpampfunc_general(ow, sct_type,ampfunc); 247 | 248 | end 249 | 250 | end 251 | 252 | %% Normalization 253 | V=prod(box_w); 254 | u=u*sqrt(1/maxItr*V*sigt); 255 | 256 | -------------------------------------------------------------------------------- /code/MCfieldFourierQuad.m: -------------------------------------------------------------------------------- 1 | function [u]=MCfield(sigt,albedo,box_min,box_max,l,v_max,v_stp,maxItr,lambda,doCBS,smpFlg,lmean0,vsign) 2 | %MCFIELD MC rendering field algorithm 3 | % 4 | % render a speckle field for Nv viewings and Nl lights 5 | % 6 | % u=MCfield(sigt,albedo,box_min,box_max,l,v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0,lmean0) 7 | % 8 | % INPUT: 9 | % * 'sigt' - extinction coefficient. 10 | % * 'albedo' - chance to absorption event, number between 0 to 1. also 11 | % defined as sigs/sigt, where sigs is the scattering coefficient. 12 | % * 'box_min' - 2D or 3D vector for lower bound on box. 13 | % * 'box_max' - 2D or 3D vector for upper bound on box. 14 | % * 'l' - illumination direction or points 3xNl (for 3D) or 2xNl (for 15 | % 2D). can be defined also as 1xNl vector, in this case is interperated 16 | % as angles and converted to 2D vectors. 17 | % 18 | % v_max, v_stp: (scalars) define a grid of viewing directions 19 | % vsign: (-1 or 1) whatever viewing grid at the front of back side of the phantom 20 | % 21 | % 22 | % 23 | % * 'maxItr' - number of iterations to run MC algorithm. 24 | % * 'lambda' - the wavelength. 25 | % * 'doCBS' - true for activating Coherent Backscattering. 26 | % * 'smpFlg' - sampling method for first particle. 1 for unifrom 27 | % distribted sampling, and 2 for exponential distribution sampling. 28 | % * 'sct_type' - this code is only for the isotropic scattering case 29 | % * 'lmean0' - (optional) direction of first scattering event 30 | 31 | 32 | 33 | % 34 | % OUTPUT: 35 | % * 'u' - rendered field in size of |Nv|x|Nl| 36 | 37 | %% Check validity of some of the input 38 | 39 | 40 | % get the dimensions size 41 | if((numel(box_max) ~= 2 && numel(box_max) ~= 3) || ... 42 | (size(box_max,2) ~= 1) || (any(size(box_max) ~= size(box_min)))) 43 | error('Invalid box size'); 44 | end 45 | 46 | dim = size(box_min,1); 47 | 48 | 49 | 50 | Nl = size(l,2); 51 | %Nv = size(v,2); 52 | 53 | %% Prepare for algorithm 54 | 55 | % Initiate output parameters 56 | 57 | 58 | % first scattering event direction 59 | if ~exist('lmean0','var')|isempty(lmean0) 60 | unmeanl = [0;0;1]; 61 | else 62 | unmeanl = lmean0; 63 | end 64 | meanl = unmeanl/norm(unmeanl); 65 | 66 | if ~exist('vsign','var') %this input parameter indicates from which side of the phantom the viewing grid is located 67 | vsign=-1; 68 | end 69 | % Box size 70 | box_w = box_max-box_min; 71 | 72 | 73 | 74 | 75 | 76 | 77 | ff_sign=-2*(1)+1; 78 | 79 | 80 | vbin_scl=1; 81 | vrng_scl=1%5; 82 | theta_v0=[-v_max:v_stp/vbin_scl:v_max]; 83 | v_max=v_max*vrng_scl; 84 | theta_v=[-v_max:v_stp/vbin_scl:v_max]; 85 | 86 | 87 | 88 | Nv=length(theta_v) 89 | Nv0=length(theta_v0) 90 | 91 | 92 | box_stp=lambda/(v_max*2+v_stp); 93 | 94 | Nx=ceil(box_w(1)/box_stp/2)*2+1; 95 | box_w_n=Nx*box_stp; 96 | box_min(1:2)=box_min(1:2)-(box_w_n-box_w(1))/2; 97 | box_max(1:2)=box_max(1:2)+(box_w_n-box_w(1))/2; 98 | box_w(1:2)=box_w_n; 99 | 100 | [gx,gy]=ndgrid([box_min(1)+box_stp/2:box_stp:box_max(1)],[box_min(2)+box_stp/2:box_stp:box_max(2)]); 101 | 102 | 103 | Nx_padd_size=max((Nv-Nx)/2,0); 104 | Nv_padd_size=max((Nx-Nv)/2,0); 105 | Nv0_padd_size=max((Nv-Nv0)/2,0); 106 | Nva_padd_size=Nv0_padd_size+Nv_padd_size; 107 | 108 | [vx,vy]=ndgrid(-theta_v,-theta_v); 109 | vz=vsign*sqrt(1-vx.^2-vy.^2); 110 | 111 | vx0=vx(1+Nv0_padd_size:end-Nv0_padd_size,1+Nv0_padd_size:end-Nv0_padd_size); 112 | vy0=vy(1+Nv0_padd_size:end-Nv0_padd_size,1+Nv0_padd_size:end-Nv0_padd_size); 113 | vz0=vz(1+Nv0_padd_size:end-Nv0_padd_size,1+Nv0_padd_size:end-Nv0_padd_size); 114 | 115 | 116 | z_bin=lambda/max(1-abs(vz(:)))/5; 117 | z_bin=z_bin/2;%/5; 118 | gz=[box_min(end):z_bin:box_max(end),box_max(end)]; 119 | %Nz=length(zL); 120 | 121 | Nz=length(gz); 122 | 123 | 124 | diratt0=1./abs(vz0).*(vz0<0); 125 | idiratt0=1./abs(vz0).*(vz0>0); 126 | 127 | l_diratt=1./abs(l(end)).*(l(end)>0); 128 | l_idiratt=1./abs(l(end)).*(l(end)<0); 129 | 130 | %zexp0=(-2*pi*i/lambda*vz0-sigt/2*diratt0); 131 | %boxexp0=exp(-sigt/2*(-box_min(end)).*diratt0); 132 | 133 | %zexp0=(-2*pi*i/lambda*vz0-sigt/2*diratt0); 134 | zexp0=(-2*pi*i/lambda*vz0*vsign-sigt/2*(diratt0-idiratt0)); 135 | 136 | %boxexp0=exp(-sigt/2*(-box_min(end)).*diratt0); 137 | boxexp0=exp(-sigt/2*(-box_min(end).*diratt0+box_max(end).*idiratt0)); 138 | boxexp0=boxexp0.*exp(2*pi*i/lambda*(-box_min(end).*(vz0<0).*vz0+box_max(end).*(vz0>0).*vz0 )); 139 | 140 | 141 | 142 | 143 | % threshold to begin kill particles with low weight 144 | killThr=0.2; 145 | 146 | ExpOD=sigt*box_w(end)+1; 147 | xL=zeros(dim,round(maxItr*ExpOD)); 148 | x1L=zeros(dim,round(maxItr*ExpOD)); 149 | 150 | pxL=zeros(1,size(xL,2)); 151 | pathL=zeros(1,size(xL,2)); 152 | c_itr=0; 153 | %% Begin the main loop 154 | for itr=1:maxItr 155 | 156 | % Sample the first scatter 157 | % x: first scattering point 158 | % px: probability by which first point was sampled. Needed so that 159 | % importance sampling integration is weighted properly 160 | switch smpFlg 161 | case 1 162 | % uniform distribution 163 | x=rand(dim,1).*(box_w)+box_min; px=1; 164 | case 2 165 | % exponential distribution 166 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 167 | end 168 | 169 | x1=x; 170 | 171 | w=randn(dim,1); w=w/norm(w); 172 | w0p=1/sqrt(2^(dim-1)*pi); 173 | 174 | weight=albedo; 175 | p_len=0; 176 | while 1 177 | p_len=p_len+1; 178 | c_itr=c_itr+1; 179 | xL(:,c_itr)=x; 180 | x1L(:,c_itr)=x1; 181 | pxL(:,c_itr)=sqrt(weight./px)*exp(2*pi*i*rand); 182 | if (doCBS)&(p_len>1), pxL(:,c_itr)= 1/sqrt(2)*pxL(:,c_itr); end 183 | pathL(:,c_itr)=p_len; 184 | 185 | 186 | % advance to the next scattering event 187 | d=-log(-rand+1)/(sigt); 188 | x=x+d*w; 189 | 190 | % move to the next particle if the next scattering event is outside 191 | % the box 192 | if(max(x>box_max) || max(xalbedo 200 | break 201 | end 202 | else 203 | weight=weight*albedo; 204 | end 205 | 206 | % Sample new scatteing direction 207 | ow=w; 208 | w=randn(dim,1); w=w/norm(w); %smpampfunc_general(ow, sct_type,ampfunc); 209 | 210 | 211 | 212 | end 213 | end 214 | maxItr=c_itr; 215 | xL=xL(:,1:maxItr); 216 | x1L=x1L(:,1:maxItr); 217 | pxL=pxL(:,1:maxItr); 218 | pathL=pathL(:,1:maxItr); 219 | 220 | 221 | 222 | u=zeros(Nv0,Nv0,Nl); 223 | 224 | for tt=1:2 225 | 226 | if (tt==2) 227 | if ~doCBS 228 | continue 229 | end 230 | txL=xL; 231 | xL=x1L; x1L=txL; 232 | end 233 | 234 | [sv,si]=sort(x1L(end,:)); 235 | xL=xL(:,si); 236 | pxL=pxL(:,si); 237 | x1L=x1L(:,si); 238 | pathL=pathL(:,si); 239 | 240 | 241 | 242 | z_ind_max=0; 243 | plane_count=zeros(1,Nz-1); 244 | time_count=zeros(1,Nz-1); 245 | for j1=1:Nz-1 246 | j1/Nz 247 | c_itr=z_ind_max+1; 248 | z_max=gz(j1+1); 249 | while (c_itr<=maxItr)& (x1L(end,c_itr)0); 138 | 139 | l_diratt=1./abs(l(end)).*(l(end)>0); 140 | l_idiratt=1./abs(l(end)).*(l(end)<0); 141 | 142 | %zexp0=(-2*pi*i/lambda*vz0-sigt/2*diratt0); 143 | zexp0=(2*pi*1i/lambda*vz0*vsign-sigt/2*(diratt0-idiratt0)); 144 | 145 | 146 | %boxexp0=exp(-sigt/2*(-box_min(end)).*diratt0); 147 | 148 | boxexp0=exp(-sigt/2*(-box_min(end).*diratt0+box_max(end).*idiratt0)); 149 | boxexp0=boxexp0.*exp(2*pi*1i/lambda*(-box_min(end).*(vz0<0).*vz0+box_max(end).*(vz0>0).*vz0 )); 150 | 151 | 152 | % threshold to begin kill particles with low weight 153 | killThr=0.2; 154 | 155 | ExpOD=sigt*box_w(end)+1; 156 | xL=zeros(dim,round(maxItr*ExpOD)); 157 | x1L=zeros(dim,round(maxItr*ExpOD)); 158 | 159 | pxL=zeros(1,size(xL,2)); 160 | pathL=zeros(1,size(xL,2)); 161 | c_itr=0; 162 | %% Begin the main loop 163 | for itr=1:maxItr 164 | 165 | % Sample the first scatter 166 | % x: first scattering point 167 | % px: probability by which first point was sampled. Needed so that 168 | % importance sampling integration is weighted properly 169 | switch smpFlg 170 | case 1 171 | % uniform distribution 172 | x=rand(dim,1).*(box_w)+box_min; px=1; 173 | case 2 174 | % exponential distribution 175 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 176 | end 177 | 178 | x1=x; 179 | 180 | w=randn(dim,1); w=w/norm(w); 181 | w0p=1/sqrt(2^(dim-1)*pi); 182 | 183 | weight=albedo; 184 | p_len=0; 185 | while 1 186 | p_len=p_len+1; 187 | c_itr=c_itr+1; 188 | xL(:,c_itr)=x; 189 | x1L(:,c_itr)=x1; 190 | pxL(:,c_itr)=sqrt(weight./px)*exp(2*pi*1i*rand); 191 | if (doCBS)&(p_len>1), pxL(:,c_itr)= 1/sqrt(2)*pxL(:,c_itr); end 192 | pathL(:,c_itr)=p_len; 193 | 194 | 195 | % advance to the next scattering event 196 | d=-log(-rand+1)/(sigt); 197 | x=x+d*w; 198 | 199 | % move to the next particle if the next scattering event is outside 200 | % the box 201 | if(max(x>box_max) || max(xalbedo 209 | break 210 | end 211 | else 212 | weight=weight*albedo; 213 | end 214 | 215 | % Sample new scatteing direction 216 | ow=w; 217 | w=randn(dim,1); w=w/norm(w); %smpampfunc_general(ow, sct_type,ampfunc); 218 | 219 | 220 | 221 | end 222 | end 223 | maxItr=c_itr; 224 | xL=xL(:,1:maxItr); 225 | x1L=x1L(:,1:maxItr); 226 | pxL=pxL(:,1:maxItr); 227 | pathL=pathL(:,1:maxItr); 228 | 229 | 230 | 231 | 232 | 233 | 234 | u=zeros(Nv0,Nv0); 235 | 236 | for tt=1:2 237 | 238 | if (tt==2) 239 | if ~doCBS 240 | continue 241 | end 242 | txL=xL; 243 | xL=x1L; x1L=txL; 244 | end 245 | 246 | [sv,si]=sort(x1L(end,:)); 247 | xL=xL(:,si); 248 | pxL=pxL(:,si); 249 | x1L=x1L(:,si); 250 | pathL=pathL(:,si); 251 | 252 | 253 | 254 | z_ind_max=0; 255 | plane_count=zeros(1,Nz-1); 256 | time_count=zeros(1,Nz-1); 257 | for j1=1:Nz-1 258 | % j1/Nz 259 | c_itr=z_ind_max+1; 260 | z_max=gz(j1+1); 261 | while (c_itr<=maxItr)& (x1L(end,c_itr)0); 138 | 139 | l_diratt=1./abs(l(end)).*(l(end)>0); 140 | l_idiratt=1./abs(l(end)).*(l(end)<0); 141 | 142 | %zexp0=(-2*pi*i/lambda*vz0-sigt/2*diratt0); 143 | zexp0=(2*pi*1i/lambda*vz0*vsign-sigt/2*(diratt0-idiratt0)); 144 | 145 | 146 | %boxexp0=exp(-sigt/2*(-box_min(end)).*diratt0); 147 | 148 | boxexp0=exp(-sigt/2*(-box_min(end).*diratt0+box_max(end).*idiratt0)); 149 | boxexp0=boxexp0.*exp(2*pi*1i/lambda*(-box_min(end).*(vz0<0).*vz0+box_max(end).*(vz0>0).*vz0 )); 150 | 151 | 152 | % threshold to begin kill particles with low weight 153 | killThr=0.2; 154 | 155 | ExpOD=sigt*box_w(end)+1; 156 | xL=zeros(dim,round(maxItr*ExpOD)); 157 | x1L=zeros(dim,round(maxItr*ExpOD)); 158 | 159 | pxL=zeros(1,size(xL,2)); 160 | pathL=zeros(1,size(xL,2)); 161 | c_itr=0; 162 | %% Begin the main loop 163 | for itr=1:maxItr 164 | 165 | % Sample the first scatter 166 | % x: first scattering point 167 | % px: probability by which first point was sampled. Needed so that 168 | % importance sampling integration is weighted properly 169 | switch smpFlg 170 | case 1 171 | % uniform distribution 172 | x=rand(dim,1).*(box_w)+box_min; px=1; 173 | case 2 174 | % exponential distribution 175 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 176 | end 177 | 178 | x1=x; 179 | 180 | w=randn(dim,1); w=w/norm(w); 181 | w0p=1/sqrt(2^(dim-1)*pi); 182 | 183 | weight=albedo; 184 | p_len=0; 185 | while 1 186 | p_len=p_len+1; 187 | c_itr=c_itr+1; 188 | xL(:,c_itr)=x; 189 | x1L(:,c_itr)=x1; 190 | pxL(:,c_itr)=sqrt(weight./px)*exp(2*pi*1i*rand); 191 | if (doCBS)&(p_len>1), pxL(:,c_itr)= 1/sqrt(2)*pxL(:,c_itr); end 192 | pathL(:,c_itr)=p_len; 193 | 194 | 195 | % advance to the next scattering event 196 | d=-log(-rand+1)/(sigt); 197 | x=x+d*w; 198 | 199 | % move to the next particle if the next scattering event is outside 200 | % the box 201 | if(max(x>box_max) || max(xalbedo 209 | break 210 | end 211 | else 212 | weight=weight*albedo; 213 | end 214 | 215 | % Sample new scatteing direction 216 | ow=w; 217 | w=randn(dim,1); w=w/norm(w); %smpampfunc_general(ow, sct_type,ampfunc); 218 | 219 | 220 | 221 | end 222 | end 223 | maxItr=c_itr; 224 | xL=xL(:,1:maxItr); 225 | x1L=x1L(:,1:maxItr); 226 | pxL=pxL(:,1:maxItr); 227 | pathL=pathL(:,1:maxItr); 228 | 229 | 230 | 231 | 232 | 233 | 234 | u=zeros(Nv0,Nv0); 235 | 236 | for tt=1:2 237 | 238 | if (tt==2) 239 | if ~doCBS 240 | continue 241 | end 242 | txL=xL; 243 | xL=x1L; x1L=txL; 244 | end 245 | 246 | [sv,si]=sort(x1L(end,:)); 247 | xL=xL(:,si); 248 | pxL=pxL(:,si); 249 | x1L=x1L(:,si); 250 | pathL=pathL(:,si); 251 | 252 | 253 | 254 | z_ind_max=0; 255 | plane_count=zeros(1,Nz-1); 256 | time_count=zeros(1,Nz-1); 257 | for j1=1:Nz-1 258 | % j1/Nz 259 | c_itr=z_ind_max+1; 260 | z_max=gz(j1+1); 261 | while (c_itr<=maxItr)& (x1L(end,c_itr)1 93 | for j=1:Nl 94 | af_ang_vl(:,j)=evalampfunc_general(l(:,j)'*v,sct_type,ampfunc,dim); 95 | end 96 | else 97 | af_ang_vl=evalampfunc_general(0,sct_type,ampfunc,dim); 98 | end 99 | end 100 | 101 | % in far field, the entrance direction to the box is fixed 102 | if is_ff_v 103 | rv=v; 104 | end 105 | 106 | if is_ff_l 107 | rl=l; 108 | end 109 | 110 | ff_sign=-2*(is_ff_v)+1; 111 | 112 | % threshold to begin kill particles with low weight 113 | killThr=0.2; 114 | 115 | %% Begin the main loop 116 | for itr=1:maxItr 117 | %itr 118 | % Sample the first scatter 119 | % x: first scattering point 120 | % px: probability by which first point was sampled. Needed so that 121 | % importance sampling integration is weighted properly 122 | switch smpFlg 123 | case 1 124 | % uniform distribution 125 | x=rand(dim,1).*(box_w)+box_min; px=1; 126 | case 2 127 | % exponential distribution 128 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 129 | end 130 | %x=[0;30;0.0000001]; 131 | %x=[-30;0;50]; 132 | %x 133 | % entrance directions for near-field sources 134 | if ~is_ff_v 135 | rv=v-repmat(x,1,Nv); 136 | rv=rv./repmat(sum(rv.^2,1).^0.5,dim,1); 137 | end 138 | if ~is_ff_l 139 | rl=repmat(x,1,Nl)-l; 140 | rl=rl./repmat(sum(rl.^2,1).^0.5,dim,1); 141 | end 142 | 143 | % single scattering rotation amplitude 144 | if ~(is_ff_v && is_ff_l) 145 | if sct_type>1 146 | for j=1:Nl 147 | af_ang_vl(:,j)=evalampfunc_general(rl(:,j)'*rv,sct_type,ampfunc,dim); 148 | end 149 | else 150 | af_ang_vl=evalampfunc_general(0,sct_type,ampfunc,dim); 151 | end 152 | end 153 | 154 | % First scattering direction 155 | % w - sampled direction. 156 | % w0p - probability of the sampled direction, needed to compute inportance sampling integral correctly. 157 | if ~exist('ampfunc0','var') 158 | w=randn(dim,1); w=w/norm(w); 159 | w0p=1/sqrt(2^(dim-1)*pi); 160 | else 161 | w=smpampfunc_general(meanl, sct_type,ampfunc0); 162 | w0p=(evalampfunc_general(meanl'*w,sct_type,ampfunc0,dim)); 163 | end 164 | 165 | % rotation due to first scattering in multiple scattering case (s 166 | % function in article). 167 | af_l=evalampfunc_general((w'*rl),sct_type,ampfunc,dim)./w0p; 168 | 169 | % complex transmission (xi function in article) and attenuation term 170 | % in multiple scattering (tau function in article) between first scattering 171 | % particle and the light source 172 | e_l0=evalphaseatt(x,l,is_ff_l,sigt,lambda,box_min,box_max); 173 | 174 | % complex volumetric throughput (ni function in article) of first 175 | % scattering event to be used with paths of length >1 (the multiple scattering 176 | % case) 177 | e_l0_ms=sum(e_l0.*af_l.*Wl); 178 | 179 | % complex volumetric throughput connecting first scattering particle 180 | % and the sensors 181 | e_v0=evalphaseatt(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max); 182 | 183 | % in case of coherent backscattering, calculate also the complex 184 | % volumetric throughput where the path begins from the view to the 185 | % first scatter 186 | if doCBS 187 | af_v=evalampfunc_general((-w'*rv),sct_type,ampfunc,dim)./w0p; 188 | e_v0_ms=e_v0.*af_v; 189 | end 190 | 191 | % number of scattering events 192 | pL=0; 193 | 194 | % intensity loss due to albedo 195 | weight=albedo; 196 | 197 | % begin paths sampling loop 198 | while 1 199 | 200 | pL=pL+1; 201 | 202 | % calculate the complex volumetric throughput for the last 203 | % scattering event in case of multiple scattering 204 | if (pL>1) 205 | e_v=evalphaseatt(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max); 206 | af_v=evalampfunc_general((ow'*rv),sct_type,ampfunc,dim); 207 | e_v_ms=e_v.*af_v; 208 | if doCBS 209 | e_l=evalphaseatt(x,l,is_ff_l,sigt,lambda,box_min,box_max); 210 | af_l=evalampfunc_general((-ow'*rl),sct_type,ampfunc,dim); 211 | %e_l_ms=e_l.*af_l; 212 | e_l_ms=sum(e_l.*af_l.*Wl); 213 | 214 | end 215 | end 216 | 217 | % Update field with next-event estimation 218 | if (pL==1) 219 | %tpath=sum(af_ang_vl.*(e_v0(:)*(e_l0(:).*Wl(:)).'),2); 220 | 221 | tpath= e_v0(:).*sum(af_ang_vl*(e_l0(:).*Wl(:)),2); 222 | else 223 | tpath=(e_v_ms(:)*conj(e_l0_ms(:))'); 224 | if doCBS 225 | tpath=1/sqrt(2)*(tpath+(e_v0_ms(:)*conj(e_l_ms(:))')); 226 | end 227 | end 228 | 229 | % weight path 230 | tpath=sqrt(weight./px)*tpath; 231 | % sample random phase for path 232 | tpath=tpath*exp(2*pi*1i*rand); 233 | %add path to field 234 | u=u+tpath; 235 | 236 | % advance to the next scattering event 237 | d=-log(-rand+1)/(sigt); 238 | x=x+d*w; 239 | 240 | % move to the next particle if the next scattering event is outside 241 | % the box 242 | if(max(x>box_max) || max(xalbedo 250 | break 251 | end 252 | else 253 | weight=weight*albedo; 254 | end 255 | 256 | % Sample new scatteing direction 257 | ow=w; 258 | w=smpampfunc_general(ow, sct_type,ampfunc); 259 | 260 | end 261 | 262 | end 263 | 264 | %% Normalization 265 | V=prod(box_w); 266 | u=u*sqrt(1/maxItr*V*sigt); 267 | 268 | -------------------------------------------------------------------------------- /code/MCsampleFourier.m: -------------------------------------------------------------------------------- 1 | function [u]=MCsample( sigt, albedo, box_min,box_max, l, v_max,v_stp,maxItr,lambda,smpFlg,sct_type,ampfunc,ampfunc0,lmean0) 2 | % is_ff_l: (binary) illumination in far field. 3 | % is_ff_v: (binary) viewing in far field 4 | % l: illumination direction 3xNl or 2xNl or 1xNl(this case is interperated 5 | % as angles and converted to 6 | % 2D vectors) 7 | % if in far field this are assumed to be unit norm vector. In near field 8 | % sensor points 9 | % v: viewing directions 1xNv or 2xNv or 3xNv, directions or points 10 | % sct_type=1 isotropic sct_type=2 parametric amplitude function provided 11 | % sct_type=3 HG, amp_func= g param 12 | % box_min, box_max: 2D or 3D vectors lower and upper bounds on box 13 | 14 | Nl=size(l,2); 15 | 16 | 17 | dim=size(box_min,1); 18 | 19 | if size(l,1)==1 20 | l=[sin(l); cos(l)]; 21 | end 22 | 23 | fv_max=1/v_stp*lambda; 24 | fv_stp=1/v_max/4*lambda; 25 | fv_max=box_max(1); 26 | fv_grid=[0:fv_stp:fv_max]; 27 | fv_grid=[-fv_grid(end:-1:2),fv_grid]; 28 | [fv_x,fv_y]=meshgrid(fv_grid); 29 | 30 | 31 | 32 | 33 | Nv0=length(fv_grid); 34 | Nv=Nv0^2; 35 | fu=zeros( Nv0,Nv0,Nl); 36 | v0=[0;0;1]; 37 | %u=zeros(Nv,Nl); 38 | 39 | if ~exist('lmean0','var') 40 | unmeanl=mean(l,2); 41 | else 42 | %lmean0 43 | unmeanl=lmean0; 44 | end 45 | meanl=unmeanl/norm(unmeanl); 46 | box_w=box_max-box_min; 47 | 48 | 49 | 50 | for j=1:Nl 51 | af_ang_vl(1,j)=evalampfunc_general(l(:,j)'*v0,sct_type,ampfunc,dim); 52 | end 53 | 54 | 55 | 56 | for itr=1:maxItr 57 | %itr/maxItr 58 | 59 | switch smpFlg 60 | case 1 61 | x=rand(dim,1).*(box_w)+box_min; px=1; 62 | 63 | case 2 64 | [x,px]=expSmpX(box_min,box_max,unmeanl,sigt); 65 | 66 | end 67 | %x(1:2)=0; 68 | %x1L(:,itr)=x; 69 | 70 | 71 | if ~exist('ampfunc0','var') 72 | w=randn(dim,1); w=w/norm(w); 73 | w0p=1/sqrt(2^(dim-1)*pi); 74 | else 75 | 76 | w=smpampfunc_general(meanl, sct_type,ampfunc0); 77 | w0p=(evalampfunc_general(meanl'*w,sct_type,ampfunc0,dim)); 78 | end 79 | 80 | 81 | 82 | 83 | 84 | af_l=evalampfunc_general((w'*l),sct_type,ampfunc,dim)./w0p; 85 | e_l0=evalphaseatt(x,l,1,sigt,lambda,box_min,box_max); 86 | e_l0_ms=e_l0.*af_l; 87 | 88 | 89 | 90 | e_v0=evalphaseatt(x,-v0,1,sigt,lambda,box_min,box_max); 91 | 92 | 93 | 94 | 95 | 96 | 97 | pL=0; 98 | weight=albedo; 99 | while 1 100 | 101 | pL=pL+1; 102 | 103 | if (pL>1) 104 | 105 | e_v=evalphaseatt(x,-v0,1,sigt,lambda,box_min,box_max); 106 | af_v=evalampfunc_general((ow'*v0),sct_type,ampfunc,dim); 107 | e_v_ms=e_v.*af_v; 108 | 109 | 110 | end 111 | if (pL==1) 112 | 113 | tpath=af_ang_vl.*(e_v0(:)*conj(e_l0(:))'); 114 | 115 | 116 | else 117 | tpath=(e_v_ms(:)*conj(e_l0_ms(:))'); 118 | 119 | 120 | 121 | end 122 | tpath=sqrt(weight./px)*tpath; 123 | tpath=tpath*exp(2*pi*i*rand); 124 | %u=u+tpath; 125 | 126 | ind1=round((x(1)+fv_max)/fv_stp)+1; 127 | ind2=round((x(2)+fv_max)/fv_stp)+1; 128 | if (ind1>0)&(ind1<=Nv0)&(ind2>0)&(ind2<=Nv0) 129 | fu(ind2,ind1,:)=fu(ind2,ind1,:)+reshape(tpath,1,1,Nl); 130 | end 131 | 132 | 133 | 134 | 135 | d=-log(-rand+1)/(sigt); 136 | x=x+d*w; 137 | 138 | if(max(x>box_max)|max(xalbedo 144 | break 145 | end 146 | else 147 | weight=weight*albedo; 148 | end 149 | ow=w; 150 | w= smpampfunc_general(ow, sct_type,ampfunc); 151 | 152 | end 153 | 154 | end 155 | 156 | for j=1:Nl 157 | u(:,:,j)=fft2(fu(:,:,j)); 158 | end 159 | V=prod(box_w); 160 | u=u*sqrt(1/maxItr*V*sigt); 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /code/MCsampleHetro.m: -------------------------------------------------------------------------------- 1 | function [u,corrM]=MCsampleHetro( sigt, albedo, box_min,box_max, box_bin,l, v,is_ff_l,is_ff_v,maxItr,lambda,doCBS,smpFlg,sct_type,ampfunc,ampfunc0,lmean0,dbgpair) 2 | % is_ff_l: (binary) illumination in far field. 3 | % is_ff_v: (binary) viewing in far field 4 | % l: illumination direction 3xNl or 2xNl or 1xNl(this case is interperated 5 | % as angles and converted to 6 | % 2D vectors) 7 | % if in far field this are assumed to be unit norm vector. In near field 8 | % sensor points 9 | % v: viewing directions 1xNv or 2xNv or 3xNv, directions or points 10 | % sct_type=1 isotropic sct_type=2 parametric amplitude function provided 11 | % sct_type=3 HG, amp_func= g param 12 | % box_min, box_max: 2D or 3D vectors lower and upper bounds on box 13 | 14 | Nl=size(l,2); 15 | Nv=size(v,2); 16 | 17 | dim=size(box_min,1); 18 | 19 | if size(l,1)==1 20 | l=[sin(l); cos(l)]; 21 | end 22 | if size(v,1)==1 23 | v=[sin(v); cos(v)]; 24 | end 25 | if (length(albedo)==1) 26 | albedo=albedo*ones(size(sigt)); 27 | end 28 | if exist('dbgpair','var') 29 | corrM=zeros(1,size(dbgpair,2)); 30 | end 31 | 32 | 33 | u=zeros(Nv,Nl); 34 | 35 | if ~exist('lmean0','var') 36 | unmeanl=mean(l,2); 37 | else 38 | %lmean0 39 | unmeanl=lmean0; 40 | end 41 | meanl=unmeanl/norm(unmeanl); 42 | box_w=box_max-box_min; 43 | 44 | if (is_ff_v*is_ff_l) 45 | for j=1:Nl 46 | af_ang_vl(:,j)=evalampfunc_general(l(:,j)'*v,sct_type,ampfunc,dim); 47 | end 48 | end 49 | 50 | if is_ff_v 51 | rv=v; 52 | end 53 | if is_ff_l 54 | rl=l; 55 | end 56 | ff_sign=-2*(is_ff_v)+1; 57 | 58 | bin_prob=sigt(:)'/sum(sigt(:)); 59 | inv_bin_prob=invCDFvec(cumsum(bin_prob),length(sigt(:))*100); 60 | 61 | V=sum(sigt(:))*prod(box_bin); 62 | 63 | if (dim==2) 64 | %[gz,gx]=ndgrid([box_min(2):box_bin(2):box_max(2)],[box_min(1):box_bin(1):box_max(1)] ); 65 | [gx,gz]=ndgrid([box_min(1):box_bin(1):box_max(1)],[box_min(2):box_bin(2):box_max(2)] ); 66 | 67 | gx_min=gx(1:end-1,1:end-1); 68 | gz_min=gz(1:end-1,1:end-1); 69 | 70 | bin_min=[gx_min(:)';gz_min(:)']; 71 | bin_max=bin_min+box_bin; 72 | else 73 | [gx,gy,gz]=ndgrid([box_min(1):box_bin(1):box_max(1)],[box_min(2):box_bin(2):box_max(2)], [box_min(3):box_bin(3):box_max(3)] ); 74 | gx_min=gx(1:end-1,1:end-1,1:end-1); 75 | gy_min=gy(1:end-1,1:end-1,1:end-1); 76 | gz_min=gz(1:end-1,1:end-1,1:end-1); 77 | 78 | bin_min=[gx_min(:)';gy_min(:)';gz_min(:)']; 79 | bin_max=bin_min+box_bin; 80 | end 81 | 82 | %x1L=zeros(dim,maxItr); 83 | 84 | 85 | for itr=1:maxItr 86 | %itr/maxItr 87 | 88 | switch smpFlg 89 | case 1 90 | 91 | bin_ind=smpicdf(inv_bin_prob); 92 | x=rand(dim,1).*(box_bin)+bin_min(:,bin_ind); px=1/V; 93 | 94 | case 2 95 | %error('not implemented yet') 96 | 97 | [x,px]=expSmpXHetro(box_min,box_max,box_bin,meanl,sigt,[]); 98 | 99 | end 100 | %x=0.5*(box_min+box_max) 101 | if(max(x>box_max)|max(x1) 160 | e_v=evalphaseattHetro(x,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max,box_bin); 161 | 162 | af_v=evalampfunc_general((ow'*rv),sct_type,ampfunc,dim); 163 | e_v_ms=e_v.*af_v; 164 | if doCBS 165 | e_l=evalphaseattHetro(x,l,is_ff_l,sigt,lambda,box_min,box_max,box_bin); 166 | 167 | af_l=evalampfunc_general((-ow'*rl),sct_type,ampfunc,dim); 168 | e_l_ms=e_l.*af_l; 169 | 170 | end 171 | 172 | end 173 | if (pL==1) 174 | 175 | tpath=af_ang_vl.*(e_v0(:)*conj(e_l0(:))'); 176 | 177 | 178 | else 179 | tpath=(e_v_ms(:)*conj(e_l0_ms(:))'); 180 | if doCBS 181 | tpath=1/sqrt(2)*(tpath+(e_v0_ms(:)*conj(e_l_ms(:))')); 182 | end 183 | 184 | 185 | end 186 | tpath=sqrt(weight./px)*tpath; 187 | tpath=tpath*exp(2*pi*i*rand); 188 | u=u+tpath; 189 | 190 | if exist('dbgpair','var') 191 | for j=1:size(dbgpair,2) 192 | corrM(j)=corrM(j)+tpath(dbgpair(1,j),dbgpair(2,j))*conj(tpath(dbgpair(3,j),dbgpair(4,j))); 193 | end 194 | end 195 | 196 | d=smpWoodcock(x,box_min,box_max,box_bin,sigt,w); 197 | %d=-log(-rand+1)/(sigt); 198 | x=x+d*w; 199 | 200 | if(max(x>box_max)|max(xalbedo(findBin(x,box_min,box_max,box_bin)) 206 | break 207 | end 208 | else 209 | weight=weight*albedo(findBin(x,box_min,box_max,box_bin)); 210 | end 211 | ow=w; 212 | w= smpampfunc_general(ow, sct_type,ampfunc); 213 | 214 | end 215 | 216 | end 217 | 218 | 219 | %V=prod(box_w); 220 | 221 | 222 | u=u*sqrt(1/maxItr); 223 | 224 | 225 | 226 | if exist('dbgpair','var') 227 | corrM=corrM*(1/maxItr*sigt); 228 | end -------------------------------------------------------------------------------- /code/coreFunctions/cubeDist.m: -------------------------------------------------------------------------------- 1 | function [d,xd] = cubeDist(x,vmin,vmax,v) 2 | % distance from v to x inside the box 3 | 4 | thr=0.1^7; 5 | bd = inf(size(v)); 6 | for j=1:size(vmin,1) 7 | bd(j,:) = (x(j)-vmin(j))./max(abs(v(j,:)),thr).*(v(j,:)<=0) + ... 8 | (-x(j)+vmax(j))./max(abs(v(j,:)),thr).*(v(j,:)>0); 9 | end 10 | 11 | d=min(bd); 12 | 13 | if nargout>1 14 | ep = 0.1^4*max(abs(vmax-vmin)); 15 | xd = x+(d+ep)*v; 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /code/coreFunctions/cubeProj.m: -------------------------------------------------------------------------------- 1 | function [xd]=cubeProj(x,vmin,vmax,v) 2 | 3 | thr=0.1^7; 4 | bd = inf(size(v)); 5 | for j=1:size(vmin,1) 6 | bd(j,:)=(x(j)-vmax(j))./max(abs(v(j,:)),thr).*(v(j,:)<=0)+(-x(j)+vmin(j))./max(abs(v(j,:)),thr).*(v(j,:)>0); 7 | end 8 | 9 | d = max(bd); 10 | 11 | if d>=0 12 | ep=0.1^4*max(abs(vmax-vmin)); 13 | 14 | xd=x+(d+ep)*v; 15 | else 16 | xd=d; 17 | end 18 | 19 | end -------------------------------------------------------------------------------- /code/coreFunctions/evalampfunc_amplitude.m: -------------------------------------------------------------------------------- 1 | function p = evalampfunc_amplitude(ampfunc,angs,dim) 2 | % provided amplitude function rotation amplitude 3 | N = length(ampfunc.evalAmp); 4 | 5 | if(dim == 2) 6 | p = ampfunc.evalAmp(round(angs*(N-1)/(2*pi))+1); 7 | else 8 | p = ampfunc.evalAmp(round(angs*(N-1)/(pi))+1); 9 | end 10 | end -------------------------------------------------------------------------------- /code/coreFunctions/evalampfunc_general.m: -------------------------------------------------------------------------------- 1 | function af_v = evalampfunc_general(cosang, sct_type,ampfunc,dim) 2 | % Pre-calculate single scattering rotation amplitude 3 | Nv=length(cosang); 4 | 5 | switch sct_type 6 | case 1 7 | % isotropic scattering 8 | af_v = ones(1,Nv)/sqrt(2^(dim-1)*pi); 9 | 10 | case 2 11 | % provided amplitude function 12 | ang = acos(cosang); 13 | af_v = evalampfunc_amplitude(ampfunc,ang,dim); 14 | 15 | case 3 16 | % HG scattering 17 | af_v = sqrt(evaluateHG(cosang, ampfunc, 1, dim)); 18 | end 19 | end -------------------------------------------------------------------------------- /code/coreFunctions/evalphaseatt.m: -------------------------------------------------------------------------------- 1 | function e = evalphaseatt(x,v,is_ff,sigt,lambda,box_min,box_max) 2 | % complex transmission and attenuation term in multiple scattering 3 | 4 | Nv = size(v,2); 5 | dim = size(v,1); 6 | if (is_ff) 7 | pv = x'*v; 8 | rv = ones(1,Nv); 9 | bdv = cubeDist(x,box_min,box_max,-v); 10 | else 11 | d = repmat(x,1,Nv)-v; 12 | nd = sum(d.^2,1).^0.5; 13 | v = d./repmat(nd,dim,1); 14 | pv = nd; 15 | rv = 1./(nd+0.01*lambda).^((dim-1)/2); 16 | bdv = min(cubeDist(x,box_min,box_max,-v),nd); 17 | end 18 | 19 | e = exp(1i*pi*2/lambda*pv-sigt/2*bdv).*rv; 20 | 21 | end -------------------------------------------------------------------------------- /code/coreFunctions/evalphaseattHetro.m: -------------------------------------------------------------------------------- 1 | function [e,nx]=evalphaseattHetro(x,v,is_ff,sigt,lambda,box_min,box_max,box_bin) 2 | 3 | 4 | 5 | Nv=size(v,2); 6 | dim=size(v,1); 7 | 8 | 9 | 10 | 11 | 12 | if (is_ff) 13 | pv=x'*v; 14 | rv=ones(1,Nv); 15 | % bdv=cubeDist(x,box_min,box_max,-v); 16 | nd=10^12*ones(1,Nv); 17 | else 18 | d=repmat(x,1,Nv)-v; 19 | nd=sum(d.^2,1).^0.5; 20 | v=d./repmat(nd,dim,1); 21 | pv=nd; 22 | rv=1./(nd+0.01*lambda).^((dim-1)/2); 23 | %bdv=min(cubeDist(x,box_min,box_max,-v),nd); 24 | end 25 | 26 | 27 | bdv=zeros(1,Nv); 28 | wbdv=zeros(1,Nv); 29 | for j=1:Nv 30 | 31 | nx=x; 32 | 33 | while 1 34 | [bin_ind,bin_min,bin_max]=findBin(nx,box_min,box_max,box_bin); 35 | [d,nx]=cubeDist(nx,bin_min,bin_max,-v(:,j)); 36 | bdv(j)=bdv(j)+d; 37 | wbdv(j)=wbdv(j)+d*sigt(bin_ind); 38 | if (bdv(j)>=nd(j)) 39 | md=bdv(j)-nd(j); 40 | bdv(j)=nd(j); 41 | wbdv(j)=wbdv(j)-md*sigt(bin_ind); 42 | break 43 | end 44 | 45 | if(max(nx>box_max)|max(nx0)+(-d+box_max(end)).*(lmean(end)<=0); 11 | 12 | px = exp(-sigs*d)/(rmax)*sigs*dmax; 13 | end -------------------------------------------------------------------------------- /code/coreFunctions/expSmpXHetro.m: -------------------------------------------------------------------------------- 1 | function [x,px]=expSmpXHetro(box_min,box_max,box_bin,lmean,sigt,lrad) 2 | dim=size(lmean,1); x=zeros(dim,1); 3 | 4 | if isempty(lrad) 5 | lrad=sqrt(sum((box_max-box_min).^2)); 6 | end 7 | 8 | u=null(lmean'); 9 | 10 | x=u*((rand(dim-1,1)-0.5)*lrad)-lmean*max(abs([box_max;box_min]))*dim; 11 | 12 | x=cubeProj(x,box_min,box_max,lmean); 13 | 14 | if(max(x>box_max)||max(xbox_max)||max(x1 14 | bin_min=box_min+box_bin.*(ii-1); 15 | bin_max=bin_min+box_bin; 16 | 17 | 18 | end -------------------------------------------------------------------------------- /code/coreFunctions/invCDF.m: -------------------------------------------------------------------------------- 1 | function icdf=invCDF(cdf,dim) 2 | % inverse of cumulative distribution function 3 | N = length(cdf); 4 | stp = 1/(N-1); 5 | grid = 0:stp:1; 6 | icdf=zeros(size(cdf)); 7 | for j=1:N 8 | [~,icdf(j)] = min(abs(cdf - grid(j))); 9 | end 10 | 11 | if(dim == 2) 12 | icdf = icdf/N*2*pi; 13 | end 14 | 15 | if(dim == 3) 16 | icdf = icdf/N*pi; 17 | end 18 | 19 | end -------------------------------------------------------------------------------- /code/coreFunctions/invCDFvec.m: -------------------------------------------------------------------------------- 1 | function icdf=invCDFvec(cdf,N) 2 | 3 | if ~exist('N','var') 4 | N=length(cdf); 5 | end 6 | 7 | icdf =cumsum(hist(cdf,N)); 8 | end -------------------------------------------------------------------------------- /code/coreFunctions/ismonotonic.m: -------------------------------------------------------------------------------- 1 | function monotonic = ismonotonic(x, strict, direction, dim) 2 | % ISMONOTONIC(X) returns a boolean value indicating whether or not a vector is monotonic. 3 | % By default, ISMONOTONIC returns true for non-strictly monotonic vectors, 4 | % and both monotonic increasing and monotonic decreasing vectors. For 5 | % matrices and N-D arrays, ISMONOTONIC returns a value for each column in 6 | % X. 7 | % 8 | % ISMONOTONIC(X, 1) works as above, but only returns true when X is 9 | % strictly monotonically increasing, or strictly monotonically decreasing. 10 | % 11 | % ISMONOTONIC(X, 0) works as ISMONOTONIC(X). 12 | % 13 | % ISMONOTONIC(X, [], 'INCREASING') works as above, but returns true only 14 | % when X is monotonically increasing. 15 | % 16 | % ISMONOTONIC(X, [], 'DECREASING') works as above, but returns true only 17 | % when X is monotonically decreasing. 18 | % 19 | % ISMONOTONIC(X, [], 'EITHER') works as ISMONOTONIC(X, []). 20 | % 21 | % ISMONOTONIC(X, [], [], DIM) works as above, but along dimension DIM. 22 | % 23 | % NOTE: Third input variable is case insensitive, and partial matching is 24 | % used, so 'd' would be recognised as 'DECREASING' etc.. 25 | % 26 | % EXAMPLE: 27 | % x = [1:4; 6:-2:2 3] 28 | % ismonotonic(x) 29 | % ismonotonic(x, [], 'i') 30 | % ismonotonic(x, [], [], 2) 31 | % 32 | % x = 33 | % 1 2 3 4 34 | % 6 4 2 3 35 | % ans = 36 | % 1 1 1 1 37 | % ans = 38 | % 1 1 0 0 39 | % ans = 40 | % 1 41 | % 0 42 | % 43 | % SEE ALSO: is* 44 | % 45 | % $ Author: Richie Cotton $ $ Date: 2010/01/20 $ $ Version: 1.2 $ 46 | %% Basic error checking & default setup 47 | if ~isreal(x) || ~isnumeric(x) 48 | warning('ismonotonic:badXValue', ... 49 | 'The array to be tested is not real and numeric. Unexpected behaviour may occur.'); 50 | end 51 | if nargin < 2 || isempty(strict) 52 | strict = false; 53 | end 54 | if nargin < 3 || isempty(direction) 55 | direction = 'either'; 56 | end 57 | % Accept partial matching for direction 58 | lendir = length(direction); 59 | if strncmpi(direction, 'increasing', lendir) 60 | testIncreasing = true; 61 | testDecreasing = false; 62 | elseif strncmpi(direction, 'decreasing', lendir) 63 | testIncreasing = false; 64 | testDecreasing = true; 65 | elseif strncmpi(direction, 'either', lendir) 66 | testIncreasing = true; 67 | testDecreasing = true; 68 | else 69 | warning('ismonotonic:badDirection', ... 70 | 'The string entered for direction has not been recognised, reverting to ''either''.'); 71 | testIncreasing = true; 72 | testDecreasing = true; 73 | end 74 | if nargin < 4 || isempty(dim) 75 | dim = find(size(x) ~= 1, 1); 76 | if isempty(dim) 77 | dim = 1; 78 | end 79 | end 80 | %% Test for monotonic increasing 81 | if testIncreasing 82 | if strict 83 | comparison = @gt; 84 | else 85 | comparison = @ge; 86 | end 87 | monotonicAscending = all(comparison(diff(x, [], dim), 0), dim); 88 | else 89 | monotonicAscending = false; 90 | end 91 | %% Test for monotonic decreasing 92 | if testDecreasing 93 | if strict 94 | fhComparison = @lt; 95 | else 96 | fhComparison = @le; 97 | end 98 | monotonicDescending = all(fhComparison(diff(x, [], dim), 0), dim); 99 | else 100 | monotonicDescending = false; 101 | end 102 | monotonic = monotonicAscending | monotonicDescending; -------------------------------------------------------------------------------- /code/coreFunctions/rotateBytheta.m: -------------------------------------------------------------------------------- 1 | function w=rotateBytheta(ow,costheta) 2 | % get new vector direction by given theta direction. phi direction is 3 | % sampled uniformly 4 | sintheta = real(sqrt(1-real(costheta)^2)); 5 | dim = size(ow,1); 6 | if(dim == 2) 7 | sintheta = ((rand>0.5)*2-1)*sintheta; 8 | w = [costheta,sintheta;-sintheta,costheta]*ow; 9 | end 10 | 11 | if(dim == 3) 12 | phi = pi*2*rand; 13 | 14 | sinphi = sin(phi); 15 | cosphi = cos(phi); 16 | w = zeros(3,1); 17 | if (abs(ow(3)) > 0.999999999) 18 | w(1) = sintheta * cosphi; 19 | w(2) = sintheta * sinphi; 20 | w(3) = costheta * ow(3) / abs(ow(3)); 21 | else 22 | temp = sqrt(1 - ow(3)^2); 23 | w(1) = sintheta*(ow(1)*ow(3)*cosphi - ow(2)*sinphi)/temp + ow(1)*costheta; 24 | w(2) = sintheta*(ow(2)*ow(3)*cosphi + ow(1)*sinphi)/temp + ow(2)*costheta; 25 | w(3) = -sintheta*cosphi*temp+ow(3)*costheta; 26 | end 27 | 28 | end 29 | end -------------------------------------------------------------------------------- /code/coreFunctions/sampleHG.m: -------------------------------------------------------------------------------- 1 | function costheta=sampleHG(g, dim) 2 | % sample direction by HG distribution 3 | if(abs(g) < 0.001) 4 | costheta = 2*rand-1; 5 | return 6 | end 7 | 8 | if(dim == 3) 9 | costheta = (1-g*g)/(1-g+2*g*rand); 10 | costheta = (1/(2*g)) * ((1+g*g)-costheta*costheta); %Not calculating theta to save time 11 | end 12 | if(dim == 2) 13 | %for 2D http://www.eugenedeon.com/wp-content/uploads/2016/09/hitchhikers_v0.1.3.pdf 14 | %chapter 2.5, HG in flatland 15 | theta_q = 2*atan( (1-g)/(1+g) * tan( pi/2*(1-2*rand) ) ); 16 | costheta = cos(theta_q); 17 | end 18 | 19 | end -------------------------------------------------------------------------------- /code/coreFunctions/smpWoodcock.m: -------------------------------------------------------------------------------- 1 | function d=smpWoodcock(x,box_min,box_max,box_bin,sigt,v) 2 | sigt_max=max(sigt(:)); 3 | 4 | d=0; 5 | while 1 6 | d=d-log(1-rand)/sigt_max; 7 | nx=x+d*v; 8 | if(max(nx>box_max)||max(nx1 19 | w = rotateBytheta(ow,cosa); 20 | end 21 | 22 | end -------------------------------------------------------------------------------- /code/coreFunctions/smpicdf.m: -------------------------------------------------------------------------------- 1 | function x=smpicdf(icdf) 2 | 3 | N=length(icdf); 4 | 5 | a=rand; 6 | i=ceil(a*N); 7 | x=icdf(i); 8 | 9 | end -------------------------------------------------------------------------------- /code/evalMeanUnifCtr.m: -------------------------------------------------------------------------------- 1 | function [meanU]=evalMeanUnifCtr(box_min,box_max,l,v,sigt,lambda) 2 | 3 | %This is a mean calculation that is valid in the far field only, for 4 | %homogenious case, and assuming the illumination and viewing directions are 5 | %at a small angle with the normail of the target sample. 6 | 7 | box_w=box_max-box_min; 8 | 9 | dim=size(box_min,1); 10 | 11 | Nl=size(l,2); 12 | Nv=size(v,2); 13 | meanU=zeros(Nv,Nl); 14 | for j=1:Nl 15 | w=v(1:dim-1,:)-l(1:dim-1,j); 16 | w_e=v(dim,:)-l(dim,j); 17 | jj=find(abs(w_e)<0.7); 18 | aw=asin(w(:,jj)); 19 | e=1; 20 | for j2=1:dim-1 21 | e=e.* sinc(aw(j2,:).*box_w(j2)); 22 | end 23 | e=e*prod(box_w(1:dim-1))*exp(-sigt/2*box_w(end)); 24 | meanU(jj(:),j)=e(:); 25 | end -------------------------------------------------------------------------------- /code/refocus.m: -------------------------------------------------------------------------------- 1 | function rU=refocus(u,v,l,box_min,box_max,box_stp,lambda) 2 | %l is assumed to be a 3x1 ellements vector, v a 3xN (that is only single 3 | %illumination direction) 4 | dim=size(box_min,1); 5 | 6 | if (dim==2) 7 | [gx,gz]=ndgrid([box_min(1):box_stp(1):box_max(1)],[box_min(2):box_stp(2):box_max(2)] ); 8 | 9 | p_grid=[gx(:)';gz(:)']; 10 | 11 | dimv=size(gx); 12 | 13 | else 14 | [gx,gy,gz]=ndgrid([box_min(1):box_stp(1):box_max(1)],[box_min(2):box_stp(2):box_max(2)], [box_min(3):box_stp(3):box_max(3)] ); 15 | 16 | p_grid=[gx(:)';gy(:)';gz(:)']; 17 | dimv=size(gx); 18 | end 19 | 20 | Ns=50; 21 | 22 | N=size(p_grid,2); 23 | 24 | rU=zeros(1,N); 25 | 26 | for j=1:Ns:N 27 | %j/N 28 | jj=[j+1:min(j+Ns,N)]; 29 | e=exp(-2*pi*i/lambda*(v'*p_grid(:,jj))); 30 | el=exp(2*pi*i/lambda*(l'*p_grid(:,jj))); 31 | rU(jj)=(u(:)'*e).*el; 32 | end 33 | 34 | rU=reshape(rU,dimv); 35 | -------------------------------------------------------------------------------- /code/test3DFourierSmpQuad.m: -------------------------------------------------------------------------------- 1 | 2 | lambda=1; 3 | box_min=[-50; -50; 0]; 4 | box_max=[ 50; 50; 100]; 5 | box_min=[-4000; -4000; 0]; 6 | box_max=[ 4000; 4000; 100]; 7 | box_min=[-1000;-1000;0]; box_max=[1000;1000;30];%3000 8 | 9 | 10 | 11 | sigt=1/2000; 12 | sigt=1/25; 13 | %theta_l=deg2rad([-35:5:35]); 14 | theta_l=deg2rad([-20:20:20]); 15 | 16 | theta_max=deg2rad(40); 17 | theta_stp=deg2rad(0.2); 18 | theta_max=0.5; 19 | theta_max=0.02; 20 | theta_stp=theta_max/200; 21 | theta_l=[-theta_max/2:theta_stp*50:theta_max/2]; 22 | 23 | 24 | %IMPORTANT: this is a uniform grid of sin(theta) not of theta 25 | %This is important to have a uniform grid for the Fourier transform 26 | theta_v=[-theta_max:theta_stp:theta_max]; 27 | 28 | Nl0=length(theta_l); 29 | Nv0=length(theta_v); 30 | Nv=Nv0^2; 31 | Nl=Nl0^2; 32 | 33 | 34 | 35 | [vx,vy]=ndgrid(theta_v,theta_v); 36 | v=-[vx(:)';vy(:)'; sqrt(1-vx(:).^2-vy(:).^2)']; %Note again: we assume the grid is a uniform grid of sin(theta) so no sin applyied 37 | 38 | 39 | [lx,ly]=ndgrid(theta_l,theta_l); 40 | l=[lx(:)';ly(:)'; sqrt(1-lx(:).^2-ly(:).^2)']; 41 | 42 | 43 | v(3,:)=-v(3,:); l(3,:)=-l(3,:); 44 | 45 | 46 | 47 | doCBS=1; smpFlg=1; 48 | maxItr=10^4*4; 49 | maxItr=10^3 50 | %maxItr=3; 51 | %maxItr=100; 52 | %maxItr=50; 53 | %maxItr=2; 54 | j=1 55 | 56 | rng(520) 57 | for j=1:1 58 | tic 59 | 60 | [uLf]=MCfieldFourierQuad( sigt, 1, box_min,box_max, l, theta_max,theta_stp,maxItr,lambda,doCBS,smpFlg,[],median(sign(v(3,:)))); 61 | 62 | toc 63 | end 64 | uLf=sum(uLf,4); 65 | 66 | rng(520) 67 | 68 | box_min=[-1007;-1007;0]; 69 | box_max=[ 1007; 1007;30]; 70 | 71 | 72 | for j=1:1 73 | tic 74 | uL(:,:,j)=MCfield( sigt, 1, box_min,box_max, l, v,1,1,maxItr,lambda,doCBS,smpFlg,1,0); 75 | toc 76 | end 77 | uL=sum(uL,3); 78 | figure, imshow(real(uLf(:,:,1)),[]) 79 | figure, imshow(real(reshape(uL(:,1),Nv0,Nv0)),[]) 80 | su=reshape(sum(uL,2),Nv0,Nv0); 81 | suf=sum(uLf,3); 82 | csuf=fftCorr(suf); 83 | csu=fftCorr(su); 84 | 85 | 86 | 87 | figure, imshow(abs(csu),[]) 88 | figure, imshow(abs(csuf),[]) 89 | 90 | 91 | csuf=fftCorr(uLf(:,:,13),uLf(:,:,15)); 92 | csu=fftCorr(reshape(uL(:,13),Nv0,Nv0),reshape(uL(:,15),Nv0,Nv0)); 93 | figure, imshow(abs(csu),[]) 94 | figure, imshow(abs(csuf),[]) 95 | csuf=fftCorr(uLf(:,:,13),uLf(:,:,1)); 96 | csu=fftCorr(reshape(uL(:,13),Nv0,Nv0),reshape(uL(:,1),Nv0,Nv0)); 97 | figure, imshow(abs(csu),[]) 98 | figure, imshow(abs(csuf),[]) 99 | 100 | 101 | return 102 | -------------------------------------------------------------------------------- /code/test3DFourierSmpQuadOnWave.m: -------------------------------------------------------------------------------- 1 | 2 | lambda=1; 3 | box_min=[-50; -50; 0]; 4 | box_max=[ 50; 50; 100]; 5 | box_min=[-4000; -4000; 0]; 6 | box_max=[ 4000; 4000; 100]; 7 | box_min=[-1000;-1000;0]; box_max=[1000;1000;30];%3000 8 | 9 | 10 | 11 | sigt=1/400; 12 | sigt=1/40000; 13 | sigt=1/2000; 14 | %sigt=1/50; 15 | %theta_l=deg2rad([-35:5:35]); 16 | theta_l=deg2rad([-20:20:20]); 17 | 18 | theta_max=deg2rad(40); 19 | theta_stp=deg2rad(0.2); 20 | theta_max=0.5; 21 | theta_max=0.02; 22 | theta_stp=theta_max/200; 23 | theta_l=[-theta_max:theta_stp*50:theta_max]; 24 | 25 | 26 | %IMPORTANT: this is a uniform grid of sin(theta) not of theta 27 | %This is important to have a uniform grid for the Fourier transform 28 | theta_v=[-theta_max:theta_stp:theta_max]; 29 | 30 | Nl0=length(theta_l); 31 | Nv0=length(theta_v); 32 | Nv=Nv0^2; 33 | Nl=Nl0^2; 34 | 35 | %Nx=(box_max(1)-box_min(1))/box_bin(1); 36 | %Nz=(box_max(2)-box_min(2))/box_bin(2); 37 | %Nxz=Nx*Nz; 38 | 39 | [vx,vy]=ndgrid(theta_v,theta_v); 40 | v=-[vx(:)';vy(:)'; sqrt(1-vx(:).^2-vy(:).^2)']; %Note again: we assume the grid is a uniform grid of sin(theta) so no sin applyied 41 | %v=[sin(vx(:))';sin(vy(:))';ones(1,Nv)]; 42 | %v=v./repmat(sum(v.^2,1).^0.5,3,1); 43 | vsign=-1; 44 | [lx,ly]=ndgrid(theta_l,theta_l); 45 | l=-[lx(:)';ly(:)'; sqrt(1-lx(:).^2-ly(:).^2)']; 46 | %[lx,ly]=ndgrid(theta_l,theta_l); 47 | %l=[sin(lx(:))';sin(ly(:))';ones(1,Nl)]; 48 | %l=l./repmat(sum(l.^2,1).^0.5,3,1); 49 | 50 | 51 | 52 | 53 | doCBS=1; smpFlg=1; 54 | maxItr=10^4*4; 55 | maxItr=10^3 56 | maxItr=3; 57 | %maxItr=100; 58 | maxItr=50; 59 | j=1 60 | 61 | rng(520) 62 | for j=1:1 63 | tic 64 | uLf(:,:,:,j)=MCfieldFourierQuad( sigt, 1, box_min,box_max, l, theta_max,theta_stp,maxItr,lambda,doCBS,smpFlg,[],vsign); 65 | 66 | 67 | 68 | toc 69 | end 70 | uLf=sum(uLf,4); 71 | %keyboard 72 | 73 | 74 | lW=rand(Nl,1).*exp(2*pi*i*rand(Nl,1)); 75 | %lW(:)=0; lW(1)=1; 76 | uLfwp=0; 77 | for j=1:Nl 78 | uLfwp=uLfwp+uLf(:,:,j)*lW(j); 79 | end 80 | rng(520) 81 | tic 82 | [uLfw]=MCfieldFourierQuadOnWave( sigt, 1, box_min,box_max, l, theta_max,theta_stp,maxItr,lambda,doCBS,smpFlg,[0;0;1],lW,vsign); 83 | toc 84 | 85 | max(max(abs(uLfw-uLfwp))) 86 | 87 | [meanU]=evalMeanUnifCtr(box_min,box_max,l,v,sigt,lambda); 88 | meanlW=reshape(meanU*lW(:),Nv0,Nv0); 89 | 90 | figure, imshow(real(uLfw),[]) 91 | figure, imshow(real(uLfw+meanlW),[]) 92 | 93 | 94 | 95 | return 96 | -------------------------------------------------------------------------------- /examples/buildFarFieldCovMatrix/farFieldCov.m: -------------------------------------------------------------------------------- 1 | %% Build far field covariance matrix 2 | 3 | % Build the target area 4 | boxTargetArea = boxArea( ... 5 | 1 , ... wavelength 6 | 10, ... MFP (O.D. = 2) 7 | [-10,10], ... z 8 | [-10,10] ... x 9 | ); 10 | 11 | % views config, define by angles 12 | viewsDirections = 0:1:359; 13 | views = farFieldSource(deg2rad(viewsDirections),0); 14 | 15 | % lights config, lighting in some directions 16 | lightsDirections = [0, 1, 4, 20]; 17 | lights = farFieldSource(deg2rad(lightsDirections),0); 18 | 19 | % scatter config 20 | % load measured amplitude (generated by mu-diff far field) 21 | load('scatteringAmplitude.mat', 'theta', 'farField') 22 | scatter = tabulatedAmplitudeScatter( ... 23 | theta, ... diirections 24 | farField ... measured amplitude 25 | ); 26 | 27 | % Show the scattering function 28 | figure 29 | polarplot(theta, abs(farField).^2); 30 | title('Scattering function of single particle') 31 | 32 | %% Sovle scmc with CBS 33 | tic 34 | CBSres = scmc(boxTargetArea,views,lights,scatter,1e3,'CBS',true,'parforIters',12); 35 | toc 36 | 37 | %% Sovle scmc without CBS 38 | tic 39 | NCBSres = scmc(boxTargetArea,views,lights,scatter,1e3,'CBS',false,'parforIters',12); 40 | toc 41 | 42 | %% Compare cov matrix 43 | f = figure; 44 | f.Position = [0,0,1200,700]; 45 | maxval = max(abs([CBSres.C(:);NCBSres.C(:)])); 46 | 47 | subplot(2,4,1); 48 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,1)),[0,maxval]); 49 | xlabel('view[deg]'); 50 | ylabel({'CBS','view[deg]'}); 51 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(1)),'\circ)']); 52 | 53 | subplot(2,4,2); 54 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,2)),[0,maxval]); 55 | xlabel('view[deg]'); 56 | ylabel('view[deg]'); 57 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(2)),'\circ)']); 58 | 59 | subplot(2,4,3); 60 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,3)),[0,maxval]); 61 | xlabel('view[deg]'); 62 | ylabel('view[deg]'); 63 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(3)),'\circ)']); 64 | 65 | subplot(2,4,4); 66 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,4)),[0,maxval]); 67 | xlabel('view[deg]'); 68 | ylabel('view[deg]'); 69 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(4)),'\circ)']); 70 | 71 | subplot(2,4,5); 72 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,1)),[0,maxval]); 73 | xlabel('view[deg]'); 74 | ylabel({'Without CBS','view[deg]'}); 75 | 76 | subplot(2,4,6); 77 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,2)),[0,maxval]); 78 | xlabel('view[deg]'); 79 | ylabel('view[deg]'); 80 | 81 | subplot(2,4,7); 82 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,3)),[0,maxval]); 83 | xlabel('view[deg]'); 84 | ylabel('view[deg]'); 85 | 86 | subplot(2,4,8); 87 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,4)),[0,maxval]); 88 | xlabel('view[deg]'); 89 | ylabel('view[deg]'); 90 | 91 | %% Compare diagonals 92 | figure 93 | 94 | hold on 95 | plot(viewsDirections,diag(abs(CBSres.C(:,:,1,1))), 'lineWidth', 2); 96 | plot(viewsDirections,diag(abs(NCBSres.C(:,:,1,1))), 'lineWidth', 2); 97 | 98 | xlabel('view[deg]'); 99 | ylabel('intensity'); 100 | 101 | legend('With CBS','Without CBS') -------------------------------------------------------------------------------- /examples/buildFarFieldCovMatrix/farFieldCov.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/buildFarFieldCovMatrix/farFieldCov.pdf -------------------------------------------------------------------------------- /examples/buildFarFieldCovMatrix/scatteringAmplitude.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/buildFarFieldCovMatrix/scatteringAmplitude.mat -------------------------------------------------------------------------------- /examples/buildNearFieldCovMatrix/nearFieldCov.m: -------------------------------------------------------------------------------- 1 | %% Build far field covariance matrix 2 | 3 | % Build the target area 4 | boxTargetArea = boxArea( ... 5 | 1 , ... wavelength 6 | 10, ... MFP (O.D. = 2) 7 | [-10,10], ... z 8 | [-10,10] ... x 9 | ); 10 | 11 | % views config, near field sensors, sensors located in a circle around the 12 | % target area 13 | viewsDirections = 0:1:359; 14 | sensorsRadius = 20; 15 | views = nearFieldSource(sensorsRadius, deg2rad(viewsDirections)); 16 | 17 | % lights config, lighting in some directions 18 | lightsDirections = [0, 1, 4, 20]; 19 | lights = farFieldSource(deg2rad(lightsDirections),0); 20 | 21 | % scatter config 22 | % use Henyey-Greenstein scattering function 23 | load('scatteringAmplitude.mat', 'theta', 'farField') 24 | scatter = HGScatter(-0.5); 25 | 26 | %% Sovle scmc with CBS 27 | tic 28 | CBSres = scmc(boxTargetArea,views,lights,scatter,1e3,'CBS',true,'parforIters',12); 29 | toc 30 | 31 | %% Sovle scmc without CBS 32 | tic 33 | NCBSres = scmc(boxTargetArea,views,lights,scatter,1e3,'CBS',false,'parforIters',12); 34 | toc 35 | 36 | %% Compare cov matrix 37 | f = figure; 38 | f.Position = [0,0,1200,700]; 39 | maxval = max(abs([CBSres.C(:);NCBSres.C(:)])); 40 | 41 | subplot(2,4,1); 42 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,1)),[0,maxval]); 43 | xlabel('view[deg]'); 44 | ylabel({'CBS','view[deg]'}); 45 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(1)),'\circ)']); 46 | 47 | subplot(2,4,2); 48 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,2)),[0,maxval]); 49 | xlabel('view[deg]'); 50 | ylabel('view[deg]'); 51 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(2)),'\circ)']); 52 | 53 | subplot(2,4,3); 54 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,3)),[0,maxval]); 55 | xlabel('view[deg]'); 56 | ylabel('view[deg]'); 57 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(3)),'\circ)']); 58 | 59 | subplot(2,4,4); 60 | imagesc(viewsDirections,viewsDirections,abs(CBSres.C(:,:,1,4)),[0,maxval]); 61 | xlabel('view[deg]'); 62 | ylabel('view[deg]'); 63 | title(['(',num2str(lightsDirections(1)),'\circ,',num2str(lightsDirections(4)),'\circ)']); 64 | 65 | subplot(2,4,5); 66 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,1)),[0,maxval]); 67 | xlabel('view[deg]'); 68 | ylabel({'Without CBS','view[deg]'}); 69 | 70 | subplot(2,4,6); 71 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,2)),[0,maxval]); 72 | xlabel('view[deg]'); 73 | ylabel('view[deg]'); 74 | 75 | subplot(2,4,7); 76 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,3)),[0,maxval]); 77 | xlabel('view[deg]'); 78 | ylabel('view[deg]'); 79 | 80 | subplot(2,4,8); 81 | imagesc(viewsDirections,viewsDirections,abs(NCBSres.C(:,:,1,4)),[0,maxval]); 82 | xlabel('view[deg]'); 83 | ylabel('view[deg]'); 84 | 85 | %% Compare diagonals 86 | figure 87 | 88 | hold on 89 | plot(viewsDirections,diag(abs(CBSres.C(:,:,1,1))), 'lineWidth', 2); 90 | plot(viewsDirections,diag(abs(NCBSres.C(:,:,1,1))), 'lineWidth', 2); 91 | 92 | xlabel('view[deg]'); 93 | ylabel('intensity'); 94 | 95 | legend('With CBS','Without CBS') -------------------------------------------------------------------------------- /examples/buildNearFieldCovMatrix/nearFieldCov.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/buildNearFieldCovMatrix/nearFieldCov.pdf -------------------------------------------------------------------------------- /examples/evaluateTabulatedScatterVsHG/evaluateTabulatedScatterVsHG.m: -------------------------------------------------------------------------------- 1 | %% Evaluate Tabulated Scattering vs HG 2 | % In this example, we will show how to build tabulated scatter in 2D and 3D 3 | % and compare the evaluated scattering in single scattering case 4 | 5 | % first build the target area for 2D and 3D 6 | % we make very tiny box, in order to demonstrate the pdf 7 | boxTargetArea2D = boxArea( ... 8 | 1 , ... wavelength 9 | 200, ... MFP 10 | [-5,5], ... z 11 | [-5,5] ... x 12 | ); 13 | 14 | boxTargetArea3D = boxArea( ... 15 | 1 , ... wavelength 16 | 200, ... MFP 17 | [-5,5], ... z 18 | [-5,5], ... x 19 | [-5,5] ... y 20 | ); 21 | 22 | % and the lighting and views 23 | viewDirections = 0:1:360; % in deg 24 | views = farFieldSource(deg2rad(viewDirections),0); 25 | lights = farFieldSource(0,0); % light in 0 deg direction 26 | 27 | % the g parameter we comapre with 28 | gParam = 0.7; 29 | 30 | % the 2D direction vector MUST being with 0 and end with 2*pi 31 | directions2D = (0:1e-4:1) * 2 * pi; 32 | hg2Damplitude = sqrt(evaluateHG(directions2D, gParam, 0, 2)); 33 | 34 | figure 35 | polarplot(directions2D,hg2Damplitude.^2); 36 | 37 | title('Target HG function') 38 | 39 | %% Build 2D tabulated HG function 40 | 41 | % solve for both tabulated and HG 42 | tic 43 | hgRes = scmc(boxTargetArea2D, views, lights, HGScatter(gParam), 1e3); 44 | toc 45 | 46 | tic 47 | tabRes = scmc(boxTargetArea2D, views, lights, ... 48 | tabulatedAmplitudeScatter(directions2D,hg2Damplitude), 1e3); 49 | toc 50 | 51 | % plot the intensity of both results 52 | figure 53 | polarplot(deg2rad(viewDirections),diag(abs(hgRes.C))); 54 | hold on 55 | polarplot(deg2rad(viewDirections),diag(abs(tabRes.C))); 56 | 57 | legend('HG','Tabulated HG'); 58 | title('2D HG plot') 59 | 60 | %% Build 3D tabulated HG function 61 | 62 | % the 3D direction vector MUST being with 0 and end with pi, theta is the 63 | % elevation direction 64 | cosThetaVals3D = (0:1e-4:1) * pi; 65 | hg3Damplitude = sqrt(evaluateHG(cosThetaVals3D, gParam, 0, 3)); 66 | 67 | % solve for both tabulated and HG 68 | tic 69 | hgRes = scmc(boxTargetArea3D, views, lights, HGScatter(gParam), 1e3); 70 | toc 71 | 72 | tic 73 | tabRes = scmc(boxTargetArea3D, views, lights, ... 74 | tabulatedAmplitudeScatter(cosThetaVals3D,hg3Damplitude), 1e3); 75 | toc 76 | 77 | % plot the intensity of both results 78 | figure 79 | polarplot(deg2rad(viewDirections),diag(abs(hgRes.C))); 80 | hold on 81 | polarplot(deg2rad(viewDirections),diag(abs(tabRes.C))); 82 | 83 | legend('HG','Tabulated HG'); 84 | title('3D HG plot') -------------------------------------------------------------------------------- /examples/evaluateTabulatedScatterVsHG/evaluateTabulatedScatterVsHG.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/evaluateTabulatedScatterVsHG/evaluateTabulatedScatterVsHG.pdf -------------------------------------------------------------------------------- /examples/memoryEffectMeasurements/memoryEffectMeasurements.m: -------------------------------------------------------------------------------- 1 | %% Define the expirements we want to run 2 | 3 | % Delta between light to view (in order to avoid CBS) 4 | theta0 = 0.002; 5 | 6 | % light 7 | theta = deg2rad((0:0.001:0.02) + theta0); 8 | 9 | % phantom width 10 | L = 2000; 11 | 12 | % HG parameters 13 | g = 0; 14 | g0 = 0; 15 | 16 | % OD 17 | OD = 10; 18 | 19 | % backward scattering 20 | bws = false; 21 | 22 | % view which will be squee 23 | viewsVec = deg2rad(-1:0.1:-0.1); 24 | vecNum = numel(viewsVec); 25 | 26 | % sectors of cov matrix 27 | sec_1 = 1:1:vecNum; 28 | sec_2 = vecNum+1:1:2*vecNum; 29 | 30 | % results 31 | c_measured = zeros(1,numel(theta)); 32 | 33 | %% Run the expirements 34 | 35 | % prepare the config 36 | boxTargetArea = boxArea( ... 37 | 1 , ... wavelength 38 | L/OD, ... MFP 39 | [0,L], ... z 40 | [-50000,50000], ... half of x axis 41 | [-50000,50000] ... half of x axis 42 | ); 43 | 44 | scatter = HGScatter(g,g0); 45 | 46 | tic 47 | % Run seperatly for each two directions 48 | for idx1 = 1:1:numel(theta) 49 | theta_1 = theta(1); 50 | theta_2 = theta(idx1); 51 | 52 | dtheta = theta_2 - theta_1; 53 | phi_1 = viewsVec; 54 | phi_2 = viewsVec - dtheta; 55 | 56 | % If backward scattering 57 | if(bws) 58 | phi_1 = phi_1 + pi; 59 | phi_2 = phi_2 + pi; 60 | end 61 | 62 | % Run expirements 63 | mulres = scmc(boxTargetArea, ... 64 | farFieldSource([phi_1,phi_2],0), ... 65 | farFieldSource([theta_1,theta_2],0), ... 66 | scatter,1e3, ... 1e5 for more accurate result 67 | 'CBS',false, ... The light and the view are never the same direction 68 | 'uniformFirstScatter',false, ... for more effitient sampling 69 | 'parforIters', 12); 70 | 71 | % Get the intensity correlation 72 | sigma = zeros(2); 73 | sigma(1,1) = mean(diag(mulres.C(sec_1,sec_1,1,1))); 74 | sigma(2,2) = mean(diag(mulres.C(sec_2,sec_2,2,2))); 75 | 76 | % Check wich diagonal has higher values 77 | diagA = mean(diag(mulres.C(sec_2,sec_1,1,2))); 78 | diagB = mean(diag(mulres.C(sec_1,sec_2,1,2))); 79 | 80 | if(abs(diagA) > abs(diagB)) 81 | sigma(1,2) = mean(diag(mulres.C(sec_2,sec_1,1,2))); 82 | sigma(2,1) = mean(diag(mulres.C(sec_1,sec_2,2,1))); 83 | else 84 | sigma(1,2) = mean(diag(mulres.C(sec_1,sec_2,1,2))); 85 | sigma(2,1) = mean(diag(mulres.C(sec_2,sec_1,2,1))); 86 | end 87 | 88 | sigma_I = zeros(2); 89 | sigma_I(1,1) = (sigma(1,1))^2; 90 | sigma_I(2,2) = (sigma(2,2))^2; 91 | sigma_I(1,2) = sigma(1,2) * sigma(2,1); 92 | 93 | sigma_I = real(sigma_I); 94 | 95 | % Calculate the memory effect 96 | c_measured(idx1) = (sigma_I(1,2)/(sqrt(sigma_I(2,2)*sigma_I(1,1)))); 97 | end 98 | toc 99 | 100 | %% Compare between the calculated and theoreric ME graphs 101 | % The theoretic ME is true for the diffusive region 102 | dtheta = theta - theta(1); 103 | c_theory = (2*pi*L*dtheta./sinh(2*pi*L*dtheta)).^2; 104 | c_theory(dtheta == 0) = 1; 105 | 106 | figure 107 | hold on 108 | plot(rad2deg(dtheta),c_measured,'lineWidth',2); 109 | plot(rad2deg(dtheta),c_theory,'k--','lineWidth',2); 110 | 111 | xlabel('\theta[deg]'); 112 | ylim([0,1]); 113 | legend('Measured','Theoretic') -------------------------------------------------------------------------------- /examples/memoryEffectMeasurements/memoryEffectMeasurements.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/memoryEffectMeasurements/memoryEffectMeasurements.pdf -------------------------------------------------------------------------------- /examples/multipleAndSingleScattering/multipleAndSingleScattering.m: -------------------------------------------------------------------------------- 1 | %% Check dependence of single vs. multiple scattering 2 | % Measure the correlation in multiple scattering and single scattering 3 | % cases, where the light and view are rotated around the z axis 4 | 5 | span = 22; % how l1 source is far from z axis (in degrees) 6 | alpha = 0:3:90; % the rotation directions (in degrees) 7 | 8 | % Build the target area 9 | boxTargetArea = boxArea( ... 10 | 1 , ... wavelength 11 | 20, ... MFP 12 | [-50,50], ... z 13 | [-50,50], ... x 14 | [-50,50] ... y 15 | ); 16 | 17 | scatter = isotropicScatter; 18 | 19 | singleCorr = zeros(1,numel(alpha)); 20 | mulCorr = zeros(1,numel(alpha)); 21 | totalCorr = zeros(1,numel(alpha)); 22 | 23 | %% Measure correlation 24 | 25 | l1 = [-sind(span), 0, cosd(span)]; 26 | v1 = [-sind(span), 0, -cosd(span)]; % minus for backward scattering 27 | 28 | tic 29 | for a = 1:1:numel(alpha) 30 | % Build the rotation matrix around z axis 31 | R_alpha = [ ... 32 | cosd(alpha(a)), -sind(alpha(a)), 0; ... 33 | sind(alpha(a)), cosd(alpha(a)), 0; ... 34 | 0 0 1]; 35 | 36 | l2=(R_alpha*l1')'; 37 | v2=(R_alpha*v1')'; 38 | 39 | % Solve 40 | mulres = scmc(boxTargetArea, ... 41 | farFieldSource([v1',v2']), ... 42 | farFieldSource([l1',l2']), ... 43 | scatter,1e3, ... 44 | 'mean', false, ... 45 | 'singleScattering', true, ... 46 | 'parforIters', 12); 47 | 48 | singleCorrMatrix = mulres.Csingle(:,:,1,2); 49 | totalCorrMatrix = mulres.C(:,:,1,2); 50 | [~,maxCorrIdx] = max(abs(totalCorrMatrix(:))); 51 | 52 | singleCorr(a) = abs(singleCorrMatrix(maxCorrIdx)); 53 | mulCorr(a) = abs(totalCorrMatrix(maxCorrIdx) - singleCorrMatrix(maxCorrIdx)); 54 | totalCorr(a) = abs(totalCorrMatrix(maxCorrIdx)); 55 | 56 | end 57 | toc 58 | 59 | maxCorr = max(totalCorr); 60 | 61 | %% Comapare between single scattering the multiple scattering 62 | figure; 63 | hold on 64 | plot(alpha,singleCorr/maxCorr,'lineWidth',2); 65 | plot(alpha,mulCorr/maxCorr,'lineWidth',2); 66 | plot(alpha,totalCorr/maxCorr,'lineWidth',2); 67 | 68 | legend('Single Scattering','Multiple Scattering','Total Scattering') 69 | xlabel('Rotation [deg]'); 70 | ylabel('Correlation'); -------------------------------------------------------------------------------- /examples/multipleAndSingleScattering/multipleAndSingleScattering.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/multipleAndSingleScattering/multipleAndSingleScattering.pdf -------------------------------------------------------------------------------- /examples/renderSpecklesImages/renderSpecklesImages.m: -------------------------------------------------------------------------------- 1 | %% Render speckles images 2 | % Show how to use the rendering algorithm, and demonstrate the memory 3 | % effect 4 | 5 | % Build the target area 6 | boxTargetArea = boxArea( ... 7 | 1 , ... wavelength 8 | 200, ... MFP 9 | [0,2000], ... z 10 | [-50000,50000], ... x 11 | [-50000,50000] ... y 12 | ); 13 | 14 | % g = 0.9 for strong ME. g = 0 will give weak ME. 15 | scatter = HGScatter(0.9, 0.8); 16 | 17 | % Light directions number, each direction is a different image 18 | lightsNum = 5; 19 | 20 | % Delta beween each direction (in degrees) 21 | lightDelta = 0.0025; 22 | 23 | lights = (0:1:(lightsNum-1)) * lightDelta; 24 | 25 | % Create 101x101 image 26 | pixNum = 101; 27 | 28 | % For each lighting direction, we will set up 20 sensors 29 | % The more sensorsToLight is bigger, the bigger speckles are, but less 30 | % speckles will appear. 31 | % It is also the numbet of pixels each speckle will move between lightings. 32 | sensorsToLight = 20; 33 | 34 | viewsVector = (-((pixNum-1)/2):1:((pixNum-1)/2)) * ... 35 | (lightDelta/sensorsToLight); 36 | 37 | % Make views image 38 | [X,Y] = meshgrid(viewsVector); 39 | 40 | % The directions will be auto-normalized in the code 41 | views = [sind(X(:).');sind(Y(:).');ones(1,numel(X))]; 42 | 43 | %% Run the code and get the rendered image 44 | % Be careful not render the correlation matrix, since it has huge memory 45 | % consuption 46 | 47 | tic; 48 | mulres = scmc(boxTargetArea, ... 49 | farFieldSource(views), ... 50 | farFieldSource(deg2rad(lights),0), ... 51 | scatter,1e3, ... 52 | 'renderCov', false, ... Avoid from making the correlation matrix 53 | 'CBS',false, ... Since we forward, the CBS is not necessary 54 | 'uniformFirstScatter', false, ... For more efficient sampling 55 | 'renderField', true, ... In order to actually render the image 56 | 'parforIters', 12); 57 | toc; 58 | 59 | % put back the resolt into an image 60 | u = reshape(mulres.field,pixNum,pixNum,lightsNum); 61 | 62 | %% Plot the images 63 | f = figure; 64 | f.Position = [0,0,1400,250]; 65 | 66 | maxVal = max(abs(u(:))); 67 | 68 | for lNum = 1:1:lightsNum 69 | subplot(1,lightsNum,lNum) 70 | imagesc(abs(u(:,:,lNum)),[0,maxVal]); 71 | 72 | colormap hot 73 | xticks([]); 74 | yticks([]); 75 | 76 | title([num2str(lights(lNum)),'\circ']) 77 | end -------------------------------------------------------------------------------- /examples/renderSpecklesImages/renderSpecklesImages.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/renderSpecklesImages/renderSpecklesImages.pdf -------------------------------------------------------------------------------- /examples/sampleTabulatedScatterVsHG/sampleTabulatedScatterVsHG.m: -------------------------------------------------------------------------------- 1 | %% Sample Tabulated Scattering vs HG 2 | % In this example, we will show how to build tabulated scatter in 2D and 3D 3 | % and compare the sampling from the tabulated scattering scattering in 4 | % multiple scattering case 5 | 6 | % first build the target area for 2D and 3D 7 | boxTargetArea2D = boxArea( ... 8 | 1 , ... wavelength 9 | 200, ... MFP 10 | [-300,300], ... z 11 | [-300,300] ... x 12 | ); 13 | 14 | boxTargetArea3D = boxArea( ... 15 | 1 , ... wavelength 16 | 200, ... MFP 17 | [-300,300], ... z 18 | [-300,300], ... x 19 | [-300,300] ... y 20 | ); 21 | 22 | % and the lighting and views 23 | viewDirections = 0:1:360; % in deg 24 | views = farFieldSource(deg2rad(viewDirections),0); 25 | lights = farFieldSource(0,0); % light in 0 deg direction 26 | 27 | % the g parameter we comapre with 28 | gParam = 0.7; 29 | 30 | %% Build 2D tabulated HG function 31 | 32 | % the 2D direction vector MUST being with 0 and end with 2*pi 33 | directions2D = (0:1e-4:1) * 2 * pi; 34 | hg2Damplitude = sqrt(evaluateHG(directions2D, gParam, 0, 2)); 35 | 36 | % solve for both tabulated and HG 37 | tic 38 | hgRes = scmc(boxTargetArea2D, views, lights, HGScatter(gParam), 1e4, ... 39 | 'parforIters', 12); 40 | toc 41 | 42 | tic 43 | tabRes = scmc(boxTargetArea2D, views, lights, ... 44 | tabulatedAmplitudeScatter(directions2D,hg2Damplitude), 1e4, ... 45 | 'parforIters', 12); 46 | toc 47 | 48 | % plot the intensity of both results 49 | figure 50 | polarplot(deg2rad(viewDirections),diag(abs(hgRes.C))); 51 | hold on 52 | polarplot(deg2rad(viewDirections),diag(abs(tabRes.C))); 53 | 54 | legend('HG','Tabulated HG'); 55 | title('2D HG plot') 56 | 57 | %% Build 3D tabulated HG function 58 | 59 | % the 3D direction vector MUST being with 0 and end with pi, theta is the 60 | % elevation direction 61 | cosThetaVals3D = (0:1e-4:1) * pi; 62 | hg3Damplitude = sqrt(evaluateHG(cosThetaVals3D, gParam, 0, 3)); 63 | 64 | % solve for both tabulated and HG 65 | tic 66 | hgRes = scmc(boxTargetArea3D, views, lights, HGScatter(gParam), 1e4, ... 67 | 'parforIters', 12); 68 | toc 69 | 70 | tic 71 | tabRes = scmc(boxTargetArea3D, views, lights, ... 72 | tabulatedAmplitudeScatter(cosThetaVals3D,hg3Damplitude), 1e4, ... 73 | 'parforIters', 12); 74 | toc 75 | 76 | % plot the intensity of both results 77 | figure 78 | polarplot(deg2rad(viewDirections),diag(abs(hgRes.C))); 79 | hold on 80 | polarplot(deg2rad(viewDirections),diag(abs(tabRes.C))); 81 | 82 | legend('HG','Tabulated HG'); 83 | title('3D HG plot') -------------------------------------------------------------------------------- /examples/sampleTabulatedScatterVsHG/sampleTabulatedScatterVsHG.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/sampleTabulatedScatterVsHG/sampleTabulatedScatterVsHG.pdf -------------------------------------------------------------------------------- /examples/samplingFromCovMatrix/samplingFromCovMatrix.m: -------------------------------------------------------------------------------- 1 | %% Build cov matrix, and have generate samples from it 2 | 3 | % Build the target area 4 | boxTargetArea = boxArea( ... 5 | 1 , ... wavelength 6 | 0.5, ... MFP 7 | [0,1], ... z 8 | [-10,10], ... x 9 | [-10,10] ... y 10 | ); 11 | 12 | % define HG scatter 13 | scatter = isotropicScatter; 14 | 15 | % make lights in far field, and views in near field 16 | lightDirections = [0, 4]; 17 | lights = farFieldSource(deg2rad(lightDirections), 0); 18 | views = nearFieldSource([-5;0;-10],[5;0;-10],101); 19 | viewsPositions = views.positions(1,:); 20 | 21 | % render both the cov matrix, and one direct sample of the field 22 | tic; 23 | mulres = scmc(boxTargetArea, views, lights, scatter,1e3, ... 24 | 'renderField', true, 'parforIters', 12); 25 | toc 26 | 27 | maxVal = max(abs(mulres.C(:))); 28 | 29 | % show correlation matrix 30 | f = figure; 31 | f.Position = [0,0,870,420]; 32 | subplot(1,2,1) 33 | imagesc(viewsPositions,viewsPositions,abs(mulres.C(:,:,1,1)),[0,maxVal]) 34 | title(['(',num2str(lightDirections(1)),',', ... 35 | num2str(lightDirections(1)),')']); 36 | 37 | subplot(1,2,2) 38 | imagesc(viewsPositions,viewsPositions,abs(mulres.C(:,:,1,2)),[0,maxVal]) 39 | title(['(',num2str(lightDirections(1)),',', ... 40 | num2str(lightDirections(2)),')']); 41 | 42 | %% Sample from correlation matrix 43 | % Sample from complex multinormal distribution 44 | 45 | % first build united C matirx 46 | C = [mulres.C(:,:,1,1),mulres.C(:,:,1,2) ; ... 47 | mulres.C(:,:,2,1),mulres.C(:,:,2,2)]; 48 | 49 | figure 50 | imagesc(abs(C)); 51 | xticks([]); 52 | yticks([]); 53 | title('United correlation matrix'); 54 | 55 | % seperate the real and complex part of the matrix 56 | Sigma = 0.5 * [real(C), -imag(C); imag(C), real(C)]; 57 | Miu = zeros(1,size(Sigma,1)); 58 | 59 | % take two samples 60 | sample1 = mvnrnd(Miu,Sigma); 61 | sample2 = mvnrnd(Miu,Sigma); 62 | 63 | % reshape to complex number 64 | halfSample = numel(sample1)/2; 65 | z1 = sample1(1:halfSample) + 1i * sample1(halfSample+1:end); 66 | z2 = sample2(1:halfSample) + 1i * sample2(halfSample+1:end); 67 | 68 | % reshape to two lighting directions 69 | u1 = reshape(z1,[],2); 70 | u2 = reshape(z2,[],2); 71 | 72 | %% Plot all samples 73 | % In full lines - lighting direction of $0^\circ$ 74 | % 75 | % In dashed line - lighting direction of $4^\circ$ 76 | figure; 77 | f = gca; 78 | plotColors = f.ColorOrder; 79 | hold on 80 | 81 | l1 = plot(viewsPositions,abs(mulres.field(:,1)), ... 82 | 'lineWidth',2,'Color',plotColors(1,:),'LineStyle','-'); 83 | 84 | plot(viewsPositions,abs(mulres.field(:,2)), ... 85 | 'lineWidth',2,'Color',plotColors(1,:),'LineStyle','--'); 86 | 87 | l2 = plot(viewsPositions,abs(u1(:,1)), ... 88 | 'lineWidth',2,'Color',plotColors(2,:),'LineStyle','-'); 89 | 90 | plot(viewsPositions,abs(u1(:,2)), ... 91 | 'lineWidth',2,'Color',plotColors(2,:),'LineStyle','--'); 92 | 93 | l3 = plot(viewsPositions,abs(u2(:,1)), ... 94 | 'lineWidth',2,'Color',plotColors(3,:),'LineStyle','-'); 95 | 96 | plot(viewsPositions,abs(u2(:,2)), ... 97 | 'lineWidth',2,'Color',plotColors(3,:),'LineStyle','--'); 98 | 99 | legend([l1, l2, l3], 'Measured Field', 'Sampled Field 1', 'Sampled Field 2'); 100 | xlabel('View position'); 101 | ylabel('Abs field'); 102 | title('Direct rendered field vs sampled field'); -------------------------------------------------------------------------------- /examples/samplingFromCovMatrix/samplingFromCovMatrix.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-ci-lab/mcspeckle/c4ecf78f32558cba5e45ab0c43a0995a20f2c85b/examples/samplingFromCovMatrix/samplingFromCovMatrix.pdf -------------------------------------------------------------------------------- /examples/testHetro/testHetroCov.m: -------------------------------------------------------------------------------- 1 | lambda=1 2 | box_min=[-60;-60]; box_max=[60;60]; box_bin=[40;60]; 3 | %sigt=[1/200,0,1/400;0,1/400,1/200]'; 4 | sigt=[1/30,0,1/60;0,1/120,1/30]'; 5 | 6 | MFP=1./sigt; 7 | 8 | 9 | 10 | 11 | 12 | theta_l=pi-deg2rad([0,4,12,32]); 13 | theta_v=deg2rad([-88:4:270]); 14 | 15 | 16 | 17 | 18 | Nl=length(theta_l); 19 | Nv=length(theta_v); 20 | 21 | 22 | Nx=(box_max(1)-box_min(1))/box_bin(1); 23 | Nz=(box_max(2)-box_min(2))/box_bin(2); 24 | Nxz=Nx*Nz; 25 | 26 | 27 | load tmpdata/ampfunc05lmbd1 28 | %eval(sprintf('load ../../resdirHetro/res_itr36_MFP200.mat')) 29 | eval(sprintf('load ../../resdirHetro/res_itr100_MFP30.mat')) 30 | 31 | E2=covU; 32 | for j1=1:Nl 33 | for j2=1:Nl 34 | covU(:,:,j1,j2)=covU(:,:,j1,j2)-meanU(:,j1)*meanU(:,j2)'; 35 | end 36 | end 37 | 38 | 39 | v=[sin(theta_v);cos(theta_v)]; 40 | l=[sin(theta_l);cos(theta_l)]; 41 | 42 | doCBS=1; smpFlg=1; 43 | maxItr=10^3; 44 | 45 | 46 | parfor j=1:100 47 | j 48 | [Ms2,Mm2,mean12]=MCCovHetro( sigt, 1, box_min,box_max,box_bin, l, v,1,1,maxItr,lambda,doCBS,2,2,ampfunc); 49 | tMs(:,:,:,:,j)=Ms2; tMm(:,:,:,:,j)=Mm2; tmean1(:,:,j)=mean12; 50 | end 51 | Ms2=mean(tMs,5); 52 | Mm2=mean(tMm,5); 53 | mean12=mean(tmean1,3); 54 | M2=Ms2+Mm2; 55 | 56 | 57 | 58 | parfor j=1:100 59 | j 60 | [Ms,Mm,mean1]=MCCovHetro( sigt, 1, box_min,box_max,box_bin, l, v,1,1,maxItr,lambda,doCBS,smpFlg,2,ampfunc); 61 | tMs(:,:,:,:,j)=Ms; tMm(:,:,:,:,j)=Mm; tmean1(:,:,j)=mean1; 62 | end 63 | Ms=mean(tMs,5); 64 | Mm=mean(tMm,5); 65 | mean1=mean(tmean1,3); 66 | M=Ms+Mm; 67 | 68 | 69 | 70 | maxItrSi=10^2; 71 | maxItrS=10^4; 72 | uL=zeros(Nv,Nl,maxItrS); 73 | if 1 74 | parfor j=1:maxItrS 75 | j 76 | uL(:,:,j)=MCsampleHetro( sigt, 1, box_min,box_max,box_bin, l, v,1,1,maxItrSi,lambda,doCBS,2,2,ampfunc); 77 | 78 | end 79 | end 80 | for j1=1:Nl 81 | for j2=1:Nl 82 | MU(:,:,j1,j2)=1/maxItrS*squeeze(uL(:,j1,:))*squeeze(uL(:,j2,:))'; 83 | end 84 | end 85 | theta_v_d=rad2deg(theta_v); 86 | theta_l_d=rad2deg(theta_l); 87 | 88 | for j1=1%:Nl%:Nl 89 | for j2=j1:Nl 90 | 91 | ds=find(abs(theta_v_d-theta_l_d(j1))<0.001)-find(abs(theta_v_d-theta_l_d(j2))<0.001); 92 | 93 | figure, plot(abs(diag( M(:,:,j1,j2),ds))); hold on 94 | plot(abs(diag( M2(:,:,j1,j2),ds))); 95 | plot(abs(diag( covU(:,:,j1,j2 ),ds)),'r'); 96 | plot(abs(diag( MU(:,:,j1,j2),ds))); 97 | legend('MC','MC exp ','mu-diff','MC smp') 98 | title(sprintf('theta_1=%d, theta_2=%d',round(rad2deg(theta_l(j1))),round(rad2deg(theta_l(j2))))) 99 | 100 | 101 | end 102 | end 103 | figure, hold on, plot(theta_v_d,abs(meanU(:,1))),plot(theta_v_d,abs(mean1(:,1))) 104 | figure, hold on, plot(theta_v_d,abs(meanU(:,3))),plot(theta_v_d,abs(mean1(:,3))) 105 | -------------------------------------------------------------------------------- /examples/testHetro/testRefocus.m: -------------------------------------------------------------------------------- 1 | 2 | lambda=1; 3 | box_min=[-50; -50]; 4 | box_max=[ 50; 50]; 5 | sigt=[1/25,1/25,0,1/50;0,1/100,1/100,1/25]'; 6 | box_bin=[25;50]; 7 | 8 | theta_l=pi-deg2rad([-35:5:35]); 9 | theta_v=deg2rad([-40:0.2:40]); 10 | 11 | 12 | Nl=length(theta_l); 13 | Nv=length(theta_v); 14 | 15 | 16 | Nx=(box_max(1)-box_min(1))/box_bin(1); 17 | Nz=(box_max(2)-box_min(2))/box_bin(2); 18 | Nxz=Nx*Nz; 19 | 20 | v=[sin(theta_v);cos(theta_v)]; 21 | l=[sin(theta_l);cos(theta_l)]; 22 | 23 | doCBS=0; smpFlg=2; 24 | maxItr=10^4; 25 | %maxItr=1; 26 | g=0.5 27 | j=1 28 | rng(520) 29 | tic 30 | uL(:,:,j)=MCsampleHetro( sigt, 1, box_min,box_max,box_bin, l, v,1,1,maxItr,lambda,doCBS,smpFlg,1,0); 31 | toc 32 | box_stp=[0.5;1]; 33 | for j=1:Nl 34 | tic 35 | rU(:,:,j)=refocus(uL(:,j),v,l(:,j),box_min,box_max,box_stp,lambda); 36 | toc 37 | figure, imshow(abs(rU(:,:,j)),[]) 38 | %keyboard 39 | end 40 | 41 | figure, imshow(abs(mean(rU,3)),[]) -------------------------------------------------------------------------------- /examples/testHetro/testRefocus3D.m: -------------------------------------------------------------------------------- 1 | 2 | lambda=1; 3 | box_min=[-50; -50; 0]; 4 | box_max=[ 50; 50; 100]; 5 | sigt=[1/25,1/25,0,0;0,0,1/25,1/25]'; 6 | %sigt=[0,1/2000,1/2000,0;0,1/2000,1/2000,0]'; 7 | sigt=repmat(reshape(sigt,4,1,2),[1,4,1]); 8 | box_bin=[25;25;50]; 9 | 10 | sigt=[1/50,1/25,1/25,0,0;0,0,1/50,1/25,0]'; 11 | sigt=repmat(reshape(sigt,5,1,2),[1,5,1]); 12 | sigt(:,[1:2,4:5],:)=0; 13 | box_bin=[20;20;50]; 14 | 15 | 16 | theta_l=pi-deg2rad([-35:5:35]); 17 | theta_v=deg2rad([-40:0.2:40]); 18 | 19 | 20 | Nl0=length(theta_l); 21 | Nv0=length(theta_v); 22 | Nv=Nv0^2; 23 | Nl=Nl0^2; 24 | 25 | Nx=(box_max(1)-box_min(1))/box_bin(1); 26 | Nz=(box_max(2)-box_min(2))/box_bin(2); 27 | Nxz=Nx*Nz; 28 | 29 | [vx,vy]=ndgrid(theta_v,theta_v); 30 | v=[sin(vx(:))';sin(vy(:))';ones(1,Nv)]; 31 | v=v./repmat(sum(v.^2,1).^0.5,3,1); 32 | [lx,ly]=ndgrid(theta_l,theta_l); 33 | l=[sin(lx(:))';sin(ly(:))';ones(1,Nl)]; 34 | l=l./repmat(sum(l.^2,1).^0.5,3,1); 35 | 36 | 37 | 38 | 39 | doCBS=1; smpFlg=1; 40 | maxItr=10^4; 41 | %maxItr=1; 42 | maxItr=200; 43 | j=1 44 | rng(520) 45 | parfor j=1:24 46 | tic 47 | uL(:,:,j)=MCsampleHetro( sigt, 1, box_min,box_max,box_bin, l, v,1,1,maxItr,lambda,doCBS,smpFlg,1,0); 48 | toc 49 | end 50 | uL=sum(uL,3); 51 | box_stp=[1;50;2]; 52 | box_stp=[2;50;5]; 53 | 54 | j=ceil(Nl/2); 55 | trU=refocus(uL(:,j),v,l(:,j),box_min,box_max,box_stp,lambda); 56 | d2=size(trU,2); d2=ceil(d2/2); 57 | figure, imshow(squeeze(abs(mean(trU(:,d2,:,:),4))),[]) 58 | 59 | parfor j=1:Nl 60 | j 61 | tic 62 | trU=refocus(uL(:,j),v,l(:,j),box_min,box_max,box_stp,lambda); 63 | rU(:,j)=trU(:); 64 | toc 65 | 66 | %d2=size(rU,2); d2=ceil(d2/2); 67 | %figure, imshow(squeeze(abs(rU(:,50,:,j))),[]) 68 | %keyboard 69 | end 70 | 71 | dd=size(trU); 72 | rU=reshape(rU,[dd,Nl]); 73 | d2=size(rU,2); d2=ceil(d2/2); 74 | figure, imshow(squeeze(abs(mean(rU(:,d2,:,:),4))),[]) 75 | -------------------------------------------------------------------------------- /examples/testHetro/testSmpXHetro.m: -------------------------------------------------------------------------------- 1 | maxItr=10^6; 2 | 3 | sigt=[1/30,0,1/60;0,1/120,1/30]'; 4 | box_bin=[40;60]/5; 5 | sigt=imresize(sigt,5,'nearest'); 6 | 7 | H=zeros(size(sigt)); 8 | P=zeros(size(sigt)); 9 | lmean=[0;1]; 10 | lmean=mean(l,2); 11 | lmean=[0.3;0.8] 12 | lmean=lmean/norm(lmean) 13 | lrad=sqrt(sum((box_max-box_min).^2)); 14 | 15 | for itr=1:maxItr 16 | [x,px]=expSmpXHetro(box_min,box_max,box_bin,lmean,sigt,lrad); 17 | 18 | 19 | if(max(x>box_max)|max(x(box_max-ep))|max(x+s(j)*v<(box_min+ep))) 20 | break 21 | end 22 | ts=sigt(findBin(x+s(j)*v,box_min,box_max,box_bin)); 23 | e_v(j)=ts*e_v0./(evalphaseattHetro(x+s(j)*v,ff_sign*v,is_ff_v,sigt,lambda,box_min,box_max,box_bin))^2; 24 | end 25 | 26 | for j=1:10^6 27 | d2(j)=smpWoodcock(x,box_min,box_max,box_bin,sigt,v); 28 | end 29 | 30 | h2=hist(d2,s+0.5); 31 | h2=h2/sum(h2); 32 | 33 | figure, plot(s, abs(e_v)) 34 | hold on 35 | plot(s,h2/(h2(1))*max(e_v(1))) 36 | -------------------------------------------------------------------------------- /interface/scatter/HGScatter.m: -------------------------------------------------------------------------------- 1 | function [scatter] = HGScatter(g, g0, albedo) 2 | %HGSCATTER define Henyey-Greenstein scatter propertites 3 | % 4 | % scatter = HGScatter(g) HG scatter with parameter g. g is scalar between 5 | % -1 to 1. negative g for back scattering. g = 0 for isotropic 6 | % scattering. 7 | % 8 | % scatter = HGScatter(g,g0) g0 is a parameter spasifying how to sample 9 | % the first direction of a path 10 | % Default value is isotropic scattering (g=0). 11 | % 12 | % scatter = HGScatter(g,g0,albedo) define albedo parameter. scalar from 0 13 | % to 1. 1 is without absorption, and 0 is full absorption. default value 14 | % is 1. 15 | % 16 | % Class support for all inputs: 17 | % float: double 18 | % 19 | % SEE ALSO: isotropicScatter, tabulatedAmplitudeScatter, scmc 20 | % 21 | 22 | % Check input num 23 | narginchk(1,5); 24 | 25 | scatter.type = 'scatter'; 26 | scatter.function = 'HG'; 27 | 28 | if(nargin >= 3) 29 | if(~isscalar(albedo) || albedo < 0 || albedo > 1) 30 | error('Invalid albedo input'); 31 | end 32 | 33 | scatter.albedo = albedo; 34 | else 35 | % default albedo value 36 | scatter.albedo = 1; 37 | end 38 | 39 | if(nargin >= 2) 40 | if(~isscalar(g0) || g0 < -1 || g0 > 1) 41 | error('Invalid g0 input'); 42 | end 43 | 44 | scatter.g0 = g0; 45 | else 46 | % default threshold value (inf for default) 47 | scatter.g0 = inf; 48 | end 49 | 50 | if(~isscalar(g) || g < -1 || g > 1) 51 | error('Invalid g input'); 52 | end 53 | 54 | scatter.g = g; 55 | 56 | end 57 | 58 | -------------------------------------------------------------------------------- /interface/scatter/isotropicScatter.m: -------------------------------------------------------------------------------- 1 | function [scatter] = isotropicScatter(albedo) 2 | %HGSCATTER define isotropic scattering for scatter 3 | % 4 | % scatter = isotropicScatter() isotropic scattering. 5 | % 6 | % scatter = isotropicScatter(albedo) define albedo parameter. scalar from 7 | % 0 to 1. 1 is without absorption, and 0 is full absorption. default 8 | % value is 1. 9 | % 10 | % Class support for all inputs: 11 | % float: double 12 | % 13 | % SEE ALSO: HGScatter, tabulatedAmplitudeScatter, scmc 14 | % 15 | 16 | % Check input num 17 | narginchk(0,1); 18 | 19 | scatter.type = 'scatter'; 20 | scatter.function = 'isotropic'; 21 | 22 | if(nargin == 1) 23 | if(~isscalar(albedo) || albedo < 0 || albedo > 1) 24 | error('Invalid albedo input'); 25 | end 26 | 27 | scatter.albedo = albedo; 28 | else 29 | % default albedo value 30 | scatter.albedo = 1; 31 | end 32 | 33 | end 34 | 35 | -------------------------------------------------------------------------------- /interface/scatter/tabulatedAmplitudeScatter.m: -------------------------------------------------------------------------------- 1 | function scatter = tabulatedAmplitudeScatter(theta,f,albedo) 2 | %TABULATEDFIELDSCATTER define scatter with complex amplitude function. 3 | % 4 | % scatter = tabulatedFieldScatter(theta,f) Define the amplitude function 5 | % f in directions of theta. theta is vector in size of 1xN and f is also 6 | % vector in size of 1xN, where N is the number of entries in directions. 7 | % * 2D space: theta is defined from 0 to 2pi, where 0 is the forward 8 | % direction of the field, and pi is the backward direction 9 | % * 3D space: theta is the elevation, defined from 0 to pi. 0 is the 10 | % forward direction and pi is the backward. the azimuth is uniformly 11 | % distributed from 0 to 2pi. 12 | % 13 | % scatter = tabulatedFieldScatter(theta,f,albedo) define albedo 14 | % parameter. scalar from 0 to 1. 1 is without absorption, and 0 is full 15 | % absorption. default value is 1. 16 | % 17 | % More About: 18 | % * Amplitude Function: the amplitude function f is measurement of the 19 | % complex field due to incident wave interaction with a single 20 | % scatterer. Those measurements can be produced with exact wave 21 | % solver, such as mu-diff. The amplitude function is also the square 22 | % root of the probability density function (pdf) of the scattering. 23 | % 24 | % * Cross Section: the cross section of scatterer is defined in 2D as 25 | % mean(abs(f).^2)*2*pi, and in 3D as 26 | % mean((abs(f).^2).*sin(theta))*2*pi^2. 27 | % 28 | % * Evaluation and Sampling: The evaluation in a specific direction is 29 | % normalized by the cross section, thus the integral of the evaluated 30 | % values over all directions is normalized to 1. For sampling, we 31 | % sample only the elevation, while the azimuth is sampled uniformly. 32 | % Thus, the elevation sampling is weighted by the corresponding 33 | % perimeter. 34 | % 35 | % Class support for all inputs: 36 | % float: double 37 | % 38 | % SEE ALSO: isotropicScatter, HGScatter, scmc 39 | % 40 | 41 | % Check input num 42 | narginchk(2,3); 43 | 44 | if(nargin == 3) 45 | scatter.albedo = albedo; 46 | else 47 | scatter.albedo = 1; 48 | end 49 | 50 | scatter.type = 'scatter'; 51 | scatter.function = 'tabulated'; 52 | 53 | if(~isvector(theta) || ~isvector(f)) 54 | error('theta and f must be vectors') 55 | end 56 | 57 | if(numel(theta) ~= numel(f)) 58 | error('theta and f must have same elements number') 59 | end 60 | 61 | if(~ismonotonic(theta,1)) 62 | error('theta must be monotonic increasing') 63 | end 64 | 65 | if( theta(1) == 0 && theta(end) == 2 * pi) 66 | scatter.D = 2; 67 | else 68 | if(theta(1) == 0 && theta(end) == pi) 69 | scatter.D = 3; 70 | else 71 | error('theta must be from 0 to 2pi in 2D or -1 to 1 in 3D') 72 | end 73 | end 74 | 75 | scatter.ampfunc.theta = theta(:).'; 76 | 77 | % Prepare the complex amplitude function for 2D and 3D 78 | if(scatter.D == 2) 79 | scatter.ampfunc.cs = mean(abs(f).^2)*2*pi; 80 | scatter.ampfunc.samplePdf = (abs(f(:).').^2) ./ sum((abs(f(:).').^2)); 81 | scatter.ampfunc.sampleCdf = cumsum(scatter.ampfunc.samplePdf); 82 | scatter.ampfunc.sampleIcdf = invCDF(scatter.ampfunc.sampleCdf,2); 83 | 84 | scatter.ampfunc.evalPdf = (abs(f(:).').^2) ./ scatter.ampfunc.cs; 85 | scatter.ampfunc.evalAmp = scatter.ampfunc.evalPdf .^ 0.5 ... 86 | .* exp(1i*angle(f(:).')); 87 | end 88 | 89 | if(scatter.D == 3) 90 | scatter.ampfunc.cs = mean((abs(f).^2).*sin(theta))*2*pi^2; 91 | scatter.ampfunc.samplePdf = (abs(f(:).').^2) .* sin(theta) ./ ... 92 | sum((abs(f(:).').^2) .* sin(theta)); 93 | scatter.ampfunc.sampleCdf = cumsum(scatter.ampfunc.samplePdf); 94 | scatter.ampfunc.sampleIcdf = invCDF(scatter.ampfunc.sampleCdf,3); 95 | 96 | scatter.ampfunc.evalPdf = (abs(f(:).').^2) ./ scatter.ampfunc.cs; 97 | scatter.ampfunc.evalAmp = scatter.ampfunc.evalPdf .^ 0.5 ... 98 | .* exp(1i*angle(f(:).')); 99 | end 100 | 101 | end 102 | -------------------------------------------------------------------------------- /interface/source/farFieldSource.m: -------------------------------------------------------------------------------- 1 | function [source] = farFieldSource(in1, ~) 2 | %FARFIELD build far field sources 3 | % 4 | % source = farFieldSource(directions) N directions defined explicitly. 5 | % directions is of size [2xN] or [3xN]. 6 | % * forward scattering applies when the signs of the z component of 7 | % the illumination and viewing directions are identical 8 | % * backward scattering applies when the signs of the z component of 9 | % the illumination and viewing directions are different 10 | % source = farFieldSource(theta,0) N directions, where theta defined as 11 | % [1xN] or [Nx1] in radians. 12 | % 13 | % Class support for all inputs: 14 | % float: double 15 | % 16 | % SEE ALSO: nearFieldSource, scmc 17 | % 18 | 19 | % Check input num 20 | narginchk(1,2); 21 | 22 | source.type = 'source'; 23 | 24 | source.farField = 1; 25 | 26 | if(nargin == 1) 27 | % source position are already given 28 | if(size(in1,1) ~=3 && size(in1,1) ~=2) 29 | error('Invalid positions elements number'); 30 | end 31 | 32 | source.count = size(in1,2); 33 | source.directions = in1; 34 | 35 | % normilize 36 | vectorLength = sqrt(sum(abs(source.directions).^2)); 37 | source.directions = source.directions ./ vectorLength; 38 | end 39 | 40 | if(nargin == 2) 41 | if( ~isvector(in1) ) 42 | error('theta must be vector of directions'); 43 | end 44 | 45 | source.count = numel(in1); 46 | 47 | source.directions2D = [sin(in1(:)), ... 48 | cos(in1(:))].'; 49 | 50 | source.directions3D = [sin(in1(:)), ... 51 | zeros(source.count,1), ... 52 | cos(in1(:))].'; 53 | 54 | end 55 | 56 | 57 | end 58 | 59 | -------------------------------------------------------------------------------- /interface/source/nearFieldSource.m: -------------------------------------------------------------------------------- 1 | function [source] = nearFieldSource(in1, in2, in3) 2 | %NEARFIELD build near field sources 3 | % 4 | % source = nearFieldSource(X,Y,N) make N sources spread uniformly between point X to Y. 5 | % X and Y are [2x1] or [3x1] vectors, and N is scalalr. 6 | % 7 | % source = nearFieldSource(positions) make N sources defined 8 | % explicity by positions, which is [2xN] or [3xN] vector. 9 | % 10 | % source = nearFieldSource(r,theta) make N sources in distance of r from 11 | % [0,0,0] and direction theta [1xN] or [Nx1] in radians. 12 | % 13 | % Class support for all inputs: 14 | % float: double 15 | % 16 | % SEE ALSO: farFieldSource, scmc 17 | % 18 | 19 | % Check input num 20 | narginchk(1,3); 21 | 22 | source.type = 'source'; 23 | 24 | source.farField = 0; 25 | 26 | if(nargin == 1) 27 | % source position are already given 28 | if(size(in1,1) ~=3 && size(in1,1) ~=2) 29 | error('Invalid positions elements number'); 30 | end 31 | 32 | source.count = size(in1,2); 33 | 34 | source.positions = in1; 35 | end 36 | 37 | if(nargin == 2) 38 | % r is positive scalar 39 | if(~(isscalar(in1) && in1 > 0)) 40 | error('r must be positive scalar'); 41 | end 42 | 43 | if( ~isvector(in2) ) 44 | error('theta must be vector of directions'); 45 | end 46 | 47 | source.count = numel(in2); 48 | 49 | source.positions2D = in1 * [sin(in2(:)), ... 50 | cos(in2(:))].'; 51 | 52 | source.positions3D = in1 * [sin(in2(:)), ... 53 | zeros(source.count,1), ... 54 | cos(in2(:))].'; 55 | 56 | end 57 | 58 | if(nargin == 3) 59 | % source position are given as interpulation between two points 60 | if((size(in1,1) ~=3 && size(in1,1) ~=2) || size(in1,2) ~= 1) 61 | error('Invalid X position'); 62 | end 63 | 64 | if((size(in2,1) ~=3 && size(in2,1) ~=2) || size(in2,2) ~= 1) 65 | error('Invalid Y position'); 66 | end 67 | 68 | if(size(in1,1) ~= size(in2,1)) 69 | error('Both points must have the same diamentions'); 70 | end 71 | 72 | if(~(isscalar(in3) && rem(in3,1) == 0 && in3 > 0)) 73 | error('Number of input points must be positive integer'); 74 | end 75 | 76 | source.count = in3; 77 | 78 | if(size(in1,1) == 2) 79 | source.positions = [linspace(in1(1),in2(1),in3).', ... 80 | linspace(in1(2),in2(2),in3).'].'; 81 | else 82 | source.positions = [linspace(in1(1),in2(1),in3).', ... 83 | linspace(in1(2),in2(2),in3).', ... 84 | linspace(in1(3),in2(3),in3).'].'; 85 | end 86 | 87 | 88 | end 89 | 90 | 91 | end 92 | -------------------------------------------------------------------------------- /interface/targetArea/boxArea.m: -------------------------------------------------------------------------------- 1 | function [targetArea] = boxArea(wavelength, MFP, z, x, y) 2 | %BOXAREA create target area in a shape of 2D rectangle or 3D square box. 3 | % 4 | % targetArea = boxArea(wavelength,scatteringMFP,z,x) defines the 5 | % wavelength,Mean Free Path, and diamentions of 2D rectangle target area. 6 | % * z is the depth of the rectangle, defined as 2 elements vector, where 7 | % the rectangle depth is defined from z(1) to z(2). 8 | % * x is the width of the rectangle, defined as 2 elements vector, where 9 | % the rectangle width is defined from x(1) to x(2). 10 | % 11 | % targetArea = boxArea(wavelength,scatteringMFP,z,x,y) defines 3D square 12 | % box, where the height defined from y(1) to y(2). 13 | % 14 | % Class support for inputs wavelength, MFP: 15 | % float: double scalars 16 | % 17 | % Class support for inputs z, x, y: 18 | % float: double 19 | % 20 | % SEE ALSO: mccov 21 | % 22 | 23 | % Check input num 24 | narginchk(4,5); 25 | 26 | if(~isscalar(wavelength) || ~isscalar(MFP)) 27 | error('wavelength and MFP are scalars'); 28 | end 29 | 30 | if(numel(z) ~= 2 || numel(x) ~= 2 || (nargin == 5 && numel(y) ~= 2)) 31 | error('x, y and z defined as 2 elements vectors'); 32 | end 33 | 34 | if(~isreal(z) || ~isreal(x) || (nargin == 5 && ~isreal(y))) 35 | error('x, y and z are real values'); 36 | end 37 | 38 | if(z(1) > z(2)) 39 | error('z(1) must be smaller than z(2)'); 40 | end 41 | 42 | if(x(1) > x(2)) 43 | error('x(1) must be smaller than x(2)'); 44 | end 45 | 46 | if(nargin == 5 && y(1) > y(2)) 47 | error('y(1) must be smaller than y(2)'); 48 | end 49 | 50 | targetArea.type = 'targetArea'; 51 | targetArea.wavelength = wavelength; 52 | targetArea.MFP = MFP; 53 | targetArea.z = z; 54 | targetArea.x = x; 55 | 56 | if(nargin == 4) 57 | targetArea.D = 2; 58 | end 59 | 60 | if(nargin == 5) 61 | targetArea.D = 3; 62 | targetArea.y = y; 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /scmc.m: -------------------------------------------------------------------------------- 1 | function [mulRes] = scmc(targetArea, views, lights, scatter, iterations, varargin) 2 | %SCMC Speckle Covariance Monte-Catlo solver 3 | % 4 | % mulRes = scmc(targetArea,views,lights,scatter,iterations) render 5 | % covariance of given parameters. Return structre with some of 6 | % the possible measurements: configuration struct, covariance, 7 | % single scattering covariance, rendered speckele field. 8 | % * 'targetArea' - define the sample properties and the wavelength. 9 | % see supporting functions: boxArea. 10 | % * 'views' - define far field views directions or near field views 11 | % positions. 12 | % see supporting functions: farFieldSource, nearFieldSource. 13 | % * 'lights' - define far field lights directions or near field lights 14 | % positions. 15 | % see supporting functions: farFieldSource, nearFieldSource. 16 | % * 'scatter' - define the scattering function of each scatterer. The 17 | % scattering function can be isotropic, Henyey-Greenstein 18 | % (HG),and user defined tabulated function. 19 | % see supporting functions: isotropicScatter, HGScatter, 20 | % tabulatedAmplitudeScatter. 21 | % * 'iterations' - number of mc iterations. 22 | % 23 | % mulRes = scmc(targetArea,views,lights,scatter,iterations,varargin) add 24 | % options to scmc, in pair of field name and value, with the following 25 | % options: 26 | % * 'parforIters' - number of iterations using parfor. Thus the total 27 | % iteartions is parforIters * iterations. The default 28 | % is not using parfor. 29 | % * 'rng' - rng number for random number generator (positive scalar). Not 30 | % possible when using parfor. Default is not using rng. 31 | % * 'CBS' - true= evaluat coherent back scattering. Default: true. 32 | % * 'uniformFirstScatter' - true if the first scatterer is sampled 33 | % uniformly in the target area, otherwise it 34 | % is sampled according to an exponentially 35 | % decaying function of the distance from the 36 | % edge of the target. Default: false. 37 | % * 'renderCov' - true for rendering covariance. 38 | % Default: true. 39 | % * 'singleScattering' - true for returning single scattering 40 | % covariance. Default: false. 41 | % * 'multipleScattering' - true for returning multiple scattering 42 | % covariance. Default: true. 43 | % * 'renderField' - true for sampling a field. 44 | % Default: false. 45 | % 46 | % mulRes = scmc(Config) run the algorithm with pre-calculated Config 47 | % struct, which is returned from scmc.m. 48 | % 49 | % Class support for targetArea, views, lights, scatter: 50 | % struct 51 | % 52 | % Class photonsNum: 53 | % float: double 54 | % 55 | % SEE ALSO: boxArea, nearFieldSource, farFieldSource, tabulatedAmplitudeScatter, HGScatter 56 | % 57 | 58 | %% Check valid input 59 | if(nargin ~= 1) 60 | narginchk(5,inf); 61 | 62 | if(mod(length(varargin),2) ~= 0) 63 | error('Parameters must be in struct of option and value') 64 | end 65 | 66 | if(~strcmp(targetArea.type,'targetArea')) 67 | error('Invalid target area input') 68 | end 69 | 70 | if(~strcmp(views.type,'source')) 71 | error('Invalid views input') 72 | end 73 | 74 | if(~strcmp(lights.type,'source')) 75 | error('Invalid lights input') 76 | end 77 | 78 | if(~strcmp(scatter.type,'scatter')) 79 | error('Invalid scatter input') 80 | end 81 | 82 | if(~isscalar(iterations) || iterations < 1) 83 | error('Invalid photons number') 84 | end 85 | 86 | % measuredFarField must be in 2D 87 | if(strcmp(scatter.function,'measuredFarField') && (targetArea.D == 3)) 88 | error('Measured scattering of far field is used only in 2D') 89 | end 90 | 91 | % tabulated scattering need to fit to its dimensions 92 | % if(strcmp(scatter.function,'tabulated') && (targetArea.D ~= scatter.D)) 93 | % error('Tabulated scattering function is not fit to the area dimensions') 94 | % end 95 | 96 | % scattering 2D / 3D ... 97 | if(targetArea.D == 3) 98 | if isfield(views,'directions3D') 99 | views.directions = views.directions3D; 100 | end 101 | if isfield(views,'positions3D') 102 | views.positions = views.positions3D; 103 | end 104 | 105 | if isfield(lights,'directions3D') 106 | lights.directions = lights.directions3D; 107 | end 108 | if isfield(lights,'positions3D') 109 | lights.positions = lights.positions3D; 110 | end 111 | end 112 | 113 | if(targetArea.D == 2) 114 | if isfield(views,'directions2D') 115 | views.directions = views.directions2D; 116 | end 117 | if isfield(views,'positions2D') 118 | views.positions = views.positions2D; 119 | end 120 | 121 | if isfield(lights,'directions2D') 122 | lights.directions = lights.directions2D; 123 | end 124 | if isfield(lights,'positions2D') 125 | lights.positions = lights.positions2D; 126 | end 127 | end 128 | 129 | %% Build Config 130 | Config.targetArea = targetArea; 131 | Config.views = views; 132 | Config.lights = lights; 133 | Config.scatter = scatter; 134 | Config.render.iterations = iterations; 135 | 136 | %% Default values 137 | Config.parforIters = 1; 138 | Config.rng = -1; 139 | Config.CBS = true; 140 | Config.uniformFirstScatter = false; 141 | Config.render.singleScattering = false; 142 | Config.render.cov = true; 143 | Config.render.singleScattering = false; 144 | Config.render.multipleScattering = true; 145 | Config.render.field = false; 146 | 147 | %% Set preffered values 148 | for optNum = 1:2:length(varargin) 149 | optString = char(varargin{optNum}); 150 | optVal = varargin{optNum + 1}; 151 | 152 | if strcmp(optString,'parforIters') 153 | if(~isscalar(optVal) || optVal < 0) 154 | error('invalid parfor iterations number') 155 | end 156 | 157 | if(Config.rng ~= -1) 158 | error('rng can not be used while using parfor') 159 | end 160 | 161 | Config.parforIters = optVal; 162 | continue; 163 | end 164 | 165 | if strcmp(optString,'rng') 166 | if(~isscalar(optVal) || optVal < 0) 167 | error('invalid rng number') 168 | end 169 | 170 | if(Config.parforIters ~= 1) 171 | error('rng can not be used while using parfor') 172 | end 173 | 174 | Config.rng = optVal; 175 | continue; 176 | end 177 | 178 | if strcmp(optString,'CBS') 179 | if(~isscalar(optVal) || ~islogical(optVal)) 180 | error('CBS must be logical scalar') 181 | end 182 | 183 | Config.CBS = optVal; 184 | continue; 185 | end 186 | 187 | if strcmp(optString,'uniformFirstScatter') 188 | if(~isscalar(optVal) || ~islogical(optVal)) 189 | error('uniformFirstScatter must be logical scalar') 190 | end 191 | 192 | Config.uniformFirstScatter = optVal; 193 | continue; 194 | end 195 | 196 | if strcmp(optString,'renderCov') 197 | if(~isscalar(optVal) || ~islogical(optVal)) 198 | error('renderCov must be logical scalar') 199 | end 200 | 201 | Config.render.cov = optVal; 202 | continue; 203 | end 204 | 205 | if strcmp(optString,'singleScattering') 206 | if(~isscalar(optVal) || ~islogical(optVal)) 207 | error('Single scattering option must be logical scalar') 208 | end 209 | 210 | Config.render.singleScattering = optVal; 211 | 212 | continue; 213 | end 214 | 215 | if strcmp(optString,'multipleScattering') 216 | if(~isscalar(optVal) || ~islogical(optVal)) 217 | error('Multiple scattering option must be logical scalar') 218 | end 219 | 220 | Config.render.multipleScattering = optVal; 221 | 222 | continue; 223 | end 224 | 225 | if strcmp(optString,'renderField') 226 | if(~isscalar(optVal) || ~islogical(optVal)) 227 | error('renderField must be logical scalar') 228 | end 229 | 230 | Config.render.field = optVal; 231 | continue; 232 | end 233 | 234 | error('Invalid option value') 235 | end 236 | else 237 | % in pre-allocated config, the first variable is the config 238 | Config = targetArea; 239 | end 240 | 241 | %% run Monte-Carlo 242 | mulRes.Config = Config; 243 | 244 | % build the parameters for running the algortihms 245 | sigt = 1./Config.targetArea.MFP; 246 | 247 | albedo = Config.scatter.albedo; 248 | 249 | if(strcmp(Config.scatter.function,'isotropic')) 250 | sct_type = 1; 251 | ampfunc = 0; 252 | 253 | covRendParams = 14; 254 | fieldRenderParams = 14; 255 | end 256 | 257 | if(strcmp(Config.scatter.function,'tabulated')) 258 | sct_type = 2; 259 | ampfunc = scatter.ampfunc; 260 | 261 | if(isinf(Config.scatter.ampfunc0)) 262 | covRendParams = 14; 263 | fieldRenderParams = 14; 264 | else 265 | covRendParams = 15; 266 | fieldRenderParams = 15; 267 | 268 | ampfunc0 = Config.scatter.ampfunc0; 269 | end 270 | 271 | 272 | end 273 | 274 | if(strcmp(Config.scatter.function,'HG')) 275 | sct_type = 3; 276 | ampfunc = Config.scatter.g; 277 | 278 | if(isinf(Config.scatter.g0)) 279 | % default value to g0 280 | covRendParams = 14; 281 | fieldRenderParams = 14; 282 | else 283 | covRendParams = 15; 284 | fieldRenderParams = 15; 285 | ampfunc0 = Config.scatter.g0; 286 | end 287 | end 288 | 289 | if(Config.targetArea.D == 3) 290 | box_min = [Config.targetArea.x(1);Config.targetArea.y(1);Config.targetArea.z(1)]; 291 | box_max = [Config.targetArea.x(2);Config.targetArea.y(2);Config.targetArea.z(2)]; 292 | else 293 | box_min = [Config.targetArea.x(1);Config.targetArea.z(1)]; 294 | box_max = [Config.targetArea.x(2);Config.targetArea.z(2)]; 295 | end 296 | 297 | if(Config.lights.farField == 1) 298 | is_ff_l = 1; 299 | l = Config.lights.directions; 300 | else 301 | is_ff_l = 0; 302 | l = Config.lights.positions; 303 | end 304 | 305 | if(Config.views.farField == 1) 306 | is_ff_v = 1; 307 | v = Config.views.directions; 308 | else 309 | is_ff_v = 0; 310 | v = Config.views.positions; 311 | end 312 | 313 | maxItr = Config.render.iterations; 314 | 315 | lambda = Config.targetArea.wavelength; 316 | 317 | doCBS = Config.CBS; 318 | 319 | if(Config.uniformFirstScatter) 320 | smpFlg = 1; 321 | else 322 | smpFlg = 2; 323 | end 324 | 325 | % run cov rendering 326 | if(Config.render.cov) 327 | if(Config.parforIters == 1) 328 | if(Config.rng ~= -1) 329 | rng(Config.rng); 330 | end 331 | 332 | if(covRendParams == 14) 333 | [Ms,Mm] = MCcov( sigt, albedo, box_min, box_max, ... 334 | l, v, is_ff_l, is_ff_v, maxItr, lambda, doCBS, smpFlg, ... 335 | sct_type, ampfunc); 336 | end 337 | 338 | if(covRendParams == 15) 339 | [Ms,Mm] = MCcov( sigt, albedo, box_min, box_max, ... 340 | l, v, is_ff_l, is_ff_v, maxItr, lambda, doCBS, smpFlg, ... 341 | sct_type, ampfunc,ampfunc0); 342 | end 343 | else 344 | 345 | Ms = zeros(Config.views.count, Config.views.count, ... 346 | Config.lights.count, Config.lights.count, Config.parforIters); 347 | Mm = Ms; 348 | 349 | if(covRendParams == 14) 350 | parfor iterNum = 1:1:Config.parforIters 351 | [Ms(:,:,:,:,iterNum),Mm(:,:,:,:,iterNum)] = ... 352 | MCcov( sigt, albedo, box_min, box_max, l, v, ... 353 | is_ff_l, is_ff_v, maxItr, lambda, doCBS, smpFlg, ... 354 | sct_type, ampfunc); 355 | end 356 | end 357 | if(covRendParams == 15) 358 | parfor iterNum = 1:1:Config.parforIters 359 | [Ms(:,:,:,:,iterNum),Mm(:,:,:,:,iterNum)] = ... 360 | MCcov( sigt, albedo, box_min, box_max, l, v, ... 361 | is_ff_l, is_ff_v, maxItr, lambda, doCBS, smpFlg, ... 362 | sct_type, ampfunc, ampfunc0); 363 | end 364 | end 365 | 366 | Ms = mean(Ms,5); 367 | Mm = mean(Mm,5); 368 | end 369 | 370 | if(Config.render.singleScattering) 371 | mulRes.Csingle = Ms; 372 | end 373 | 374 | if(Config.render.multipleScattering) 375 | mulRes.C = Ms + Mm; 376 | end 377 | 378 | end 379 | 380 | % run field rendering 381 | if(Config.render.field) 382 | if(Config.parforIters == 1) 383 | if(Config.rng ~= -1) 384 | rng(Config.rng); 385 | end 386 | 387 | if(fieldRenderParams == 14) 388 | u = MCfield( sigt, albedo, box_min, box_max, l, v, ... 389 | is_ff_l, is_ff_v, maxItr, lambda, doCBS,smpFlg, sct_type, ... 390 | ampfunc); 391 | end 392 | 393 | if(fieldRenderParams == 15) 394 | u = MCfield( sigt, albedo, box_min, box_max, l, v, ... 395 | is_ff_l, is_ff_v, maxItr, lambda, doCBS,smpFlg, sct_type, ... 396 | ampfunc, ampfunc0); 397 | end 398 | else 399 | u = zeros(Config.views.count, Config.lights.count, ... 400 | Config.parforIters); 401 | 402 | if(fieldRenderParams == 14) 403 | parfor iterNum = 1:1:Config.parforIters 404 | u(:,:,iterNum) = MCfield( sigt, ... 405 | albedo, box_min, box_max, l, v, is_ff_l, is_ff_v, ... 406 | maxItr, lambda, doCBS, smpFlg, sct_type, ampfunc); 407 | end 408 | end 409 | 410 | if(fieldRenderParams == 15) 411 | parfor iterNum = 1:1:Config.parforIters 412 | u(:,:,iterNum) = MCfield( sigt, ... 413 | albedo, box_min, box_max, l, v, is_ff_l, is_ff_v, ... 414 | maxItr, lambda, doCBS, smpFlg, sct_type, ampfunc, ampfunc0); 415 | end 416 | end 417 | 418 | % normalize 419 | u = u * sqrt(maxItr); 420 | u = sum(u,3); 421 | u = u./sqrt(maxItr * Config.parforIters); 422 | 423 | end 424 | 425 | mulRes.field = u; 426 | 427 | end 428 | 429 | end 430 | 431 | 432 | --------------------------------------------------------------------------------