// check the reslicing is right TEST( MultidimTest, getImage) { XMIPP_TRY MultidimArray<float> imgTgt, imgRef; imgRef.resize(3,1,3,3); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(imgRef) dAi(imgRef, n) = n; imgRef.getImage(2, imgTgt); FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(imgRef) { EXPECT_EQ(DIRECT_NZYX_ELEM(imgRef,2,k,i,j), DIRECT_ZYX_ELEM(imgTgt,k,i,j)); } imgTgt.resize(6,1,3,3); imgRef.getImage(0, imgTgt, 5); imgRef.getImage(1, imgTgt, 3); imgRef.getImage(2, imgTgt, 1); FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(imgRef) { EXPECT_EQ(DIRECT_NZYX_ELEM(imgRef,0,k,i,j), DIRECT_NZYX_ELEM(imgTgt,5,k,i,j)); EXPECT_EQ(DIRECT_NZYX_ELEM(imgRef,1,k,i,j), DIRECT_NZYX_ELEM(imgTgt,3,k,i,j)); EXPECT_EQ(DIRECT_NZYX_ELEM(imgRef,2,k,i,j), DIRECT_NZYX_ELEM(imgTgt,1,k,i,j)); } XMIPP_CATCH }
// check the reslicing is right TEST( MultidimTest, reslice) { XMIPP_TRY MultidimArray<float> imgSliced, imgRef; imgRef.resize(3,3,3); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(imgRef) dAi(imgRef, n) = n; imgRef.reslice(imgSliced, VIEW_Y_NEG); // imgSliced.reslice(ImageGeneric::Y_NEG); FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(imgRef) { EXPECT_EQ(DIRECT_ZYX_ELEM(imgRef,k,i,j), DIRECT_ZYX_ELEM(imgSliced,ZSIZE(imgSliced)-1-i,k,j)); } imgRef.reslice(imgSliced, VIEW_X_NEG); FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(imgRef) { EXPECT_EQ(DIRECT_ZYX_ELEM(imgRef,k,i,j), DIRECT_ZYX_ELEM(imgSliced,ZSIZE(imgSliced)-1-j,i,k)); } XMIPP_CATCH }
// Transform --------------------------------------------------------------- void FourierTransformer::Transform(int sign) { if (sign == FFTW_FORWARD) { fftw_execute(fPlanForward); // Normalisation of the transform unsigned long int size = 0; if (fReal != NULL) { size = MULTIDIM_SIZE(*fReal); } else if (fComplex != NULL) { size = MULTIDIM_SIZE(*fComplex); } else { REPORT_ERROR("No complex nor real data defined"); } FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(fFourier) DIRECT_MULTIDIM_ELEM(fFourier, n) /= size; } else if (sign == FFTW_BACKWARD) { fftw_execute(fPlanBackward); } }
// Apply transformation --------------------------------------------------- void applyTransformation(const MultidimArray<double> &V2, MultidimArray<double> &Vaux, double *p) { Matrix1D<double> r(3); Matrix2D<double> A, Aaux; double greyScale = p[0]; double greyShift = p[1]; double rot = p[2]; double tilt = p[3]; double psi = p[4]; double scale = p[5]; ZZ(r) = p[6]; YY(r) = p[7]; XX(r) = p[8]; Euler_angles2matrix(rot, tilt, psi, A, true); translation3DMatrix(r,Aaux); A = A * Aaux; scale3DMatrix(vectorR3(scale, scale, scale),Aaux); A = A * Aaux; applyGeometry(LINEAR, Vaux, V2, A, IS_NOT_INV, WRAP); if (greyScale!=1 || greyShift!=0) FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Vaux) DIRECT_MULTIDIM_ELEM(Vaux,n)=DIRECT_MULTIDIM_ELEM(Vaux,n)*greyScale+greyShift; }
/* Normalizations ---------------------------------------------------------- */ void normalize_OldXmipp(MultidimArray<double> &I) { double mean,std; I.computeAvgStdev(mean,std); double istd=1.0/std; FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(I) DIRECT_MULTIDIM_ELEM(I,n)=(DIRECT_MULTIDIM_ELEM(I,n)-mean)*istd; }
void FourierProjector::produceSideInfo() { // Zero padding MultidimArray<double> Vpadded; int paddedDim=(int)(paddingFactor*volumeSize); // JMRT: TODO: I think it is a very poor design to modify the volume passed // in the construct, it will be padded anyway, so new memory should be allocated volume->window(Vpadded,FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim), LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim)); volume->clear(); // Make Fourier transform, shift the volume origin to the volume center and center it MultidimArray< std::complex<double> > Vfourier; transformer3D.completeFourierTransform(Vpadded,Vfourier); ShiftFFT(Vfourier, FIRST_XMIPP_INDEX(XSIZE(Vpadded)), FIRST_XMIPP_INDEX(YSIZE(Vpadded)), FIRST_XMIPP_INDEX(ZSIZE(Vpadded))); CenterFFT(Vfourier,true); Vfourier.setXmippOrigin(); // Compensate for the Fourier normalization factor double K=(double)(XSIZE(Vpadded)*XSIZE(Vpadded)*XSIZE(Vpadded))/(double)(volumeSize*volumeSize); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Vfourier) DIRECT_MULTIDIM_ELEM(Vfourier,n)*=K; Vpadded.clear(); // Compute Bspline coefficients if (BSplineDeg==3) { MultidimArray< double > VfourierRealAux, VfourierImagAux; Complex2RealImag(Vfourier, VfourierRealAux, VfourierImagAux); Vfourier.clear(); produceSplineCoefficients(BSPLINE3,VfourierRealCoefs,VfourierRealAux); produceSplineCoefficients(BSPLINE3,VfourierImagCoefs,VfourierImagAux); //VfourierRealAux.clear(); //VfourierImagAux.clear(); } else Complex2RealImag(Vfourier, VfourierRealCoefs, VfourierImagCoefs); // Allocate memory for the 2D Fourier transform projection().initZeros(volumeSize,volumeSize); projection().setXmippOrigin(); transformer2D.FourierTransform(projection(),projectionFourier,false); // Calculate phase shift terms phaseShiftImgA.initZeros(projectionFourier); phaseShiftImgB.initZeros(projectionFourier); double shift=-FIRST_XMIPP_INDEX(volumeSize); double xxshift = -2 * PI * shift / volumeSize; for (size_t i=0; i<YSIZE(projectionFourier); ++i) { double phasey=(double)(i) * xxshift; for (size_t j=0; j<XSIZE(projectionFourier); ++j) { // Phase shift to move the origin of the image to the corner double dotp = (double)(j) * xxshift + phasey; sincos(dotp,&DIRECT_A2D_ELEM(phaseShiftImgB,i,j),&DIRECT_A2D_ELEM(phaseShiftImgA,i,j)); } } }
void FourierProjector::produceSideInfo() { // Zero padding MultidimArray<double> Vpadded; int paddedDim=(int)(paddingFactor*volumeSize); volume->window(Vpadded,FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim),FIRST_XMIPP_INDEX(paddedDim), LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim),LAST_XMIPP_INDEX(paddedDim)); volume->clear(); // Make Fourier transform, shift the volume origin to the volume center and center it MultidimArray< std::complex<double> > Vfourier; transformer3D.completeFourierTransform(Vpadded,Vfourier); ShiftFFT(Vfourier, FIRST_XMIPP_INDEX(XSIZE(Vpadded)), FIRST_XMIPP_INDEX(YSIZE(Vpadded)), FIRST_XMIPP_INDEX(ZSIZE(Vpadded))); CenterFFT(Vfourier,true); Vfourier.setXmippOrigin(); // Compensate for the Fourier normalization factor double K=(double)(XSIZE(Vpadded)*XSIZE(Vpadded)*XSIZE(Vpadded))/(double)(volumeSize*volumeSize); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Vfourier) DIRECT_MULTIDIM_ELEM(Vfourier,n)*=K; Vpadded.clear(); // Compute Bspline coefficients if (BSplineDeg==3) { MultidimArray< double > VfourierRealAux, VfourierImagAux; Complex2RealImag(Vfourier, VfourierRealAux, VfourierImagAux); Vfourier.clear(); produceSplineCoefficients(BSPLINE3,VfourierRealCoefs,VfourierRealAux); produceSplineCoefficients(BSPLINE3,VfourierImagCoefs,VfourierImagAux); //VfourierRealAux.clear(); //VfourierImagAux.clear(); } else Complex2RealImag(Vfourier, VfourierRealCoefs, VfourierImagCoefs); // Allocate memory for the 2D Fourier transform projection().initZeros(volumeSize,volumeSize); projection().setXmippOrigin(); transformer2D.FourierTransform(projection(),projectionFourier,false); }
// Some image-specific operations void normalise(Image<DOUBLE> &I, int bg_radius, DOUBLE white_dust_stddev, DOUBLE black_dust_stddev, bool do_ramp) { int bg_radius2 = bg_radius * bg_radius; DOUBLE avg, stddev; if (2*bg_radius > XSIZE(I())) REPORT_ERROR("normalise ERROR: 2*bg_radius is larger than image size!"); if (white_dust_stddev > 0. || black_dust_stddev > 0.) { // Calculate initial avg and stddev values calculateBackgroundAvgStddev(I, avg, stddev, bg_radius); // Remove white and black noise if (white_dust_stddev > 0.) removeDust(I, true, white_dust_stddev, avg, stddev); if (black_dust_stddev > 0.) removeDust(I, false, black_dust_stddev, avg, stddev); } if (do_ramp) subtractBackgroundRamp(I, bg_radius); // Calculate avg and stddev (also redo if dust was removed!) calculateBackgroundAvgStddev(I, avg, stddev, bg_radius); if (stddev < 1e-10) { std::cerr << " WARNING! Stddev of image " << I.name() << " is zero! Skipping normalisation..." << std::endl; } else { // Subtract avg and divide by stddev for all pixels FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(I()) DIRECT_MULTIDIM_ELEM(I(), n) = (DIRECT_MULTIDIM_ELEM(I(), n) - avg) / stddev; } }
void ProgXrayImport::getFlatfield(const FileName &fnFFinput, Image<double> &Iavg) { // Process the flatfield images MultidimArray<double> &mdaIavg = Iavg(); Matrix1D<double> expTimeArray, cBeamArray, slitWidthArray; // Local vectors DataSource ldSource = dSource; // Checking if fnFFinput is a single file to obtain the flatfield avg from if (extFlat && isImage(fnFFinput)) { fMD.read(fnFFinput); ldSource = NONE; } else { switch (ldSource) { case MISTRAL: if (!H5File.checkDataset(fnFFinput.getBlockName().c_str())) break; { fMD.read(fnFFinput); H5File.getDataset("NXtomo/instrument/bright_field/ExpTimes", expTimeArray, false); H5File.getDataset("NXtomo/instrument/bright_field/current", cBeamArray, false); // If expTime is empty or only one single value in nexus file then we fill with 1 if (expTimeArray.size() < 2) { reportWarning("Input file does not contains flatfields' exposition time information."); expTimeArray.initConstant(fMD.size(), 1.); } // If current is empty or only one single value in nexus file then we fill with 1 if (cBeamArray.size() < 2) { reportWarning("Input file does not contains flatfields' current beam information."); cBeamArray.initConstant(fMD.size(), 1.); } } // Since Alba does not provide slit width, we set to ones slitWidthArray.initConstant(fMD.size(), 1.); break; case BESSY: { size_t objId; for (size_t i = fIni; i <= fEnd; ++i) { objId = fMD.addObject(); fMD.setValue(MDL_IMAGE, fnFFinput + formatString("/img%d.spe", i), objId); } break; } case GENERIC: { // Get Darkfield std::cout << "Getting darkfield from "+fnFFinput << " ..." << std::endl; getDarkfield(fnFFinput, IavgDark); if (darkFix) IavgDark.write(fnRoot+"_"+fnFFinput.removeDirectories()+"_darkfield.xmp"); std::vector<FileName> listDir; fnFFinput.getFiles(listDir); size_t objId; for (size_t i = 0; i < listDir.size(); ++i) { if (!listDir[i].hasImageExtension()) continue; objId = fMD.addObject(); fMD.setValue(MDL_IMAGE, fnFFinput+"/"+listDir[i], objId); } } break; } } if ( fMD.size() == 0 ) { reportWarning("XrayImport::getFlatfield: No images to process"); return; } ImageInfo imFFInfo; getImageInfo(fMD, imFFInfo); if ( (imFFInfo.adim.xdim != imgInfo.adim.xdim) || (imFFInfo.adim.ydim != imgInfo.adim.ydim) ) { reportWarning(formatString("XrayImport:: Flatfield images size %dx%d different from Tomogram images size %dx%d", imFFInfo.adim.xdim,imFFInfo.adim.ydim,imgInfo.adim.xdim,imgInfo.adim.ydim)); std::cout << "Setting crop values to fit the smallest dimensions." <<std::endl; // This shift in the crop sizes is exclusive of Mistral data cropSizeXi = (imgInfo.adim.xdim - std::min(imgInfo.adim.xdim-cropSizeX*2, imFFInfo.adim.xdim))/2 + 1; cropSizeYi = (imgInfo.adim.ydim - std::min(imgInfo.adim.ydim-cropSizeY*2, imFFInfo.adim.ydim))/2 + 1; cropSizeXe = cropSizeXi - 2; cropSizeYe = cropSizeYi - 2; } int cropX = (imFFInfo.adim.xdim - (imgInfo.adim.xdim-cropSizeXi-cropSizeXe))/2;// - 1; int cropY = (imFFInfo.adim.ydim - (imgInfo.adim.ydim-cropSizeYi-cropSizeYe))/2;// - 1; int N = 0; Image<double> Iaux; FileName fnImg; FOR_ALL_OBJECTS_IN_METADATA(fMD) { fMD.getValue(MDL_IMAGE, fnImg, __iter.objId); readAndCrop(fnImg, Iaux, cropX, cropY); if ( darkFix ) { Iaux() -= IavgDark(); forcePositive(Iaux()); } double currentBeam = 1; double expTime = 1; double slitWidth = 1; switch (ldSource) { case MISTRAL: { size_t idx = fnImg.getPrefixNumber(); currentBeam = dMi(cBeamArray, idx-1); expTime = dMi(expTimeArray, idx-1); slitWidth = dMi(slitWidthArray, idx-1); } break; case BESSY: case GENERIC: readCorrectionInfo(fnImg, currentBeam, expTime, slitWidth); break; default: break; } Iaux() *= 1.0/(currentBeam*expTime*slitWidth); if ( N == 0 ) mdaIavg = Iaux(); else mdaIavg += Iaux(); N++; } darkFix = false; // We reset just in case there is no dark field for tomo images mdaIavg*=1.0/N; /* Create a mask with zero valued pixels to apply boundaries median filter * to avoid dividing by zero when normalizing */ MultidimArray<char> &mdaMask = MULTIDIM_ARRAY(bpMask); if ( !fnBPMask.empty() && !mdaIavg.sameShape(mdaMask) ) REPORT_ERROR(ERR_MULTIDIM_SIZE, "XrayImport: Mask size does not match flat fields size."); if (BPFactor > 0) { double avg, std; mdaIavg.computeAvgStdev(avg, std); mdaMask.resize(mdaIavg, false); double th = avg - std*BPFactor; FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(mdaMask) dAi(mdaMask, n) = dAi(mdaIavg, n) < th; } else if (fnBPMask.empty()) mdaIavg.equal(0,mdaMask); MultidimArray<char> mask = mdaMask; boundMedianFilter(mdaIavg,mask); }
// Transform --------------------------------------------------------------- void FourierTransformer::Transform(int sign) { if (sign == FFTW_FORWARD) { fftw_execute(fPlanForward); if (sign == normSign) { unsigned long int size=0; if(fReal!=NULL) size = MULTIDIM_SIZE(*fReal); else if (fComplex!= NULL) size = MULTIDIM_SIZE(*fComplex); else REPORT_ERROR(ERR_UNCLASSIFIED,"No complex nor real data defined"); double isize=1.0/size; double *ptr=(double*)MULTIDIM_ARRAY(fFourier); size_t nmax=(fFourier.nzyxdim/4)*4; for (size_t n=0; n<nmax; n+=4) { *ptr++ *= isize; *ptr++ *= isize; *ptr++ *= isize; *ptr++ *= isize; *ptr++ *= isize; *ptr++ *= isize; *ptr++ *= isize; *ptr++ *= isize; } for (size_t n=nmax; n<fFourier.nzyxdim; ++n) { *ptr++ *= isize; *ptr++ *= isize; } } } else if (sign == FFTW_BACKWARD) { fftw_execute(fPlanBackward); if (sign == normSign) { unsigned long int size=0; if(fReal!=NULL) { size = MULTIDIM_SIZE(*fReal); double isize=1.0/size; FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*fReal) DIRECT_MULTIDIM_ELEM(*fReal,n) *= isize; } else if (fComplex!= NULL) { size = MULTIDIM_SIZE(*fComplex); double isize=1.0/size; double *ptr=(double*)MULTIDIM_ARRAY(*fComplex); FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*fComplex) { *ptr++ *= isize; *ptr++ *= isize; } }