11#if !defined(__newimagefns_h)
12#define __newimagefns_h
20#include "armawrap/newmat.h"
21#include "miscmaths/miscmaths.h"
23#include "complexvolume.h"
28#define MAX(a,b) (((a)>(b))?(a):(b))
32#define MIN(a,b) (((a)<(b))?(a):(b))
50 volume<float> abs(
const volume<float>& realvol,
51 const volume<float>& imagvol);
53 volume<float> phase(
const volume<float>& realvol,
54 const volume<float>& imagvol);
56 volume<float> real(
const volume<float>& absvol,
57 const volume<float>& phasevol);
59 volume<float> imag(
const volume<float>& absvol,
60 const volume<float>& phasevol);
64 volume<T> abs(
const volume<T>& vol);
66 template <
class T,
class S>
67 volume<T> divide(
const volume<T>& numervol,
const volume<T>& denomvol,
68 const volume<S>& mask);
70 template <
class T,
class S>
71 volume<T> mask_volume(
const volume<T>& invol,
const volume<S>& mask );
76 void clamp(volume<T>& vol, T minval, T maxval);
80 volume<T> binarise(
const volume<T>& vol, T lowerth, T upperth, threshtype tt=inclusive,
bool invert=
false);
82 volume<T> binarise(
const volume<T>& vol, T thresh,
bool invert=
false);
86 volume<T> threshold(
const volume<T>& vol, T lowerth, T upperth, threshtype tt=inclusive);
88 volume<T> threshold(
const volume<T>& vol, T thresh);
92 volume<T> min(
const volume<T>& v1,
const volume<T>& v2);
94 volume<T> max(
const volume<T>& v1,
const volume<T>& v2);
96 volume<float> sqrt(
const volume<char>& vol);
97 volume<float> sqrt(
const volume<short>& vol);
98 volume<float> sqrt(
const volume<int>& vol);
99 volume<float> sqrt(
const volume<float>& vol);
100 volume<double> sqrt(
const volume<double>& vol);
102 volume<float> sqrt_float(
const volume<T>& vol);
105 volume<float> meanvol(
const volume4D<T>& vol4);
107 volume<float> stddevvol(
const volume4D<T>& vol4);
109 volume<float> variancevol(
const volume4D<T>& vol4);
111 volume<float> sumvol(
const volume4D<T>& vol4);
113 volume<float> sumsquaresvol(
const volume4D<T>& vol4);
115 volume<float> dotproductvol(
const volume4D<T>& vol4,
116 const NEWMAT::ColumnVector& vec);
119 void pad(
const volume<T>& vol, volume<T>& paddedvol);
121 void pad(
const volume<T>& vol, volume<T>& paddedvol,
122 int offsetx,
int offsety,
int offsetz);
126 double dotproduct(
const volume<T>& vol1,
127 const volume<T>& vol2);
128 template <
class T,
class S>
129 double dotproduct(
const volume<T>& vol1,
130 const volume<T>& vol2,
131 const volume<S>& mask);
132 template <
class T,
class S>
133 double dotproduct(
const volume<T>& vol1,
134 const volume<T>& vol2,
135 const volume<S> *mask);
140 double powerdotproduct(
const volume<T>& vol1,
142 const volume<T>& vol2,
144 template <
class T,
class S>
145 double powerdotproduct(
const volume<T>& vol1,
147 const volume<T>& vol2,
149 const volume<S>& mask);
150 template <
class T,
class S>
151 double powerdotproduct(
const volume<T>& vol1,
153 const volume<T>& vol2,
155 const volume<S> *mask);
161 double mean(
const volume<T>& vol);
162 template <
class T,
class S>
163 double mean(
const volume<T>& vol,
164 const volume<S>& mask);
165 template <
class T,
class S>
166 double mean(
const volume<T>& vol,
167 const volume<S> *mask);
170 double sum(
const volume<T>& vol);
171 template <
class T,
class S>
172 double sum(
const volume<T>& vol,
173 const volume<S>& mask);
174 template <
class T,
class S>
175 double sum(
const volume<T>& vol,
176 const volume<S> *mask);
184 void affine_transform(
const volume<T>& vin, volume<T>& vout,
185 const NEWMAT::Matrix& aff,
float paddingsize=0.0);
187 void affine_transform(
const volume<T>& vin, volume<T>& vout,
188 const NEWMAT::Matrix& aff,
float paddingsize,
bool set_backgnd);
191 void affine_transform(
const volume<T>& vin, volume<T>& vout,
192 const NEWMAT::Matrix& aff, interpolation interptype,
193 float paddingsize=0.0);
195 volume<T> affine_transform_mask(
const volume<T>& vin,
const volume<T>& vout,
196 const NEWMAT::Matrix& aff,
float padding=0.0);
199 void get_axis_orientations(
const volume<T>& inp1,
200 int& icode,
int& jcode,
int& kcode);
204 template <
class T,
class S>
205 volume<T> convolve(
const volume<T>& source,
const volume<S>& kernel);
206 template <
class T,
class S>
207 volume<T> convolve_separable(
const volume<T>& source,
208 const NEWMAT::ColumnVector& kernelx,
209 const NEWMAT::ColumnVector& kernely,
210 const NEWMAT::ColumnVector& kernelz);
215 template <
class T,
class S,
class M>
216 volume<T> convolve(
const volume<T>& source,
const volume<S>& kernel,
217 const volume<M>& mask,
bool ignoremask=
false,
bool renormalise=
true);
218 template <
class T,
class M>
219 volume<T> convolve_separable(
const volume<T>& source,
220 const NEWMAT::ColumnVector& kernelx,
221 const NEWMAT::ColumnVector& kernely,
222 const NEWMAT::ColumnVector& kernelz,
223 const volume<M>& mask,
bool ignoremask=
false,
bool renormalise=
true);
226 template <
class T,
class S>
227 volume<T> susan_convolve(volume<T> source,
const volume<S>& kernel,
const float sigmabsq,
const bool use_median,
int num_usan,volume<T>* usan_area =
new volume<T>(1,1,1),volume<T> usan_vol1=volume<T>(1,1,1),
const float sigmab1sq=0,volume<T> usan_vol2 = volume<T>(1,1,1),
const float sigmab2sq=0);
229 template <
class T,
class S>
230 volume4D<T> generic_convolve(
const volume4D<T>& source,
const volume<S>& kernel,
bool seperable=
false,
bool renormalise=
true);
231 template <
class T,
class S>
232 volume<T> efficient_convolve(
const volume<T>& vin,
const volume<S>& vker);
233 template <
class T,
class S>
234 int insertpart(volume<T>& v1,
const volume<S>& v2);
235 template <
class T,
class S,
class U>
236 volume<S> extractpart(
const volume<T>& v1,
const volume<S>& v2,
const volume<U>& kernel) ;
237 float fsllog2(
float x);
241 volume4D<T> bandpass_temporal_filter(volume4D<T>& source,
double hp_sigma,
double lp_sigma);
244 template <
class T,
class S>
245 volume<T> morphfilter(
const volume<T>& source,
const volume<S>& kernel,
246 const std::string& filtertype);
249 volume<T> dilall(
const volume<T>& im, volume<T>& mask);
251 volume<T> fill_holes(
const volume<T>& im,
int connectivity=6);
254 volume<T> isotropic_resample(
const volume<T>& aniso,
float scale);
257 volume<T> subsample_by_2(
const volume<T>& refvol,
bool centred=
true);
259 int upsample_by_2(volume<T>& highresvol,
const volume<T>& lowresvol,
262 volume<T> upsample_by_2(
const volume<T>& lowresvol,
bool centred=
true);
265 void make_blur_mask(NEWMAT::ColumnVector& bmask,
const float final_vox_dim,
266 const float init_vox_dim);
268 volume<T> blur(
const volume<T>& source,
const NEWMAT::ColumnVector& resel_size);
270 volume<T> blur(
const volume<T>& source,
float iso_resel_size);
278 NEWMAT::ColumnVector gaussian_kernel1D(
float sigma,
int radius);
279 volume<float> gaussian_kernel2D(
float sigma,
int radius);
280 volume<float> gaussian_kernel3D(
float sigma,
int radius);
281 volume<float> gaussian_kernel3D(
float sigma,
float xdim,
float ydim,
float zdim,
float cutoff=4.0);
282 volume<float> spherical_kernel(
float radius,
float xdim,
float ydim,
float zdim);
283 volume<float> box_kernel(
float length,
float xdim,
float ydim,
float zdim);
284 volume<float> box_kernel(
int x,
int y,
int z);
286 void make_grad_masks(volume<float>& maskx, volume<float>& masky,
287 volume<float>& maskz);
290 volume<float> gradient(
const volume<T>& source);
293 void gradient(
const volume<T>& source,volume<float>& grad);
297 volume4D<float> lrxgrad(
const volume<float>& im,
const volume<T>& mask);
299 volume4D<float> lrygrad(
const volume<float>& im,
const volume<T>& mask);
301 volume4D<float> lrzgrad(
const volume<float>& im,
const volume<T>& mask);
305 volume<T> log_edge_detect(
const volume<T>& source,
306 float sigma1,
float sigma2,
309 volume<T> fixed_edge_detect(
const volume<T>& source,
float threshold,
310 bool twodimensional=
false);
312 volume4D<T> edge_strengthen(
const volume4D<T>& source);
317 volume<int> connected_components(
const volume<T>& vol, NEWMAT::ColumnVector& clustersize,
int numconnected=26);
320 volume<int> connected_components(
const volume<T>& vol,
321 const volume<T>& mask,
322 bool (*binaryrelation)(T , T), NEWMAT::ColumnVector& clustersize);
325 volume<int> connected_components(
const volume<T>& vol,
326 int numconnected=26);
328 volume<int> connected_components(
const volume<T>& vol,
329 const volume<T>& mask,
330 bool (*binaryrelation)(T , T));
333 volume<float> distancemap(
const volume<T>& binaryvol);
335 volume<float> distancemap(
const volume<T>& binaryvol,
const volume<T>& mask);
338 volume4D<float> sparseinterpolate(
const volume4D<T>& sparsesamps,
339 const volume<T>& mask,
340 const std::string& interpmethod=
"general");
345 NEWMAT::Matrix NewimageVox2NewimageVoxMatrix(
const NEWMAT::Matrix& flirt_in2ref,
346 const volume<T>& invol,
const volume<T>& refvol);
354 void print_volume_info(
const volume<T>& source,
const std::string& name, std::ostream& output=std::cout)
356 output << name <<
":: Size = (" << source.xsize() <<
","
357 << source.ysize() <<
"," << source.zsize() <<
"," << source.tsize() <<
")" << std::endl;
358 output << name <<
":: Dims = (" << source.xdim() <<
","
359 << source.ydim() <<
"," << source.zdim() <<
"," << source.tdim() <<
")" << std::endl;
360 output << name <<
":: ROI Size = (" << source.maxx() - source.minx() + 1
361 <<
"," << source.maxy() - source.miny() + 1
362 <<
"," << source.maxz() - source.minz() + 1
363 <<
"," << source.maxt() - source.mint() + 1 <<
")" << std::endl;
364 output << name <<
":: Minimum and maximum intensities are: "
365 << source.min() <<
" and " << source.max() << std::endl;
373 void clamp(volume<T>& vol, T minval, T maxval)
375 if (maxval < minval)
return;
376 for (
typename volume<T>::nonsafe_fast_iterator it=vol.nsfbegin(), itEnd=vol.nsfend(); it < itEnd; it++ ) {
379 else if ( *it < minval )
385 volume<T> abs(
const volume<T>& vol)
387 volume<T> newvol(vol);
388 for (
typename volume<T>::nonsafe_fast_iterator it=newvol.nsfbegin(), itEnd=newvol.nsfend(); it < itEnd; it++ ) {
389 *it = (T)fabs( (
double)*it );
395 volume<T> binarise(
const volume<T>& vol, T lowerth, T upperth, threshtype tt,
bool invert)
397 volume<T> newvol(vol);
398 newvol.binarise(lowerth,upperth,tt,invert);
403 volume<T> binarise(
const volume<T>& vol, T lowthresh,
bool invert)
405 return binarise(vol,lowthresh,vol.max(),inclusive, invert);
409 volume<T> threshold(
const volume<T>& vol, T lowerth, T upperth, threshtype tt)
411 volume<T> newvol(vol);
412 newvol.threshold(lowerth,upperth,tt);
417 volume<T> threshold(
const volume<T>& vol, T thresh)
419 return threshold(vol,thresh,vol.max(),inclusive);
423 volume<T> min(
const volume<T>& v1,
const volume<T>& v2)
425 if (!samesize(v1,v2)) {
426 imthrow(
"Must use volumes of same size in min(v1,v2)",3);
428 volume<T> newvol(v1,
false);
429 typename volume<T>::nonsafe_fast_iterator it=newvol.nsfbegin();
430 for (
typename volume<T>::fast_const_iterator v1it=v1.fbegin(), v1itEnd=v1.fend(), v2it=v2.fbegin(); v1it < v1itEnd; it++, v1it++, v2it++ )
431 *it=MISCMATHS::Min( *v1it, *v2it );
436 volume<T> max(
const volume<T>& v1,
const volume<T>& v2)
438 if (!samesize(v1,v2)) {
439 imthrow(
"Must use volumes of same size in max(v1,v2)",3);
442 copyconvert(v1, newvol,
false);
443 typename volume<T>::nonsafe_fast_iterator it=newvol.nsfbegin();
444 for (
typename volume<T>::fast_const_iterator v1it=v1.fbegin(), v1itEnd=v1.fend(), v2it=v2.fbegin(); v1it < v1itEnd; it++, v1it++, v2it++ )
445 *it=MISCMATHS::Max( *v1it, *v2it );
450 volume<float> sqrt_float(
const volume<T>& vol)
452 volume<float> retvol;
453 copyconvert(vol, retvol,
false);
454 typename volume<float>::nonsafe_fast_iterator it=retvol.nsfbegin();
455 for (
typename volume<T>::fast_const_iterator vit=vol.fbegin(), vend=vol.fend(); vit < vend; it++, vit++ ) {
457 *it=sqrt( (
double) *vit);
465 volume<float> sumvol(
const volume<T>& vol4)
467 if (vol4.tsize()<1) { volume<float> newvol;
return newvol; }
468 volume<float> SumVol, dummy;
469 copyconvert(vol4.constSubVolume(0),SumVol);
470 for (
int ctr= 1; ctr < vol4.tsize(); ctr++) {
471 copyconvert(vol4.constSubVolume(ctr),dummy);
479 volume<float> meanvol(
const volume<T>& vol4)
481 if (vol4.tsize()<1) { volume<float> newvol;
return newvol; }
482 volume<float> MeanVol = sumvol(vol4) / (float)vol4.tsize();
488 volume<float> sumsquaresvol(
const volume<T>& vol4)
490 if (vol4.tsize()<1) { volume<float> newvol;
return newvol; }
491 volume<float> SumSq, dummy;
492 copyconvert( vol4.constSubVolume(0) * vol4.constSubVolum(0) , SumSq);
493 for (
int ctr=1; ctr < vol4.tsize(); ctr++) {
494 copyconvert( vol4.constSubVolume(ctr) * vol4.constSubVolume(ctr), dummy);
502 volume<float> variancevol(
const volume<T>& vol4)
504 volume<float> variance;
507 volume<float> Mean = meanvol(vol4);
508 variance = Mean*0.0f;
510 for (
int z=0; z<vol4.zsize(); z++)
511 for (
int y=0; y<vol4.ysize(); y++)
512 for (
int x=0; x<vol4.xsize(); x++) {
514 for (
int t=0; t<vol4.tsize(); t++)
515 total+=pow(vol4(x,y,z,t)-Mean(x,y,z),2.0);
516 variance(x,y,z)=(float)total;
518 variance /= (float) (vol4.tsize()-1.0);
523 volume<float> stddevvol(
const volume<T>& vol4)
525 if (vol4.tsize()<1) { volume<float> newvol;
return newvol; }
526 volume<float> StdVol = variancevol(vol4);
527 for (
int z=0; z<StdVol.zsize(); z++)
528 for (
int y=0; y<StdVol.ysize(); y++)
529 for (
int x=0; x<StdVol.xsize(); x++)
530 StdVol(x,y,z) = sqrt(StdVol(x,y,z));
536 volume<float> dotproductvol(
const volume4D<T>& vol4,
537 const NEWMAT::ColumnVector& vec)
539 if (vol4.mint()<0) { volume<float> newvol;
return newvol; }
540 if ( vol4.tsize() != vec.Nrows() )
542 std::cerr <<
"ERROR::Time series length differs from vector length in"
543 <<
" dotproductvol()" << std::endl;
544 volume<float> newvol;
return newvol;
546 volume<float> vol4copy;
547 copyconvert(vol4[vol4.mint()],vol4copy);
548 volume<float> DotVol(vol4copy);
549 DotVol *= (float) vec(1);
550 for (
int n=vol4.mint() + 1; n <= vol4.maxt(); n++) {
551 copyconvert(vol4[n],vol4copy);
552 DotVol += (vol4copy * (float) vec(1 + n - vol4.mint()));
559 void pad(
const volume<T>& vol, volume<T>& paddedvol)
562 if ( ( paddedvol.xsize() < vol.xsize() ) || ( paddedvol.ysize() < vol.ysize() ) || ( paddedvol.zsize() < vol.zsize() ) ) {
563 imthrow(
"Cannot pad when target volume is smaller than original",7);
565 int64_t offx = ( paddedvol.xsize() - vol.xsize() ) / 2;
566 int64_t offy = ( paddedvol.ysize() - vol.ysize() ) / 2;
567 int64_t offz = ( paddedvol.zsize() - vol.zsize() ) / 2;
568 pad(vol,paddedvol,offx,offy,offz);
572 double dotproduct(
const volume<T>& vol1,
573 const volume<T>& vol2)
575 if (!samesize(vol1,vol2,
true)) imthrow(
"dotproduct: Image dimension mismatch",99);
578 for (
typename volume<T>::fast_const_iterator it1=vol1.fbegin(), it_end=vol1.fend(), it2=vol2.fbegin(); it1 != it_end; ++it1, ++it2) {
579 rval +=
static_cast<double>((*it1)*(*it2));
584 template <
class T,
class S>
585 double dotproduct(
const volume<T>& vol1,
586 const volume<T>& vol2,
587 const volume<S>& mask)
589 if (!samesize(vol1,vol2,
true) || !samesize(vol1,mask,
true)) imthrow(
"dotproduct: Image dimension mismatch",99);
592 typename volume<S>::fast_const_iterator itm = mask.fbegin();
593 for (
typename volume<T>::fast_const_iterator it1=vol1.fbegin(), it_end=vol1.fend(), it2=vol2.fbegin(); it1 != it_end; ++it1, ++it2, ++itm) {
595 rval +=
static_cast<double>((*it1)*(*it2));
601 template <
class T,
class S>
602 double dotproduct(
const volume<T>& vol1,
603 const volume<T>& vol2,
604 const volume<S> *mask)
606 if (mask)
return(dotproduct(vol1,vol2,*mask));
607 else return(dotproduct(vol1,vol2));
611 double powerdotproduct(
const volume<T>& vol1,
613 const volume<T>& vol2,
616 if (!samesize(vol1,vol2,
true)) imthrow(
"powerdotproduct: Image dimension mismatch",99);
619 for (
typename volume<T>::fast_const_iterator it1=vol1.fbegin(), it_end=vol1.fend(), it2=vol2.fbegin(); it1 != it_end; ++it1, ++it2) {
621 for (
unsigned int i=0; i<n1; i++) val1 *= *it1;
623 for (
unsigned int i=0; i<n2; i++) val2 *= *it2;
624 rval +=
static_cast<double>(val1*val2);
629 template <
class T,
class S>
630 double powerdotproduct(
const volume<T>& vol1,
632 const volume<T>& vol2,
634 const volume<S>& mask)
636 if (!samesize(vol1,vol2,
true) || !samesize(vol1,mask,
true)) imthrow(
"powerdotproduct: Image dimension mismatch",99);
639 typename volume<S>::fast_const_iterator itm = mask.fbegin();
640 for (
typename volume<T>::fast_const_iterator it1=vol1.fbegin(), it_end=vol1.fend(), it2=vol2.fbegin(); it1 != it_end; ++it1, ++it2, ++itm) {
643 for (
unsigned int i=0; i<n1; i++) val1 *= *it1;
645 for (
unsigned int i=0; i<n2; i++) val2 *= *it2;
646 rval +=
static_cast<double>(val1*val2);
652 template <
class T,
class S>
653 double powerdotproduct(
const volume<T>& vol1,
655 const volume<T>& vol2,
657 const volume<S> *mask)
659 if (mask)
return(powerdotproduct(vol1,n1,vol2,n2,*mask));
660 else return(powerdotproduct(vol1,n1,vol2,n2));
664 double mean(
const volume<T>& vol)
666 double rval = sum(vol);
667 rval /=
static_cast<double>( vol.totalElements() );
671 template <
class T,
class S>
672 double mean(
const volume<T>& vol,
673 const volume<S>& mask)
675 if (!samesize(vol,mask,
true)) imthrow(
"mean: Image-Mask dimension mismatch",99);
679 typename volume<S>::fast_const_iterator itm = mask.fbegin();
680 for (
typename volume<T>::fast_const_iterator it=vol.fbegin(), it_end=vol.fend(); it != it_end; ++it, ++itm) {
683 rval +=
static_cast<double>(*it);
686 rval /=
static_cast<double>(n);
690 template <
class T,
class S>
691 double mean(
const volume<T>& vol,
692 const volume<S> *mask)
694 if (mask)
return(mean(vol,*mask));
695 else return(mean(vol));
699 double sum(
const volume<T>& vol)
702 for (
typename volume<T>::fast_const_iterator it=vol.fbegin(), it_end=vol.fend(); it != it_end; ++it) {
703 rval +=
static_cast<double>(*it);
708 template <
class T,
class S>
709 double sum(
const volume<T>& vol,
710 const volume<S>& mask)
712 if (!samesize(vol,mask,
true)) imthrow(
"sum: Image-Mask dimension mismatch",99);
715 typename volume<S>::fast_const_iterator itm = mask.fbegin();
716 for (
typename volume<T>::fast_const_iterator it=vol.fbegin(), it_end=vol.fend(); it != it_end; ++it, ++itm) {
718 rval +=
static_cast<double>(*it);
724 template <
class T,
class S>
725 double sum(
const volume<T>& vol,
726 const volume<S> *mask)
728 if (mask)
return(sum(vol,*mask));
729 else return(sum(vol));
732 template <
class T,
class S>
733 volume<T> divide(
const volume<T>& numervol,
const volume<T>& denomvol,
734 const volume<S>& mask)
736 if ((!samesize(numervol,denomvol)) || (!samesize(mask,denomvol,SUBSET))) {
737 imthrow(
"Attempted to divide images of different sizes",3);
739 volume<T> resvol(numervol);
741 typename volume<S>::fast_const_iterator maskIt = mask.fbegin(), maskEnd=mask.fend();
742 typename volume<T>::nonsafe_fast_iterator it=resvol.nsfbegin();
743 for (
typename volume<T>::fast_const_iterator itd=denomvol.fbegin(), itd_end=denomvol.fend(); itd != itd_end; ++it, ++itd, maskIt++) {
744 if ( *maskIt != 0 ) {
749 if ( maskIt == maskEnd )
750 maskIt=mask.fbegin();
757template <
class T,
class S>
758 volume<T> mask_volume(
const volume<T>& invol,
const volume<S>& mask)
760 if ( !samesize(invol,mask,SUBSET)) {
761 imthrow(
"Attempted to mask_volume with wrong sized mask",3);
763 volume<T> resvol(invol,
false);
765 typename volume<S>::fast_const_iterator maskIt = mask.fbegin(), maskEnd=mask.fend();
766 typename volume<T>::nonsafe_fast_iterator itr=resvol.nsfbegin();
767 for (
typename volume<T>::fast_const_iterator it=invol.fbegin(), it_end=invol.fend(); it != it_end; ++it, ++itr, maskIt++) {
768 if ( *maskIt != 0 ) {
773 if ( maskIt == maskEnd )
774 maskIt=mask.fbegin();
782 void raw_affine_transform(
const volume<T>& vin, volume<T>& vout,
783 const NEWMAT::Matrix& aff);
786 void affine_transform_mask(
const volume<T>& vin, volume<T>& vout,
787 const NEWMAT::Matrix& aff,
float padding,
const T padval);
790 volume<T> affine_transform_mask(
const volume<T>& vin,
const volume<T>& vout,
791 const NEWMAT::Matrix& aff,
float padding)
796 affine_transform_mask(vin,affmask,aff,padding,(T) 0);
802 void affine_transform(
const volume<T>& vin, volume<T>& vout,
803 const NEWMAT::Matrix& aff,
float paddingsize,
bool set_backgnd)
808 padval = vin.getpadvalue();
809 oldex = vin.getextrapolationmethod();
810 vin.setpadvalue(vin.backgroundval());
811 vin.setextrapolationmethod(extraslice);
815 raw_affine_transform(vin,vout,aff);
817 affine_transform_mask(vin,vout,aff,paddingsize,vin.getpadvalue());
819 vin.setpadvalue(padval);
820 vin.setextrapolationmethod(oldex);
825 void affine_transform(
const volume<T>& vin, volume<T>& vout,
826 const NEWMAT::Matrix& aff,
float paddingsize)
828 affine_transform(vin,vout,aff,paddingsize,
true);
832 void affine_transform(
const volume<T>& vin, volume<T>& vout,
833 const NEWMAT::Matrix& aff, interpolation interptype,
836 interpolation oldinterp;
837 oldinterp = vin.getinterpolationmethod();
838 vin.setinterpolationmethod(interptype);
839 affine_transform(vin,vout,aff,paddingsize);
840 vin.setinterpolationmethod(oldinterp);
847 template <
class T,
class S>
848 volume<T> susan_convolve(
const volume<T> source,
const volume<S>& kernel,
const float sigmabsq,
const bool use_median,
int num_usan,volume<T>* usan_area,volume<T> usan_vol1,
const float sigmab1sq,volume<T> usan_vol2,
const float sigmab2sq)
857 if ( (( (kernel.maxz() - kernel.minz()) % 2)==1) ||
858 (( (kernel.maxy() - kernel.miny()) % 2)==1) ||
859 (( (kernel.maxx() - kernel.minx()) % 2)==1) )
860 std::cerr <<
"WARNING:: Off-centre convolution being performed as kernel has even dimensions" << std::endl;
861 if ((num_usan>=1 && !samesize(source,usan_vol1)) || (num_usan>=2 && !samesize(source,usan_vol2)) || (num_usan>=1 && !samesize(source,*usan_area)) )
863 std::cerr <<
"Warning: an external usan or output usan is not the same size as the source image, reverting to num_usans=0 mode" << std::endl;
866 int midx, midy, midz,lz,uz,lx,ux,ly,uy,lutsize=16384;
873 volume<T> result(source);
874 midz=(kernel.maxz() - kernel.minz())/2;
875 midy=(kernel.maxy() - kernel.miny())/2;
876 midx=(kernel.maxx() - kernel.minx())/2;
878 float range1=1,range2=1,range = (source.max() - source.min())/(
float)lutsize;
879 float **lut=
new float *[3];
880 for(
int i=0;i<=num_usan;i++) lut[i]=
new float[2*lutsize+1];
881 for(
int i=0;i<=num_usan;i++) lut[i]+=lutsize;
882 for (
int i=0;i<=lutsize;i++) lut[0][-i]=lut[0][i]= exp(-pow(i*range,2.0)/sigmabsq);
885 range1= (usan_vol1.max() - usan_vol1.min())/(
float)lutsize;
886 for (
int i=0;i<=lutsize;i++) lut[1][-i]=lut[1][i]= exp(-pow(i*range1,2.0)/sigmab1sq);
890 range2= (usan_vol2.max() - usan_vol2.min())/(
float)lutsize;
891 for (
int i=0;i<=lutsize;i++) lut[2][-i]=lut[2][i]= exp(-pow(i*range2,2.0)/sigmab2sq);
893 NEWMAT::ColumnVector mediankernel((kernel.zsize()>1)?26:8);
894 int medoffst=((kernel.zsize()>1)?1:0);
895 for (
int z=lz; z<=uz; z++)
896 for (
int y=ly; y<=uy; y++)
897 for (
int x=lx; x<=ux; x++)
899 int xmin=x-midx,ymin=y-midy,zmin=z-midz;
900 int xmax=MIN(x+midx,ux),ymax=MIN(y+midy,uy),zmax=MIN(z+midz,uz);
901 float num=0, denom=0,center_val1=0,center_val2=0,factor;
902 float center_val=source.value(x,y,z);
903 if (num_usan>=1) center_val1=usan_vol1.value(x,y,z);
904 if (num_usan>=2) center_val2=usan_vol2.value(x,y,z);
905 for(
int mz=MAX(zmin,lz); mz<=zmax; mz++)
906 for(
int my=MAX(ymin,ly); my<=ymax; my++)
907 for(
int mx=MAX(xmin,lx); mx<=xmax; mx++)
908 if ((factor=(
float)kernel.value(mx-xmin,my-ymin,mz-zmin)))
910 if (num_usan==0) factor*= lut[0][(int)((source.value(mx,my,mz)-center_val)/range)];
911 else factor*= lut[1][(int)((usan_vol1.value(mx,my,mz)-center_val1)/range1)];
912 if (num_usan>=2) factor*=lut[2][(int)((usan_vol2.value(mx,my,mz)-center_val2)/range2)];
913 num+=source.value(mx,my,mz) * factor;
916 if (num_usan>=1) usan_area->value(x,y,z)=(T) denom;
917 if (use_median && denom<1.5)
920 for(
int x2=MAX(x-1,lx);x2<=MIN(x+1,ux);x2++)
921 for(
int y2=MAX(y-1,ly);y2<=MIN(y+1,uy);y2++)
922 for(
int z2=MAX(z-medoffst,lz);z2<=MIN(z+medoffst,uz);z2++)
923 if ( (x2-x) || (y2-y) || (z2-z) ) mediankernel(count++)=source.value(x2,y2,z2);
924 NEWMAT::ColumnVector subkernel = mediankernel.SubMatrix(1,count-1,1,1);
925 SortAscending(subkernel);
926 result(x,y,z) = (T)((subkernel(count/2)+subkernel((count+1)/2))/2.0);
928 else result.value(x,y,z)=(T) (num/denom);
930 for(
int i=0;i<=num_usan;i++)
delete[] (lut[i]-lutsize);
935 template <
class T,
class S>
936 volume<T> convolve(
const volume<T>& source,
const volume<S>& kernel)
938 extrapolation oldex = source.getextrapolationmethod();
940 if ((oldex==boundsassert) || (oldex==boundsexception))
941 { source.setextrapolationmethod(constpad); }
942 volume<T> result(source);
943 if ( (kernel.zsize()%2==0) || (kernel.ysize()%2==0) || (kernel.xsize()%2==0) )
945 std::cerr <<
"WARNING:: Off-centre convolution being performed as kernel"
946 <<
" has even dimensions" << std::endl;
951 int midx, midy, midz;
952 midz=(kernel.zsize()-1)/2 + offset;
953 midy=(kernel.ysize()-1)/2 + offset;
954 midx=(kernel.xsize()-1)/2 + offset;
957 for (
int z=0; z<result.zsize(); z++)
958 for (
int y=0; y<result.ysize(); y++)
959 for (
int x=0; x<result.xsize(); x++) {
961 for (
int mz=0; mz<kernel.zsize(); mz++)
962 for (
int my=0; my<kernel.ysize(); my++)
963 for (
int mx=0; mx<kernel.xsize(); mx++) {
964 val+=source(x+mx-midx,y+my-midy,z+mz-midz) * kernel(mx,my,mz);
966 result(x,y,z)=(T) val;
970 source.setextrapolationmethod(oldex);
974 template <
class T,
class S,
class M>
975 volume<T> convolve(
const volume<T>& source,
const volume<S>& kernel,
976 const volume<M>& mask,
bool ignoremask,
bool renormalise)
978 if (!ignoremask && !samesize(mask, source))
979 imthrow(
"convolve: mask and source are not the same size",10);
981 if ( (( (kernel.maxz() - kernel.minz()) % 2)==1) ||
982 (( (kernel.maxy() - kernel.miny()) % 2)==1) ||
983 (( (kernel.maxx() - kernel.minx()) % 2)==1) )
985 std::cerr <<
"WARNING:: Off-centre convolution being performed as kernel"
986 <<
" has even dimensions" << std::endl;
988 volume<T> result(source);
989 int midx, midy, midz;
990 int lz,uz,lx,ux,ly,uy;
997 midz=(kernel.maxz() - kernel.minz())/2;
998 midy=(kernel.maxy() - kernel.miny())/2;
999 midx=(kernel.maxx() - kernel.minx())/2;
1000 for (
int z=lz; z<=uz; z++)
1001 for (
int y=ly; y<=uy; y++)
1002 for (
int x=lx; x<=ux; x++)
1003 if (ignoremask || mask(x,y,z)>0.5)
1005 float val(0),norm(0);
1010 for (
int mz=kernel.minz(); mz<=kernel.maxz(); mz++)
1011 for (
int my=kernel.miny(); my<=kernel.maxy(); my++)
1012 for (
int mx=kernel.minx(); mx<=kernel.maxx(); mx++)
1018 if ((ignoremask && (x2<=ux && x2>=lx && y2<=uy && y2>=ly && z2<=uz && z2>=lz)) || (!ignoremask && mask(x2,y2,z2)>0.5))
1020 val+=source.value(x2,y2,z2) * kernel.value(mx,my,mz);
1021 norm+=kernel.value(mx,my,mz);
1024 if (renormalise && fabs(norm)>1e-12) result.value(x,y,z)=(T) (val/norm);
1025 else result.value(x,y,z)=(T) val;
1031 volume<T> convolve_separable(
const volume<T>& source,
1032 const NEWMAT::ColumnVector& kernelx,
1033 const NEWMAT::ColumnVector& kernely,
1034 const NEWMAT::ColumnVector& kernelz)
1036 volume<T> result(source);
1037 volume<double> kerx(kernelx.Nrows(),1,1);
1038 volume<double> kery(1,kernely.Nrows(),1);
1039 volume<double> kerz(1,1,kernelz.Nrows());
1040 for (
int n=1; n<=kernelx.Nrows(); n++) kerx.value(n-1,0,0) = kernelx(n);
1041 for (
int n=1; n<=kernely.Nrows(); n++) kery.value(0,n-1,0) = kernely(n);
1042 for (
int n=1; n<=kernelz.Nrows(); n++) kerz.value(0,0,n-1) = kernelz(n);
1043 result = convolve(result,kerx);
1044 result = convolve(result,kery);
1045 result = convolve(result,kerz);
1049 template <
class T,
class M>
1050 volume<T> convolve_separable(
const volume<T>& source,
1051 const NEWMAT::ColumnVector& kernelx,
1052 const NEWMAT::ColumnVector& kernely,
1053 const NEWMAT::ColumnVector& kernelz,
1054 const volume<M>& mask,
bool ignoremask,
bool renormalise)
1056 volume<T> result(source);
1057 volume<double> kerx(kernelx.Nrows(),1,1);
1058 volume<double> kery(1,kernely.Nrows(),1);
1059 volume<double> kerz(1,1,kernelz.Nrows());
1060 for (
int n=1; n<=kernelx.Nrows(); n++) kerx.value(n-1,0,0) = kernelx(n);
1061 for (
int n=1; n<=kernely.Nrows(); n++) kery.value(0,n-1,0) = kernely(n);
1062 for (
int n=1; n<=kernelz.Nrows(); n++) kerz.value(0,0,n-1) = kernelz(n);
1063 result = convolve(result,kerx,mask,ignoremask,renormalise);
1064 result = convolve(result,kery,mask,ignoremask,renormalise);
1065 result = convolve(result,kerz,mask,ignoremask,renormalise);
1072 template <
class T,
class S>
1073 volume<T> morphfilter(
const volume<T>& source,
const volume<S>& kernel,
1074 const std::string& filtertype)
1079 extrapolation oldex = source.getextrapolationmethod();
1080 if ((oldex==boundsassert) || (oldex==boundsexception))
1081 { source.setextrapolationmethod(constpad); }
1082 volume<T> result(source);
1087 volume<S> dummy(kernel);
1088 dummy.binarise((S)0.5);
1089 nker = (int) dummy.sum();
1092 int midx, midy, midz;
1093 if ( (( (kernel.maxz() - kernel.minz()) % 2)==1) ||
1094 (( (kernel.maxy() - kernel.miny()) % 2)==1) ||
1095 (( (kernel.maxx() - kernel.minx()) % 2)==1) )
1097 std::cerr <<
"WARNING:: Off-centre morphfilter being performed as kernel"
1098 <<
" has even dimensions" << std::endl;
1100 midz=(kernel.maxz() - kernel.minz())/2;
1101 midy=(kernel.maxy() - kernel.miny())/2;
1102 midx=(kernel.maxx() - kernel.minx())/2;
1105 for (
int z=result.minz(); z<=result.maxz(); z++) {
1106 for (
int y=result.miny(); y<=result.maxy(); y++) {
1107 for (
int x=result.minx(); x<=result.maxx(); x++) {
1108 NEWMAT::ColumnVector vals(nker);
1110 for (
int mz=MISCMATHS::Max(kernel.minz(),result.minz()-z+midz);
1111 mz<=MISCMATHS::Min(kernel.maxz(),result.maxz()-z+midz); mz++) {
1112 for (
int my=MISCMATHS::Max(kernel.miny(),result.miny()-y+midy);
1113 my<=MISCMATHS::Min(kernel.maxy(),result.maxy()-y+midy); my++) {
1114 for (
int mx=MISCMATHS::Max(kernel.minx(),result.minx()-x+midx);
1115 mx<=MISCMATHS::Min(kernel.maxx(),result.maxx()-x+midx); mx++) {
1116 if (kernel(mx,my,mz)>0.5) {
1117 if ((filtertype!=
"dilateM" && filtertype!=
"dilateD") || source(x+mx-midx,y+my-midy,z+mz-midz)) vals(count++) = source(x+mx-midx,y+my-midy,z+mz-midz);
1123 NEWMAT::ColumnVector littlevals;
1124 littlevals = vals.SubMatrix(1,count-1,1,1);
1125 if (filtertype==
"median") {
1126 SortAscending(littlevals);
1127 result(x,y,z) = (T)littlevals(MISCMATHS::Max(1,(count+1)/2));
1128 }
else if ((filtertype==
"max") || (filtertype==
"dilate")) result(x,y,z) = (T)littlevals.Maximum();
1129 else if ((filtertype==
"min") || (filtertype==
"erode")) result(x,y,z) = (T)littlevals.Minimum();
1130 else if (filtertype==
"erodeS") {
if (source(x,y,z)!=0 && littlevals.Minimum()==0) result(x,y,z) = 0;
else result(x,y,z) = source(x,y,z);}
1131 else if (filtertype==
"dilateM") {
if (source(x,y,z)==0) result(x,y,z) = (T)(littlevals.Sum()/--count);
else result(x,y,z) = source(x,y,z);}
1132 else if (filtertype==
"dilateD") {
if (source(x,y,z)==0){
1133 SortDescending(littlevals);
1134 double max=littlevals(1);
1136 double current=littlevals(1);
1138 for(
int i=2;i<count;i++)
1140 if (littlevals(i)==current) currentn++;
1143 current=littlevals(i);
1146 max=littlevals(i-1);
1152 result(x,y,z) = (T)max;}
else result(x,y,z) = source(x,y,z);
1154 else imthrow(
"morphfilter:: Filter type " + filtertype +
"unsupported",7);
1155 }
else result(x,y,z) = source(x,y,z);
1159 source.setextrapolationmethod(oldex);
1164 double dilateval(
const volume<T>& im,
const volume<T>& mask,
int x,
int y,
int z)
1168 for (
int zz=MISCMATHS::Max(0,z-1); zz<=MISCMATHS::Min(z+1,im.maxz()); zz++) {
1169 for (
int yy=MISCMATHS::Max(0,y-1); yy<=MISCMATHS::Min(y+1,im.maxy()); yy++) {
1170 for (
int xx=MISCMATHS::Max(0,x-1); xx<=MISCMATHS::Min(x+1,im.maxx()); xx++) {
1171 if ((mask(xx,yy,zz)>(T) 0.5) && !((xx==x) && (yy==y) && (zz==z))) {
1172 sum += im(xx,yy,zz);
1178 return sum/(MISCMATHS::Max(n,1));
1183 bool ext_edge(
const volume<T>& mask,
int x,
int y,
int z)
1185 if (mask(x,y,z)>(T) 0.5) {
return false; }
1186 for (
int zz=MISCMATHS::Max(0,z-1); zz<=MISCMATHS::Min(z+1,mask.maxz()); zz++) {
1187 for (
int yy=MISCMATHS::Max(0,y-1); yy<=MISCMATHS::Min(y+1,mask.maxy()); yy++) {
1188 for (
int xx=MISCMATHS::Max(0,x-1); xx<=MISCMATHS::Min(x+1,mask.maxx()); xx++) {
1189 if ((mask(xx,yy,zz)>(T) 0.5) && !((xx==x) && (yy==y) && (zz==z))) {
1205 if (!samesize(input,mask)) { std::cerr <<
"ERROR::dilall::image are not the same size" << std::endl; }
1206 std::deque<vec3_temp> ptlist;
1209 for (
int z=0; z<=im.maxz(); z++) {
1210 for (
int y=0; y<=im.maxy(); y++) {
1211 for (
int x=0; x<=im.maxx(); x++) {
1212 if (ext_edge(mask,x,y,z)) {
1213 v.x=x; v.y=y; v.z=z;
1214 ptlist.push_front(v);
1219 while (!ptlist.empty()) {
1222 if (mask(v.x,v.y,v.z)<=(T) 0.5) {
1223 im(v.x,v.y,v.z)=dilateval(im,mask,v.x,v.y,v.z);
1224 mask(v.x,v.y,v.z)=(T)1;
1226 for (
int zz=MISCMATHS::Max(0,v.z-1); zz<=MISCMATHS::Min(v.z+1,im.maxz()); zz++) {
1227 for (
int yy=MISCMATHS::Max(0,v.y-1); yy<=MISCMATHS::Min(v.y+1,im.maxy()); yy++) {
1228 for (
int xx=MISCMATHS::Max(0,v.x-1); xx<=MISCMATHS::Min(v.x+1,im.maxx()); xx++) {
1229 if (ext_edge(mask,xx,yy,zz)) { newv.x=xx; newv.y=yy; newv.z=zz; ptlist.push_front(newv); }
1240 volume<T> fill_holes(
const volume<T>& im,
int connectivity)
1243 std::set<int> edgelabs;
1244 mask = connected_components((T)1-im,connectivity);
1247 for (
int z=0; z<=im.maxz(); z++) {
1248 for (
int y=0; y<=im.maxy(); y++) {
1249 if (mask(0,y,z)!=0) edgelabs.insert(mask(0,y,z));
1250 if (mask(im.maxx(),y,z)!=0) edgelabs.insert(mask(im.maxx(),y,z));
1253 for (
int z=0; z<=im.maxz(); z++) {
1254 for (
int x=0; x<=im.maxx(); x++) {
1255 if (mask(x,0,z)!=0) edgelabs.insert(mask(x,0,z));
1256 if (mask(x,im.maxy(),z)!=0) edgelabs.insert(mask(x,im.maxy(),z));
1259 for (
int y=0; y<=im.maxy(); y++) {
1260 for (
int x=0; x<=im.maxx(); x++) {
1261 if (mask(x,y,0)!=0) edgelabs.insert(mask(x,y,0));
1262 if (mask(x,y,im.maxz())!=0) edgelabs.insert(mask(x,y,im.maxz()));
1267 while (!edgelabs.empty()) {
1268 int val=*(edgelabs.begin());
1269 for (
int z=0; z<=im.maxz(); z++) {
1270 for (
int y=0; y<=im.maxy(); y++) {
1271 for (
int x=0; x<=im.maxx(); x++) {
1272 if (mask(x,y,z)==val) mask(x,y,z)=0;
1276 edgelabs.erase(val);
1278 volume<T> imcopy(im);
1279 for (
int z=0; z<=im.maxz(); z++)
1280 for (
int y=0; y<=im.maxy(); y++)
1281 for (
int x=0; x<=im.maxx(); x++)
1282 if (mask(x,y,z)>(T)0.5) imcopy(x,y,z)=1;
1291 volume<T> upsample_by_2(
const volume<T>& lowresvol,
bool centred)
1294 upsample_by_2(res,lowresvol,centred);
1303 volume<T> blur(
const volume<T>& source,
const NEWMAT::ColumnVector& resel_size)
1305 NEWMAT::ColumnVector bmaskx, bmasky, bmaskz;
1306 make_blur_mask(bmaskx,resel_size(1),source.xdim());
1307 make_blur_mask(bmasky,resel_size(2),source.ydim());
1308 make_blur_mask(bmaskz,resel_size(3),source.zdim());
1309 return convolve_separable(source,bmaskx,bmasky,bmaskz);
1314 volume<T> blur(
const volume<T>& source,
float iso_resel_size)
1316 NEWMAT::ColumnVector resel_size(3);
1317 resel_size = iso_resel_size;
1318 return blur(source,resel_size);
1322 volume<T> smooth(
const volume<T>& source,
float sigma_mm)
1324 float sigmax, sigmay, sigmaz;
1325 sigmax = sigma_mm/source.xdim();
1326 sigmay = sigma_mm/source.ydim();
1327 sigmaz = sigma_mm/source.zdim();
1328 int nx=((int) (sigmax-0.001))*2 + 3;
1329 int ny=((int) (sigmay-0.001))*2 + 3;
1330 int nz=((int) (sigmaz-0.001))*2 + 3;
1331 NEWMAT::ColumnVector kernelx, kernely, kernelz;
1332 kernelx = gaussian_kernel1D(sigmax,nx);
1333 kernely = gaussian_kernel1D(sigmay,ny);
1334 kernelz = gaussian_kernel1D(sigmaz,nz);
1335 return convolve_separable(source,kernelx,kernely,kernelz);
1342 volume<T> smooth2D(
const volume<T>& source,
float sigma_mm,
int nulldir=3)
1344 float sigmax, sigmay, sigmaz;
1345 sigmax = sigma_mm/source.xdim();
1346 sigmay = sigma_mm/source.ydim();
1347 sigmaz = sigma_mm/source.zdim();
1348 int nx=((int) (sigmax-0.001))*2 + 3;
1349 int ny=((int) (sigmay-0.001))*2 + 3;
1350 int nz=((int) (sigmaz-0.001))*2 + 3;
1351 NEWMAT::ColumnVector kernelx, kernely, kernelz, nullker(1);
1352 kernelx = gaussian_kernel1D(sigmax,nx);
1353 kernely = gaussian_kernel1D(sigmay,ny);
1354 kernelz = gaussian_kernel1D(sigmaz,nz);
1357 return convolve_separable(source,nullker,kernely,kernelz);
1358 }
else if (nulldir==2) {
1359 return convolve_separable(source,kernelx,nullker,kernelz);
1362 return convolve_separable(source,kernelx,kernely,nullker);
1366template <
class T,
class S>
1367 int insertpart(volume<T>& v1,
const volume<S>& v2)
1369 for (
int z=v2.minz(); z<=v2.maxz(); z++) {
1370 for (
int y=v2.miny(); y<=v2.maxy(); y++) {
1371 for (
int x=v2.minx(); x<=v2.maxx(); x++) {
1372 v1(x,y,z)=(T) v2(x,y,z);
1380 template <
class T,
class S,
class U>
1381volume<S> extractpart(
const volume<T>& v1,
const volume<S>& v2,
const volume<U>& kernel)
1385 int kxoff = (kernel.xsize()-1)/2;
1386 int kyoff = (kernel.ysize()-1)/2;
1387 int kzoff = (kernel.zsize()-1)/2;
1388 for (
int z=v2.minz(); z<=v2.maxz(); z++) {
1389 for (
int y=v2.miny(); y<=v2.maxy(); y++) {
1390 for (
int x=v2.minx(); x<=v2.maxx(); x++) {
1391 vout(x,y,z)=(S) v1(x+kxoff,y+kyoff,z+kzoff);
1400template <
class T,
class S>
1401volume<T> efficient_convolve(
const volume<T>& vin,
const volume<S>& vker)
1405 float offt = 2 * vin.nvoxels() * fsllog2(2 * vin.nvoxels());
1406 float osum = (float)vin.nvoxels() * (float)vker.nvoxels();
1408 float scalefactor = 44;
1409 usefft = (osum > offt * scalefactor);
1412 int sx = MISCMATHS::Max(vin.xsize(),vker.xsize())*2;
1413 int sy = MISCMATHS::Max(vin.ysize(),vker.ysize())*2;
1414 int sz = MISCMATHS::Max(vin.zsize(),vker.zsize())*2;
1415 complexvolume vif, vkf;
1416 vif.re().reinitialize(sx,sy,sz);
1419 vif.im() = vif.re();
1421 insertpart(vif.re(),vin);
1422 insertpart(vkf.re(),vker);
1427 return extractpart(vif.re(),vin,vker);
1428 }
else return convolve(vin,vker);
1431 template <
class T,
class S>
1432 volume4D<T> generic_convolve(
const volume4D<T>& source,
const volume<S>& kernel,
bool seperable,
bool renormalise)
1434 volume4D<T> result(source);
1437 volume<double> kerx(kernel.xsize(),1,1);
1438 volume<double> kery(1,kernel.ysize(),1);
1439 volume<double> kerz(1,1,kernel.zsize());
1440 for (
int n=0; n<kernel.xsize(); n++) kerx.value(n,0,0) = kernel(n,kernel.ysize()/2,kernel.zsize()/2);
1441 for (
int n=0; n<kernel.ysize(); n++) kery.value(0,n,0) = kernel(kernel.xsize()/2,n,kernel.zsize()/2);
1442 for (
int n=0; n<kernel.zsize(); n++) kerz.value(0,0,n) = kernel(kernel.xsize()/2,kernel.ysize()/2,n);
1443 volume<T> mask(1,1,1);
1444 for (
int t=source.mint(); t<=source.maxt(); t++) result.replaceSubVolume(t,convolve(result.constSubVolume(t),kerx,mask,
true,renormalise));
1445 for (
int t=source.mint(); t<=source.maxt(); t++) result.replaceSubVolume(t,convolve(result.constSubVolume(t),kery,mask,
true,renormalise));
1446 for (
int t=source.mint(); t<=source.maxt(); t++) result.replaceSubVolume(t,convolve(result.constSubVolume(t),kerz,mask,
true,renormalise));
1450 volume<S> norm_kernel(kernel);
1451 if (kernel.sum()) norm_kernel/=kernel.sum();
1452 for (
int t=source.mint(); t<=source.maxt(); t++) result.replaceSubVolume(t,efficient_convolve(source.constSubVolume(t),norm_kernel));
1453 result.copyproperties(source);
1456 volume4D<T> unitary_mask(source);
1458 for (
int t=source.mint(); t<=source.maxt(); t++) unitary_mask.replaceSubVolume(t,efficient_convolve(unitary_mask.constSubVolume(t),norm_kernel));
1459 result/=unitary_mask;
1471 volume<float> gradient(
const volume<T>& source)
1474 volume<float> maskx,masky,maskz;
1475 make_grad_masks(maskx,masky,maskz);
1476 volume<float> grad(source);
1477 float valx, valy, valz;
1478 int midx, midy, midz;
1479 midz=maskx.xsize()/2;
1480 midy=maskx.ysize()/2;
1481 midx=maskx.zsize()/2;
1482 for (
int z=0; z<grad.zsize(); z++) {
1483 for (
int y=0; y<grad.ysize(); y++) {
1484 for (
int x=0; x<grad.xsize(); x++) {
1485 valx=0.0; valy=0.0; valz=0.0;
1486 for (
int mz=-midz; mz<=midz; mz++) {
1487 for (
int my=-midy; my<=midy; my++) {
1488 for (
int mx=-midx; mx<=midx; mx++) {
1489 valx+=source(x+mx,y+my,z+mz) * maskx(mx+midx,my+midy,mz+midz);
1490 valy+=source(x+mx,y+my,z+mz) * masky(mx+midx,my+midy,mz+midz);
1491 valz+=source(x+mx,y+my,z+mz) * maskz(mx+midx,my+midy,mz+midz);
1495 grad(x,y,z)=sqrt(MISCMATHS::Sqr(valx) + MISCMATHS::Sqr(valy) + MISCMATHS::Sqr(valz));
1505 void gradient(
const volume<T>& source,volume<float>& grad)
1507 volume<float> maskx,masky,maskz;
1508 make_grad_masks(maskx,masky,maskz);
1509 grad.reinitialize(source.xsize(),source.ysize(),source.zsize(),3);
1510 copybasicproperties(source,grad);
1511 float valx, valy, valz;
1512 int midx, midy, midz;
1513 midz=maskx.xsize()/2;
1514 midy=maskx.ysize()/2;
1515 midx=maskx.zsize()/2;
1516 for (
int z=0; z<grad.zsize(); z++) {
1517 for (
int y=0; y<grad.ysize(); y++) {
1518 for (
int x=0; x<grad.xsize(); x++) {
1519 valx=0.0; valy=0.0; valz=0.0;
1520 for (
int mz=-midz; mz<=midz; mz++) {
1521 for (
int my=-midy; my<=midy; my++) {
1522 for (
int mx=-midx; mx<=midx; mx++) {
1523 valx+=source(x+mx,y+my,z+mz) * maskx(mx+midx,my+midy,mz+midz);
1524 valy+=source(x+mx,y+my,z+mz) * masky(mx+midx,my+midy,mz+midz);
1525 valz+=source(x+mx,y+my,z+mz) * maskz(mx+midx,my+midy,mz+midz);
1541 volume<float> lrxgrad(
const volume<float>& im,
const volume<T>& mask)
1546 volume4D<float> grad(im);
1548 if (!samesize(im,mask)) imthrow(
"Mask and image not the same size",20);
1550 for (
int z=0; z<im.zsize(); z++) {
1551 for (
int y=0; y<im.ysize(); y++) {
1552 for (
int x=0; x<im.xsize(); x++) {
1554 if (mask(x,y,z)>0.5) {
1557 if (mask(x-1,y,z)>0.5) {
1558 grad(x,y,z,0) = im(x,y,z) - im(x-1,y,z);
1562 if (x<im.xsize()-1) {
1563 if (mask(x+1,y,z)>0.5) {
1564 grad(x,y,z,1) = im(x+1,y,z) - im(x,y,z);
1567 grad(x,y,z,1) = grad(x,y,z,0);
1571 if ( (x>0) && (mask(x-1,y,z)<=0.5) ) {
1572 grad(x,y,z,0) = grad(x,y,z,1);
1584 volume<float> lrygrad(
const volume<float>& im,
const volume<T>& mask)
1589 volume4D<float> grad(im);
1591 if (!samesize(im,mask)) imthrow(
"Mask and image not the same size",20);
1593 for (
int z=0; z<im.zsize(); z++) {
1594 for (
int y=0; y<im.ysize(); y++) {
1595 for (
int x=0; x<im.xsize(); x++) {
1597 if (mask(x,y,z)>0.5) {
1600 if (mask(x,y-1,z)>0.5) {
1601 grad(x,y,z,0) = im(x,y,z) - im(x,y-1,z);
1605 if (y<im.ysize()-1) {
1606 if (mask(x,y+1,z)>0.5) {
1607 grad(x,y,z,1) = im(x,y+1,z) - im(x,y,z);
1610 grad(x,y,z,1) = grad(x,y,z,0);
1614 if ( (y>0) && (mask(x,y-1,z)<=0.5) ) {
1615 grad(x,y,z,0) = grad(x,y,z,1);
1627 volume<float> lrzgrad(
const volume<float>& im,
const volume<T>& mask)
1632 volume4D<float> grad(im);
1634 if (!samesize(im,mask)) imthrow(
"Mask and image not the same size",20);
1635 for (
int z=0; z<im.zsize(); z++) {
1636 for (
int y=0; y<im.ysize(); y++) {
1637 for (
int x=0; x<im.xsize(); x++) {
1639 if (mask(x,y,z)>0.5) {
1642 if (mask(x,y,z-1)>0.5) {
1643 grad(x,y,z,0) = im(x,y,z) - im(x,y,z-1);
1647 if (z<im.zsize()-1) {
1648 if (mask(x,y,z+1)>0.5) {
1649 grad(x,y,z,1) = im(x,y,z+1) - im(x,y,z);
1652 grad(x,y,z,1) = grad(x,y,z,0);
1656 if ( (z>0) && (mask(x,y,z-1)<=0.5) ) {
1657 grad(x,y,z,0) = grad(x,y,z,1);
1671 volume<T> bandpass_temporal_filter(volume<T>& source,
double hp_sigma,
double lp_sigma)
1673 int hp_mask_size_PLUS, lp_mask_size_PLUS, hp_mask_size_MINUS, lp_mask_size_MINUS;
1674 double *hp_exp=NULL, *lp_exp=NULL, *array, *array2;
1675 volume<T> result(source);
1677 if (hp_sigma<=0) hp_mask_size_MINUS=0;
1678 else hp_mask_size_MINUS=(int)(hp_sigma*3);
1679 hp_mask_size_PLUS=hp_mask_size_MINUS;
1680 if (lp_sigma<=0) lp_mask_size_MINUS=0;
1681 else lp_mask_size_MINUS=(int)(lp_sigma*20)+2;
1682 lp_mask_size_PLUS=lp_mask_size_MINUS;
1684 array=
new double[source.tsize()];
1685 array2=
new double[source.tsize()];
1689 hp_exp=
new double[hp_mask_size_MINUS+hp_mask_size_PLUS+1];
1690 hp_exp+=hp_mask_size_MINUS;
1691 for(
int t=-hp_mask_size_MINUS; t<=hp_mask_size_PLUS; t++)
1692 hp_exp[t] = exp( -0.5 * ((
double)(t*t)) / (hp_sigma*hp_sigma) );
1698 lp_exp=
new double[lp_mask_size_MINUS+lp_mask_size_PLUS+1];
1699 lp_exp+=lp_mask_size_MINUS;
1700 for(
int t=-lp_mask_size_MINUS; t<=lp_mask_size_PLUS; t++)
1702 lp_exp[t] = exp( -0.5 * ((
double)(t*t)) / (lp_sigma*lp_sigma) );
1706 for(
int t=-lp_mask_size_MINUS; t<=lp_mask_size_PLUS; t++)
1709 for(
int z=0;z<source.zsize();z++)
1710 for(
int y=0;y<source.ysize();y++)
1711 for(
int x=0;x<source.xsize();x++)
1713 for(
int t=0; t<source.tsize(); t++)
1714 array[t] = (
double)source.value(x,y,z,t);
1720 for(
int t=0; t<source.tsize(); t++)
1723 double c, w, A=0, B=0, C=0, D=0, N=0, tmpdenom;
1724 for(tt=MAX(t-hp_mask_size_MINUS,0); tt<=MIN(t+hp_mask_size_PLUS,source.tsize()-1); tt++)
1731 D += w * dt * array[tt];
1737 c = (B*C-A*D) / tmpdenom;
1743 array2[t] = c0 + array[t] - c;
1745 else array2[t] = array[t];
1749 mean/=source.tsize();
1750 for(
int t=0; t<source.tsize(); t++)
1752 memcpy(array,array2,
sizeof(
double)*source.tsize());
1757 for(
int t=0; t<source.tsize(); t++)
1762 for(tt=MAX(t-lp_mask_size_MINUS,0); tt<=MIN(t+lp_mask_size_PLUS,source.tsize()-1); tt++) {
1763 total += array[tt] * lp_exp[tt-t];
1767 array2[t] = total/sum;
1771 memcpy(array,array2,
sizeof(
double)*source.tsize());
1774 for(
int t=0; t<source.tsize(); t++)
1775 result.value(x,y,z,t)= (T)array[t] ;
1791 volume<T> log_edge_detect(
const volume<T>& source,
1792 float sigma1,
float sigma2,
int mode)
1804 volume<float> log_kern, temp_kern;
1805 volume<T> log_result(source);
1806 volume<T> zero_crossing_result(source);
1807 zero_crossing_result = 0;
1809 radius1 = (int)(4*sigma2);
1811 log_kern = gaussian_kernel2D(sigma2, radius1);
1812 temp_kern = gaussian_kernel2D(sigma1, radius1);
1814 log_kern = gaussian_kernel3D(sigma2, radius1);
1815 temp_kern = gaussian_kernel3D(sigma1, radius1);
1818 log_kern -= temp_kern;
1820 log_result = convolve(source, log_kern);
1821 for(
int t=0;t<log_result.tsize();t++)
1822 for(
int z=1;z<log_result.zsize()-1;z++)
1823 for(
int y=1;y<log_result.ysize()-1;y++)
1824 for(
int x=1;x<log_result.xsize()-1;x++) {
1825 float val = log_result.value(x,y,z,t);
1831 (log_result.value(x-1,y,z,t) <= ival) ||
1832 (log_result.value(x+1,y,z,t) <= ival) ||
1833 (log_result.value(x,y-1,z,t) <= ival) ||
1834 (log_result.value(x,y+1,z,t) <= ival) ||
1835 (log_result.value(x,y,z-1,t) <= ival) ||
1836 (log_result.value(x,y,z+1,t) <= ival)
1840 zero_crossing_result(x,y,z,t) = 1.0;
1846 (log_result.value(x-1,y,z,t) > ival) ||
1847 (log_result.value(x+1,y,z,t) > ival) ||
1848 (log_result.value(x,y-1,z,t) > ival) ||
1849 (log_result.value(x,y+1,z,t) > ival) ||
1850 (log_result.value(x,y,z-1,t) > ival) ||
1851 (log_result.value(x,y,z+1,t) > ival)
1855 zero_crossing_result(x,y,z,t) = 1.0;
1859 return zero_crossing_result;
1863 volume<T> fixed_edge_detect(
const volume<T>& source,
float threshold,
1864 bool twodimensional)
1866 volume<T> result = source;
1868 if (twodimensional) zsize=1;
1870 volume<float> log_kern(3,3,zsize);
1872 log_kern(1,1,(zsize-1)/2) = 8;
1874 extrapolation oldex = source.getextrapolationmethod();
1875 source.setextrapolationmethod(mirror);
1876 result = convolve(source, log_kern);
1877 source.setextrapolationmethod(oldex);
1878 result.binarise(threshold);
1888 volume<T> edge_strengthen(
const volume<T>& source)
1890 float tmpf=2*sqrt(1/(pow((
double)source.xdim(),2.0)) + 1/(pow((
double)source.ydim(),2.0)) + 1/(pow((
double)source.zdim(),2.0)));
1893 if (source.zsize()>2)
1895 for(
int t=0;t<source.tsize();t++)
1896 for(
int z=1;z<source.zsize()-1;z++)
1897 for(
int y=1;y<source.ysize()-1;y++)
1898 for(
int x=1;x<source.xsize()-1;x++)
1900 double temp1 = pow(
double(source.value(x,y,z+1,t)-source.value(x,y,z-1,t)),2.0)/ pow((
double)source.zdim(),2.0);
1901 double temp2 = pow(
double(source.value(x,y+1,z,t)-source.value(x,y-1,z,t)),2.0)/ pow((
double)source.ydim(),2.0);
1902 double temp3 = pow(
double(source.value(x+1,y,z,t)-source.value(x-1,y,z,t)),2.0)/ pow((
double)source.xdim(),2.0);
1903 result(x,y,z,t)=(T)(sqrt(temp1+temp2+temp3)/tmpf);
1908 for(
int t=0;t<source.tsize();t++)
1909 for(
int z=0;z<source.zsize();z++)
1910 for(
int y=1;y<source.ysize()-1;y++)
1911 for(
int x=1;x<source.xsize()-1;x++)
1913 double temp1=pow(
double(source.value(x,y+1,z,t)-source.value(x,y-1,z,t)),2.0)/ pow((
double)source.ydim(),2.0);
1914 double temp2=pow(
double(source.value(x+1,y,z,t)-source.value(x-1,y,z,t)),2.0)/ pow((
double)source.xdim(),2.0);
1915 result(x,y,z,t) = (T)(sqrt (temp1+temp2) / tmpf);
1927 int find_first_nonzero(
const NEWMAT::Matrix& mat);
1929 void addpair2set(
int x,
int y, std::vector<int>& sx, std::vector<int>& sy);
1931 void relabel_components_uniquely(volume<int>& labelvol,
1932 const std::vector<int>& equivlista,
1933 const std::vector<int>& equivlistb, NEWMAT::ColumnVector& clustersizes);
1935 void relabel_components_uniquely(volume<int>& labelvol,
1936 const std::vector<int>& equivlista,
1937 const std::vector<int>& equivlistb);
1942 offset(
const int64_t ix,
const int64_t iy,
const int64_t iz) : x(ix),y(iy),z(iz) {}
1945 std::vector<offset> backConnectivity(
int nDirections);
1948 void nonunique_component_labels(
const volume<T>& vol,
1950 std::vector<int>& equivlista,
1951 std::vector<int>& equivlistb,
1954 copyconvert(vol,labelvol);
1958 equivlista.erase(equivlista.begin(),equivlista.end());
1959 equivlistb.erase(equivlistb.begin(),equivlistb.end());
1960 std::vector<offset> neighbours(backConnectivity(numconnected));
1961 for (
int z=vol.minz(); z<=vol.maxz(); z++)
1962 for (
int y=vol.miny(); y<=vol.maxy(); y++)
1963 for (
int x=vol.minx(); x<=vol.maxx(); x++) {
1966 int lval(labelvol(x,y,z));
1967 for (std::vector<offset>::iterator it=neighbours.begin();it!=neighbours.end();it++) {
1968 int xnew(x+it->x),ynew(y+it->y),znew(z+it->z);
1969 if ( (xnew>=vol.minx()) && (ynew>=vol.miny()) && (znew>=vol.minz())
1970 && (MISCMATHS::round(vol(xnew,ynew,znew)))==val) {
1972 int lval2 = labelvol(xnew,ynew,znew);
1973 if (lval != lval2) {
1975 addpair2set(lval2,lval,equivlista,equivlistb);
1976 labelvol(x,y,z) = lval2;
1982 labelvol(x,y,z) = ++labelnum;
1988 void nonunique_component_labels(
const volume<T>& vol,
1989 volume<int>& labelvol,
1990 std::vector<int>& equivlista,
1991 std::vector<int>& equivlistb,
1992 bool (*binaryrelation)(T , T),
1995 copyconvert(vol,labelvol);
1999 equivlista.erase(equivlista.begin(),equivlista.end());
2000 equivlistb.erase(equivlistb.begin(),equivlistb.end());
2001 std::vector<offset> neighbours(backConnectivity(numconnected));
2002 for (
int z=vol.minz(); z<=vol.maxz(); z++)
2003 for (
int y=vol.miny(); y<=vol.maxy(); y++)
2004 for (
int x=vol.minx(); x<=vol.maxx(); x++) {
2007 int lval(labelvol(x,y,z));
2008 for (std::vector<offset>::iterator it=neighbours.begin();it!=neighbours.end();it++) {
2009 int xnew(x+it->x),ynew(y+it->y),znew(z+it->z);
2010 if ((xnew>=vol.minx()) && (ynew>=vol.miny()) && (znew>=vol.minz())
2011 && ((*binaryrelation)(vol(xnew,ynew,znew),val))) {
2013 int lval2 = labelvol(xnew,ynew,znew);
2014 if (lval != lval2) {
2016 addpair2set(lval2,lval,equivlista,equivlistb);
2017 labelvol(x,y,z) = lval2;
2023 labelvol(x,y,z) = ++labelnum;
2029 volume<int> connected_components(
const volume<T>& vol, NEWMAT::ColumnVector& clustersize,
int numconnected)
2031 volume<int> labelvol;
2032 copyconvert(vol,labelvol);
2033 std::vector<int> equivlista, equivlistb;
2034 nonunique_component_labels(vol,labelvol,
2035 equivlista,equivlistb,numconnected);
2036 relabel_components_uniquely(labelvol,equivlista,equivlistb,clustersize);
2042 volume<int> connected_components(
const volume<T>& vol,
2043 const volume<T>& mask,
2044 bool (*binaryrelation)(T , T), NEWMAT::ColumnVector& clustersize)
2046 volume<int> labelvol;
2047 copyconvert(vol,labelvol);
2048 std::vector<int> equivlista, equivlistb;
2049 nonunique_component_labels(vol,mask,labelvol,equivlista,equivlistb,
2051 relabel_components_uniquely(labelvol,equivlista,equivlistb,clustersize);
2057 volume<int> connected_components(
const volume<T>& vol,
int numconnected){
2058 NEWMAT::ColumnVector clustersize;
2059 return connected_components(vol,clustersize,numconnected);
2064 volume<int> connected_components(
const volume<T>& vol,
const volume<T>& mask,
2065 bool (*binaryrelation)(T , T)){
2066 NEWMAT::ColumnVector clustersize;
2067 return connected_components(vol,mask,binaryrelation,clustersize);
2074class rowentry {
public:
int x;
int y;
int z;
float d; } ;
2084 std::vector<rowentry> schedule;
2085 std::vector<offset> octantsign;
2095 volume4D<float> sparseinterpolate(
const volume4D<float>& values,
2096 const std::string& interpmethod=
"general");
2098 int setup_globals();
2099 int find_nearest(
int x,
int y,
int z,
int& x1,
int& y1,
int& z1,
2100 bool findav, NEWMAT::ColumnVector& localav,
const volume4D<float>& vals);
2101 int find_nearest(
int x,
int y,
int z,
int& x1,
int& y1,
int& z1);
2102 int create_distancemap(volume4D<float>& vout,
const volume4D<float>& valim,
2103 const std::string& interpmethod=
"none");
2104 int basic_create_distancemap(volume4D<float>& vout,
2105 const volume4D<float>& valim,
2106 const std::string& interpmethod);
2111 bvol(binarypos), mask(maskvol), bvolneg(binaryneg)
2113 if (!samesize(bvol,mask)) imthrow(
"Mask and image not the same size",20);
2114 if (!samesize(bvol,bvolneg)) imthrow(
"Two binary images are not the same size",20);
2121distancemapper<T>::distancemapper(
const volume<T>& binaryvol,
const volume<T>& maskvol) :
2122 bvol(binaryvol), mask(maskvol), bvolneg(binaryvol)
2124 if (!samesize(bvol,mask)) imthrow(
"Mask and image not the same size",20);
2130distancemapper<T>::~distancemapper()
2136int distancemapper<T>::setup_globals()
2140 for (
int p=-1; p<=1; p+=2)
2141 for (
int q=-1; q<=1; q+=2)
2142 for (
int r=-1; r<=1; r+=2)
2143 octantsign.push_back(offset(p,q,r));
2147 for (
int z=bvol.minz(); z<=bvol.maxz(); z++) {
2148 for (
int y=bvol.miny(); y<=bvol.maxy(); y++) {
2149 for (
int x=bvol.minx(); x<=bvol.maxx(); x++) {
2154 float d2 = MISCMATHS::norm2sq(x*bvol.xdim(),y*bvol.ydim(),z*bvol.zdim());
2156 schedule.push_back(newrow);
2162 sort(schedule.begin(),schedule.end(),NEWIMAGE::rowentry_lessthan);
2169int distancemapper<T>::find_nearest(
int x,
int y,
int z,
int& x1,
int& y1,
int& z1,
2170 bool findav, NEWMAT::ColumnVector& localav,
2171 const volume4D<float>& vals)
2173 float sumw=0.0, mindist=0, maxdist=0.0, weight;
2174 float minVoxSize = std::min(bvol.xdim(),std::min(bvol.ydim(),bvol.zdim()));
2175 NEWMAT::ColumnVector sumvw;
2177 localav.ReSize(vals.tsize());
2179 sumvw.ReSize(vals.tsize());
2182 for (std::vector<rowentry>::iterator it=schedule.begin(); it!=schedule.end();it++) {
2183 for (std::vector<offset>::iterator oit=octantsign.begin(); oit!=octantsign.end();oit++) {
2187 if (bvol.in_bounds(x1,y1,z1)) {
2188 bool primaryValid( bvol.value(x1,y1,z1) > 0.5);
2189 if ( primaryValid || ( dualmasks && (bvolneg.value(x1,y1,z1)>0.5))) {
2190 if ((!findav) || (dualmasks)) {
2191 return primaryValid ? 1 : -1;
2192 }
else if (mindist==0.0) {
2195 maxdist=MISCMATHS::Max(mindist+minVoxSize,mindist*1.5);
2196 }
else if (it->d>maxdist) {
2200 weight = it->d ? mindist/it->d : 1;
2202 for (
int t=0; t<vals.tsize(); t++)
2203 sumvw(t+1) += weight * vals.value(x1,y1,z1,t);
2209 if (findav) {
if (sumw>0) { localav=sumvw/sumw;
return 1; }}
2215int distancemapper<T>::find_nearest(
int x,
int y,
int z,
int& x1,
int& y1,
int& z1)
2217 NEWMAT::ColumnVector dummy;
2218 volume4D<float> dummyvol;
2219 return this->find_nearest(x,y,z,x1,y1,z1,
false,dummy,dummyvol);
2227int distancemapper<T>::create_distancemap(volume4D<float>& vout,
2228 const volume4D<float>& valim,
2229 const std::string& interpmethod)
2231 if (interpmethod!=
"general")
2232 return this->basic_create_distancemap(vout,valim,interpmethod);
2234 float meanvoxsize = pow(valim.xdim()*valim.ydim()*valim.zdim(),1.0/3.0);
2236 if (meanvoxsize<4.0) { nsubsamp=1; }
2237 if (meanvoxsize<2.0) { nsubsamp=2; }
2238 if (meanvoxsize<1.0) { nsubsamp=3; }
2241 return basic_create_distancemap(vout,valim,interpmethod);
2248 std::vector<volume4D<float> > sampledData;
2249 std::vector<volume<float> > sampledMask;
2250 sampledData.resize(nsubsamp+1);
2251 sampledMask.resize(nsubsamp+1);
2252 sampledMask[0]=1.0f - mask;
2253 sampledData[0]=valim*sampledMask[0];
2254 for (
int n=1; n<=nsubsamp; n++) {
2255 sampledMask[n]=subsample_by_2(sampledMask[n-1],
false);
2256 sampledData[n].reinitialize(sampledMask[n].xsize(),sampledMask[n].ysize(),sampledMask[n].zsize(),valim.tsize());
2257 sampledData[n].copyproperties(sampledMask[n]);
2258 for (
int t=0; t<valim.tsize(); t++)
2259 (sampledData[n])[t]=divide(subsample_by_2((sampledData[n-1])[t],
false),sampledMask[n],sampledMask[n]);
2261 sampledMask[n].binarise(1e-4);
2265 sampledData[nsubsamp]=NEWIMAGE::sparseinterpolate(sampledData[nsubsamp],sampledMask[nsubsamp]);
2267 volume<float> kernel(3,3,3);
2269 sampledMask[nsubsamp]=morphfilter(sampledMask[nsubsamp],kernel,
"dilate");
2270 sampledMask[nsubsamp]= 1.0f - sampledMask[nsubsamp];
2273 for (
int n=nsubsamp; n>0; n--) {
2274 for (
int t=0; t<valim.tsize(); t++) {
2275 ShadowVolume<float> shadow(sampledData[n-1][t]);
2276 upsample_by_2(shadow,sampledData[n][t],
false);
2278 ShadowVolume<float> shadow(sampledMask[n-1]);
2279 upsample_by_2(shadow,sampledMask[n],
false);
2281 sampledMask[0].binarise(0.5f);
2284 volume4D<float> vres(valim*(1.0f-mask) + sampledData[0]*sampledMask[0]);
2285 sampledMask[0] = mask - sampledMask[0];
2288 volume<float> invMask(1.0f - sampledMask[0]);
2289 distancemapper<float> newdmapper(invMask,sampledMask[0]);
2290 return newdmapper.basic_create_distancemap(vout,vres,interpmethod);
2297int distancemapper<T>::basic_create_distancemap(volume4D<float>& vout,
2298 const volume4D<float>& valim,
2299 const std::string& interpmethod)
2302 NEWMAT::ColumnVector localav;
2303 int interp=0, distsign=1;
2304 if ((interpmethod==
"nn") || (interpmethod==
"nearestneighbour")) interp=1;
2305 if (interpmethod==
"general") interp=2;
2306 if (interp>0) { vout = valim; }
else { vout = bvol; vout *= 0.0f; }
2307 if ((interp>0) && (!samesize(bvol,valim.constSubVolume(0))))
2308 { print_volume_info(bvol,std::string(
"bvol"),std::cerr); print_volume_info(mask,std::string(
"mask"),std::cerr); print_volume_info(valim.constSubVolume(0),std::string(
"valim"),std::cerr);
2309 imthrow(
"Binary image and interpolant not the same size",21); }
2310 for (
int z=0; z<vout.zsize(); z++) {
2311 for (
int y=0; y<vout.ysize(); y++) {
2312 for (
int x=0; x<vout.xsize(); x++) {
2313 if (mask(x,y,z)>((T) 0.5)) {
2314 distsign=find_nearest(x,y,z,x1,y1,z1,interp>=2,localav,valim);
2317 for (
int t=0;t<valim.tsize();t++) { vout(x,y,z,t)=localav(t+1); }
2320 for (
int t=0;t<valim.tsize();t++) { vout(x,y,z,t)=valim(x1,y1,z1,t); }
2324 vout(x,y,z,0)=distsign*sqrt(MISCMATHS::norm2sq((x1-x)*bvol.xdim(),
2325 (y1-y)*bvol.ydim(),(z1-z)*bvol.zdim()));
2336const volume<float> distancemapper<T>::distancemap()
2338 volume4D<float> dmap;
2339 create_distancemap(dmap,dmap,
"none");
2344volume4D<float> distancemapper<T>::sparseinterpolate(
const volume4D<float>& values,
2345 const std::string& interpmethod)
2347 volume4D<float> vout;
2348 create_distancemap(vout,values,interpmethod);
2354volume<float> distancemap(
const volume<T>& binaryvol)
2357 mask = ((T) 1) - binarise(binaryvol,((T) 0.5));
2358 return distancemap(binaryvol,mask);
2362volume<float> distancemap(
const volume<T>& binaryvol,
const volume<T>& mask)
2364 distancemapper<T> dmapper(binaryvol,mask);
2365 return dmapper.distancemap();
2369volume<float> distancemap(
const volume<T>& binarypos,
const volume<T>& binaryneg,
const volume<T>& maskvol)
2371 distancemapper<T> dmapper(binarypos,binaryneg,maskvol);
2372 return dmapper.distancemap();
2376volume4D<float> sparseinterpolate(
const volume4D<T>& sparsesamps,
2377 const volume<T>& mask,
2378 const std::string& interpmethod)
2382 invmask=((T) 1) - mask;
2383 distancemapper<T> dmapper(mask,invmask);
2384 return dmapper.sparseinterpolate(sparsesamps,interpmethod);
2391void tfce_orig_slow(volume<T>& VolIntn,
float H,
float E,
int NumConn,
float minT,
float deltaT)
2393 float maxval=VolIntn.max();
2394 volume<float> clusterenhance;
2395 copyconvert(VolIntn,clusterenhance);
2399 deltaT = (maxval - minT)/100.0;
2401 for (
float thresh=minT+deltaT; thresh<=maxval; thresh+=deltaT)
2403 volume<float> clusters;
2404 copyconvert(VolIntn,clusters);
2405 clusters.binarise(thresh);
2407 NEWMAT::ColumnVector clustersizes;
2408 volume<int>tmpvol=connected_components(clusters,clustersizes,NumConn);
2409 clustersizes = pow(clustersizes,E) * pow(thresh,H);
2410 for(
int z=0;z<VolIntn.zsize();z++)
2411 for(
int y=0;y<VolIntn.ysize();y++)
2412 for(
int x=0;x<VolIntn.xsize();x++)
2413 if (tmpvol.value(x,y,z)>0)
2414 clusterenhance.value(x,y,z) += clustersizes(tmpvol.value(x,y,z));
2416 copyconvert(clusterenhance,VolIntn);
2424 bool operator<(
const VecSort& other)
const{
2425 return Sv < other.Sv;
2430void tfce(
volume<T>& data,
float H,
float E,
int NumConn,
float minT,
float deltaT)
2433 volume<float> VolEnhn; copyconvert(data, VolEnhn); VolEnhn=0;
2435 const int INIT=-1, MASK=-2;
2437 int pX, pY, pZ, qX, qY, qZ, rX, rY, rZ;
2438 int FldCntr=0, FldCntri=0, tfceCntr=0, xFC = 0;
2439 int minX=1, minY=1, minZ=1, maxX=data.maxx()-1, maxY=data.maxy()-1, maxZ=data.maxz()-1;
2440 int sizeC=maxX*maxY*maxZ;
2441 int counter=0, edsta[27];
2442 float maxT=data.max();
2446 throw std::runtime_error(
"Error: tfce requires a positive deltaT input.");
2447 if ( data.xsize() < 3 || data.ysize() < 3 || data.zsize() < 3 )
2448 throw std::runtime_error(
"Error: tfce currently requires an input with at least 3 voxels extent into each dimension.");
2449 if( data.max()/deltaT > 10000 )
2450 std::cout <<
"Warning: tfce has detected a large number of integral steps. This operation may require a great deal of time to complete." << std::endl;
2451 std::vector<VecSort> VecSortI(sizeC);
2452 std::queue<int> Qx, Qy, Qz;
2453 for(
int z0=-1; z0<=1; z0++)
2454 for(
int y0=-1; y0<=1; y0++)
2455 for(
int x0=-1; x0<=1; x0++){
2456 edsta[counter++] = (x0*x0+y0*y0+z0*z0);
2457 if (edsta[counter-1]<2 && edsta[counter-1]!=0) edsta[counter-1]=6;
2458 if (edsta[counter-1]<3 && edsta[counter-1]!=0) edsta[counter-1]=18;
2459 if (edsta[counter-1]<4 && edsta[counter-1]!=0) edsta[counter-1]=26;
2460 if (edsta[counter-1]==0) edsta[counter-1]=100;
2463 for(
int z=minZ; z<=maxZ; z++)
2464 for(
int y=minY; y<=maxY; y++)
2465 for(
int x=minX; x<=maxX; x++) {
2466 float iVal=data.value(x,y,z);
2468 VecSortI[FldCntr].Sx=x; VecSortI[FldCntr].Sy=y; VecSortI[FldCntr].Sz=z;
2469 VecSortI[FldCntr++].Sv=iVal;
2473 VecSortI.resize(sizeC);
2474 sort(VecSortI.begin(), VecSortI.end());
2475 for(
float curThr=minT; curThr<(maxT+deltaT);curThr+=deltaT){
2476 VolLabl = INIT; FldCntr = xFC; curlab = 0;
2477 while( (VecSortI[FldCntr].Sv<=curThr) && (FldCntr<sizeC) ){
2478 VecSortI[FldCntr].Sl=0; VecSortI[FldCntr++].Sv=0;
2481 while( VecSortI[FldCntr].Sv>curThr && (FldCntr<sizeC) ){
2482 pX=VecSortI[FldCntr].Sx; pY=VecSortI[FldCntr].Sy; pZ=VecSortI[FldCntr++].Sz;
2483 VolLabl.value(pX,pY,pZ)=MASK;
2485 for(FldCntri=xFC; FldCntri<FldCntr; FldCntri++){
2486 pX=VecSortI[FldCntri].Sx; pY=VecSortI[FldCntri].Sy; pZ=VecSortI[FldCntri].Sz;
2487 if(VolLabl.value(pX, pY, pZ)==MASK){
2489 Qx.push(pX); Qy.push(pY); Qz.push(pZ);
2490 VolLabl.value(pX, pY, pZ)=curlab;
2492 qX=Qx.front(); qY=Qy.front(); qZ=Qz.front();
2493 Qx.pop(); Qy.pop(); Qz.pop();
2495 for(
int z0=-1; z0<=1; z0++)
2496 for(
int y0=-1; y0<=1; y0++)
2497 for(
int x0=-1; x0<=1; x0++){
2498 rX=qX+x0; rY=qY+y0; rZ=qZ+z0;
2499 doIT =(NumConn>=edsta[counter++]);
2500 if(doIT && (VolLabl.value(rX, rY, rZ)==MASK)){
2501 Qx.push(rX); Qy.push(rY);Qz.push(rZ);
2502 VolLabl.value(rX, rY, rZ)=curlab;
2508 NEWMAT::ColumnVector ClusterSizes(curlab), ClusterSizesI(curlab);
2510 for(tfceCntr=xFC; tfceCntr<sizeC; tfceCntr++){
2511 VecSortI[tfceCntr].Sl=VolLabl.value(VecSortI[tfceCntr].Sx, VecSortI[tfceCntr].Sy, VecSortI[tfceCntr].Sz);
2512 if ( VecSortI[tfceCntr].Sl>0 )
2513 ClusterSizes(VecSortI[tfceCntr].Sl)+=1;
2515 float HH=pow(curThr, H);
2516 ClusterSizesI=pow(ClusterSizes, E)*HH;
2517 for(tfceCntr=xFC; tfceCntr<sizeC; tfceCntr++){
2518 if ( VecSortI[tfceCntr].Sl>0 ){
2519 VolEnhn.value(VecSortI[tfceCntr].Sx, VecSortI[tfceCntr].Sy, VecSortI[tfceCntr].Sz) += ClusterSizesI(VecSortI[tfceCntr].Sl);
2523 copyconvert(VolEnhn,data);
2528void tfce_support(volume<T>& VolIntn,
float H,
float E,
int NumConn,
float minT,
float deltaT,
int Xoi,
int Yoi,
int Zoi,
float threshTFCE)
2530 volume<float> VolEnhn; copyconvert(VolIntn, VolEnhn);
2531 volume<float> VolTemp; copyconvert(VolIntn, VolTemp);
2532 int minX=0, minY=0, minZ=0, maxX=VolIntn.maxx(), maxY=VolIntn.maxy(), maxZ=VolIntn.maxz();
2533 float maxT = VolIntn.value(Xoi,Yoi,Zoi);
2534 int thrCntr = 0;
int thrNum = 0;
2540 thrNum = int(maxT/deltaT)+1;
2541 NEWMAT::ColumnVector Clusters(thrNum), Thresholds(thrNum), ClusterSizes;
2542 for(
float thresh=minT; thresh<maxT; thresh+=deltaT){
2543 copyconvert(VolEnhn, VolTemp);
2544 VolTemp.binarise(thresh);
2545 volume<int> VolLabl = connected_components(VolTemp, ClusterSizes, NumConn);
2546 Clusters(thrCntr+1) = ClusterSizes(VolLabl.value(Xoi, Yoi, Zoi));
2547 Thresholds(thrCntr+1) = thresh;
2548 for(
int z=minZ; z<=maxZ; z++)
2549 for(
int y=minY; y<=maxY; y++)
2550 for(
int x=minX; x<=maxX; x++)
2551 if( VolLabl.value(x,y,z) != VolLabl.value(Xoi,Yoi,Zoi) )
2552 VolEnhn.value(x,y,z) = 0;
2555 float summ=0, thre=0;
2556 for (
int i=0; i<thrCntr; i++){
2557 summ+=std::pow((
float)Clusters(thrCntr-i), E)*std::pow((
float)Thresholds(thrCntr-i), H);
2558 thre = Thresholds(thrCntr-i);
2559 if(summ>=threshTFCE)
2563 std::cout<<
"it doesn't reach to specified threshold"<<std::endl;
2564 copyconvert(VolIntn, VolEnhn);
2565 copyconvert(VolIntn, VolTemp); VolTemp.binarise(thre);
2566 volume<int> VolLabl = connected_components(VolTemp, ClusterSizes, NumConn);
2567 for(
int z=minZ; z<=maxZ; z++)
2568 for(
int y=minY; y<=maxY; y++)
2569 for(
int x=minX; x<=maxX; x++)
2570 if( VolLabl.value(x,y,z)!=VolLabl(Xoi, Yoi, Zoi) )
2571 VolEnhn.value(x,y,z) = 0;
2572 copyconvert(VolEnhn,VolIntn);
Definition: newimagefns.h:2420
Definition: newimagefns.h:2079
Definition: newimagefns.h:2074
Definition: newimage.h:100
Definition: newimagefns.h:1940
Definition: newimagefns.h:1198