public void InverseT(UMat reIn, UMat imIn, UMat magOut, UMat phOut) { ///accepts real and imaginary parts, inverse (fourier) Transforms ///converts real and imaginary output parts to magnitude and ///phase, returns magnitude and phase parts. ///Refer to ForwardT() for more info on why I code like this. ///Reference: https://stackoverflow.com/questions/16812950/how-do-i-compute-dft-and-its-reverse-with-emgu VectorOfUMat vec = this.vec; vec.Push(reIn); vec.Push(imIn); UMat cImg = this.img32f2c; CvInvoke.Merge(vec, cImg); //because Dft method accepts and outputs 2-channel image CvInvoke.Dft(cImg, cImg, DxtType.Inverse, 0); //new objects put into vec, vec[0] is reOut, vec[1] is imOut. CvInvoke.Split(cImg, vec); //convert output of inverse Transform to magnitude and polar CvInvoke.CartToPolar(vec[0], vec[1], magOut, phOut); vec.Clear(); }
public void ProcessForwardT(UMat inImg, UMat outMagT, UMat outPhT, bool zeroPad = false, bool switchQuadrants = true) { ///Accepts a 1-channel image, updates outMagT and outPhT. ///magnitude and phase, cause I can't think of why you ///would wanna look at real and imaginary Transforms. ///Also can't think of how you can get complex-valued images. ///Quadrant rearranging doesn't support odd rows or cols. ///T stuff, reference: https://docs.opencv.org/master/d8/d01/tutorial_discrete_fourier_transform.html //convert image to 32bit float because spacial frequency //domain values are way bigger than spatial domain values. UMat re = outMagT; //32-bit float real image, use memory from //outMagT cause it's gonna be updated anyway inImg.ConvertTo(re, DepthType.Cv32F); if (zeroPad) { //zero pad for faster dft ZeroPadImage(re); } //create imaginary image of zeros of same depthType //and size as image representing real plane UMat im = outPhT; //imaginary im.Create(re.Rows, re.Cols, re.Depth, re.NumberOfChannels); //allocate memory so you can set it to zero array //if memory hasn't already been allocated for it im.SetTo(new MCvScalar(0)); /// Quick exerpt about VectorOfUMat: /// if you create a VectorOfUMat vec, only if the first UMat variable /// to store the object is the vector node, like /// VectorOfUMat vec = new VectorOfUmat(new Umat(), new Umat()); /// vec.Push(someUMat.Clone()); /// then vec.Dispose/Clear actually disposes all the objects referenced /// to by the UMats in vec. In this case, if you did: /// VectorOfUMat vec = new VectorOfUMat(inImg.Clone(), inImg.Clone()); /// UMat one = vec[0]; /// one.Dispose(); /// one.Dispose actually does nothing. /// Otherwise, if /// UMat one = new UMat(); /// UMat two = new UMat(); /// VectorOfUMat vec = new VectorOfUmat(one); /// vec.Push(two); /// calling vec.Dispose() doesn't dispose the objects. /// you have to call one.Dispose and two.Dispose. /// Note: no matter whether the UMat's first variable stored /// in is in a vector node or not, calling vec[index].Dispose /// does NOTHING. /// The situation is the same for vec.Clear, except Clear doesn't /// dispose of vec itself, it just disposes the objects the UMats in /// it reference to. //Dft accepts 2-channel images, so we use Merge to merge //our 2 1-channel images into a single 2-channel image. //Merge accepts object arrays, so we create a VectorOfUMat //of our 2 images to feed into Merge. VectorOfUMat vec = this.vec; UMat cImg = this.img32f2c; vec.Push(re); vec.Push(im); //vec[0] = re, vec[1] = im ; CvInvoke.Merge(vec, cImg); CvInvoke.Dft(cImg, cImg, DxtType.Forward, 0); //use back the same memory //switch quadrants while images are still combined if (switchQuadrants) { SwitchQuadrants(cImg); } //make the 2-channel array into 2 1-channel arrays CvInvoke.Split(cImg, vec); //vec[0] is reT, vec[1] is imT, they are new objects. CvInvoke.CartToPolar(vec[0], vec[1], outMagT, outPhT); vec.Clear(); //dispose reT and imT.TODO: find a way to get rid of allocating memory for reT and imT. }