/* Performes a convolution by multiplication in frequency domain in input image kernel filter kernel return output image */ Mat frequencyConvolution(Mat& in, Mat& kernel) { const int kw = kernel.cols; const int kh = kernel.rows; Mat kernelBig = Mat::zeros(in.size(), in.type()); for (int x = 0; x < kw; ++x) { for (int y = 0; y < kh; ++y) { kernelBig.at<float>(x, y) = kernel.at<float>(x, y); } } Mat kernelBigShifted = circShift(kernelBig, -(kw/2), -(kh/2)); // transform into frequency domain Mat freqIn = Mat(in.size(), CV_32FC2); // complex Mat freqKernel = Mat(kernelBigShifted.size(), CV_32FC2); // complex dft(in, freqIn); dft(kernelBigShifted, freqKernel); // multiply in frequency domain (-> convolute in spatial domain) Mat freqRes = Mat(kernelBig.size(), CV_32FC2); // complex mulSpectrums(freqIn, freqKernel, freqRes, 0); // transform back into spatial domain Mat res(in.size(), in.type()); dft(freqRes, res, DFT_INVERSE | DFT_SCALE); return res; }
static std::shared_ptr<FeatureChannels_> mulSpectrumsFeatures(const cv::Mat& Af, const std::shared_ptr<FeatureChannels_>& Bf, bool conjBf = false) { std::shared_ptr<FeatureChannels_> resf(new FeatureChannels_()); for (int i = 0; i < NUMBER_OF_CHANNELS; ++i) { mulSpectrums(Af, Bf->channels[i], resf->channels[i], 0, conjBf); } return resf; }
void ImageViewer::on_actionDFT_triggered() { cv::Mat cvMat = ASM::QPixmapToCvMat(QPixmap::fromImage(*image)); cv::Mat grayscaleMat (cvMat.size(), CV_8U); cv::cvtColor( cvMat, grayscaleMat, CV_BGR2GRAY ); int width = grayscaleMat.cols; int height = grayscaleMat.rows; cv::Mat cvMat_dft = computeDFT(grayscaleMat); cv::Mat magI; updateMag(cvMat_dft,magI); //Mat mask = createBoxMask(cvMat_dft.size(), cvMat_dft.cols/2, cvMat_dft.rows/2,cvMat_dft.cols/8,cvMat_dft.rows/8, true); Mat mask = createGausFilterMask(cvMat_dft.size(), cvMat_dft.cols/2, cvMat_dft.rows/2,cvMat_dft.cols/2,cvMat_dft.rows/2, true, true); std::cout << "before mul spect " << grayscaleMat.size() << " " << cvMat_dft.size() << " " << " " << mask.size() << std::endl; shift(mask); Mat planes[] = {Mat::zeros(cvMat_dft.size(), CV_32F), Mat::zeros(cvMat_dft.size(), CV_32F)}; Mat kernel_spec; planes[0] = mask; // real planes[1] = mask; // imaginar merge(planes, 2, kernel_spec); mulSpectrums(cvMat_dft, kernel_spec, cvMat_dft , DFT_ROWS); // only DFT_ROWS accepted cv::Mat magI2; updateMag(cvMat_dft,magI2); // show spectrum cv::Mat inverseTransform; cv::dft(cvMat_dft,inverseTransform,cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT); normalize(inverseTransform, inverseTransform, 0, 255, CV_MINMAX); cv::Mat finalImage = inverseTransform; if(width <inverseTransform.cols || height<inverseTransform.rows) { finalImage = inverseTransform(Rect(0,0,width,height)); } // Back to 8-bits cv::Mat finalImage2; finalImage.convertTo(finalImage2, CV_8U); if(!scene) scene = new QGraphicsScene; if(!view) view = new QGraphicsView(scene); if(item) { scene->clear(); //delete item; item=0; } item = new QGraphicsPixmapItem(ASM::cvMatToQPixmap(finalImage2).copy()); scene->addItem(item); view->adjustSize(); view->show(); }
static T squaredNormFeaturesNoCcs(const std::shared_ptr<FeatureChannels_>& Af) { int n = Af->channels[0].rows * Af->channels[0].cols; T sum_ = 0; cv::Mat elemMul; for (int i = 0; i < NUMBER_OF_CHANNELS; ++i) { mulSpectrums(Af->channels[i], Af->channels[i], elemMul, 0, true); sum_ += static_cast<T>(cv::sum(elemMul)[0]); } return sum_ / n; }
static T squaredNormFeaturesCcs(const std::shared_ptr<FeatureChannels_>& Af) { // TODO: this is still slow and used frequently by gaussian // correlation => find an equivalent quicker formulation; // Note that reshaping and concatenating the mats first // and then multiplying them is slower than // this current approach! int n = Af->channels[0].rows * Af->channels[0].cols; T sum_ = 0; cv::Mat elemMul; for (int i = 0; i < NUMBER_OF_CHANNELS; ++i) { mulSpectrums(Af->channels[i], Af->channels[i], elemMul, 0, true); sum_ += static_cast<T>(sumRealOfSpectrum<T>(elemMul)); } return sum_ / n; }
/* in input image kernel filter kernel return output image */ Mat Dip3::frequencyConvolution(Mat& in, Mat& kernel){ Mat tempA = Mat::zeros(in.rows, in.cols, CV_32FC1); Mat tempB = Mat::zeros(in.rows, in.cols, CV_32FC1); for (int x = 0; x < kernel.rows; x++) for (int y = 0; y < kernel.cols; y++) { tempB.at<float>(x, y) = kernel.at<float>(x, y); } tempB = circShift(tempB, -1, -1); dft(in, tempA, 0); dft(tempB, tempB, 0); mulSpectrums(tempA, tempB, tempB, 0); dft(tempB, tempA, DFT_INVERSE + DFT_SCALE); return tempA; }
void DenseGaussKernel(float sigma, const Mat &x,const Mat &y, Mat &k){ Mat xf, yf; dft(x, xf, DFT_COMPLEX_OUTPUT); dft(y, yf, DFT_COMPLEX_OUTPUT); double xx = norm(x); xx = xx*xx; double yy = norm(y); yy = yy*yy; Mat xyf; mulSpectrums(xf, yf, xyf, 0, true); Mat xy; cv::idft(xyf, xy, cv::DFT_SCALE | cv::DFT_REAL_OUTPUT); // Applying IDFT CircShift(xy, scale_size(x.size(),0.5)); double numelx1 = x.cols*x.rows; //exp((-1 / (sigma*sigma)) * abs((xx + yy - 2 * xy) / numelx1), k); //thsi setting is fixed by version 2(KCF) exp((-1 / (sigma*sigma)) * max(0,(xx + yy - 2 * xy) / numelx1), k); }
/* in input image kernel filter kernel return output image */ Mat Dip3::frequencyConvolution(Mat& in, Mat& kernel){ Mat freq_in, freq_kernel, result; //copy kernel to large matrix (the size of input image) cv::Rect roi(cv::Point(0,0),kernel.size()); Mat destinationROI = Mat::zeros(in.size(), in.type()); kernel.copyTo(destinationROI(roi)); //perform circ shift on kernel Mat circ_kernel = circShift(destinationROI, -kernel.cols/2, -kernel.rows/2); //convert to frequency domains dft(in, freq_in, 0); dft(circ_kernel, freq_kernel, 0); //multiplication in freq domains mulSpectrums(freq_in, freq_kernel, freq_in,0); //convert to spatial domain dft(freq_in, result, DFT_INVERSE + DFT_SCALE); return result; }
void PhaseCorrelation::controller(const sensor_msgs::ImageConstPtr& msg) { //Transform the image to opencv format cv_bridge::CvImagePtr cv_ptr; try { cv_ptr = cv_bridge::toCvCopy(msg, enc::BGR8); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } Mat image = cv_ptr->image; imshow("image", image); waitKey(1); //Transform image to grayscale cvtColor(image, image2_in, CV_RGB2GRAY); //Image2 is the newest image, the one we get from this callback //image1 is the image2 from the last callback (we use the one that already has the dft applied. Mat image1_dft = last_image_dft; //Image2, preparation and dft Mat padded2; //expand input image to optimal size int m2 = getOptimalDFTSize( image2_in.rows ); int n2 = getOptimalDFTSize( image2_in.cols ); // on the border add zero values copyMakeBorder(image2_in, padded2, 0, m2 - image2_in.rows, 0, n2 - image2_in.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes2[] = {Mat_<float>(padded2), Mat::zeros(padded2.size(), CV_32F)}; Mat image2,image2_dft; merge(planes2, 2, image2); // Add to the expanded another plane with zeros dft(image2, image2_dft); //Image2 will be image1 on next iteration last_image_dft=image2_dft; if( !first){ //obtain the cross power spectrum c(u,v)=F(u,v)·G*(u,v)/abs(F(u,v)·G*(u,v)) Mat divident, divisor, cross_power_spec, trans_mat; mulSpectrums(image1_dft, image2_dft, divident, 0, true); //=F(u,v)·G*(u,v) --> multiply the result of a dft //divident-> where it stores the result. // flags=0. conj=true, because i want the image2 to be the complex conjugate. divisor=abs(divident); divide(divident, divisor, cross_power_spec, 1); //dft of the cross_power_spec dft(cross_power_spec, trans_mat, DFT_INVERSE); //Normalize the trans_mat so that all the values are between 0 and 1 normalize(trans_mat, trans_mat, NORM_INF); //Split trans_mat in it's real and imaginary parts vector<Mat> trans_mat_vector; split(trans_mat, trans_mat_vector); Mat trans_mat_real = trans_mat_vector.at(0); Mat trans_mat_im = trans_mat_vector.at(1); imshow("trans_mat_real", trans_mat_real); waitKey(1); //Look for maximum value and it's location on the trans_mat_real matrix double* max_value; Point* max_location; double max_val; Point max_loc; max_value = &max_val; max_location = &max_loc; minMaxLoc(trans_mat_real, NULL, max_value, NULL, max_location); ROS_INFO_STREAM("max_value: " << max_val << " - " << "max_location: " << max_loc); int pixel_x, pixel_y; if(max_loc.x < (image2.cols/2) && max_loc.y < (image2.rows/2)){ // top-left quadrant ROS_INFO_STREAM(" top - left quadrant"); pixel_x = max_loc.x; pixel_y = - max_loc.y; } if(max_loc.x > (image2.cols/2) && max_loc.y > (image2.rows/2)){ // lower-right quadrant ROS_INFO_STREAM(" lower - right quadrant"); pixel_x = - image2.cols + max_loc.x; pixel_y = + image2.rows - max_loc.y; } if(max_loc.x > (image2.cols/2) && max_loc.y < (image2.rows/2)){ // top-right quadrant ROS_INFO_STREAM(" top - right quadrant"); pixel_x = - image2.cols + max_loc.x; pixel_y = - max_loc.y; } if(max_loc.x < (image2.cols/2) && max_loc.y > (image2.rows/2)){ // lower-left quadrant ROS_INFO_STREAM(" lower - left quadrant"); pixel_x = max_loc.x; pixel_y = image2.rows - max_loc.y; } //Add the new displacement to the accumulated pixels_x = pixels_x + pixel_x; pixels_y = pixels_y + pixel_y; ROS_INFO_STREAM("pixels_x: " << pixels_x << " - " << "pixel_y: " << pixels_y); //------ transform pixels to mm --------- //To get the focal lenght: if (first){ Mat cameraMatrix(3, 3, CV_32F); cameraMatrix.at<float>(0,0)= 672.03175; //Values from the camera matrix are from the visp calibration cameraMatrix.at<float>(0,1) = 0.00000; cameraMatrix.at<float>(0,2) = 309.39349; cameraMatrix.at<float>(1,0) = 0.00000; cameraMatrix.at<float>(1,1) = 673.05595; cameraMatrix.at<float>(1,2) = 166.52006; cameraMatrix.at<float>(2,0) = 0.00000; cameraMatrix.at<float>(2,1) = 0.00000; cameraMatrix.at<float>(2,2) = 1.00000; double apertureWidth, apertureHeight, fovx, fovy, focalLength, aspectRatio; Point2d principalPoint; calibrationMatrixValues(cameraMatrix, image.size(), apertureWidth, apertureHeight, fovx, fovy, focalLength, principalPoint, aspectRatio); ROS_INFO_STREAM("focalLength: " << focalLength); fl = focalLength; first=false; } float mov_x = pixel_x/fl*h; float mov_y = pixel_y/fl*h; mov_x_acc = mov_x_acc + mov_x; mov_y_acc = mov_y_acc + mov_y; ROS_INFO_STREAM("mov_x: " << mov_x << " - mov_y: " << mov_y); ROS_INFO_STREAM("mov_x_acc: " << mov_x_acc << " - mov_y_acc: " << mov_y_acc); } }
void crossCorr( const Mat& img, const Mat& _templ, Mat& corr, Size corrsize, int ctype, Point anchor, double delta, int borderType ) { const double blockScale = 4.5; const int minBlockSize = 256; std::vector<uchar> buf; Mat templ = _templ; int depth = img.depth(), cn = img.channels(); int tdepth = templ.depth(), tcn = templ.channels(); int cdepth = CV_MAT_DEPTH(ctype), ccn = CV_MAT_CN(ctype); CV_Assert( img.dims <= 2 && templ.dims <= 2 && corr.dims <= 2 ); if( depth != tdepth && tdepth != std::max(CV_32F, depth) ) { _templ.convertTo(templ, std::max(CV_32F, depth)); tdepth = templ.depth(); } CV_Assert( depth == tdepth || tdepth == CV_32F); CV_Assert( corrsize.height <= img.rows + templ.rows - 1 && corrsize.width <= img.cols + templ.cols - 1 ); CV_Assert( ccn == 1 || delta == 0 ); corr.create(corrsize, ctype); int maxDepth = depth > CV_8S ? CV_64F : std::max(std::max(CV_32F, tdepth), cdepth); Size blocksize, dftsize; blocksize.width = cvRound(templ.cols*blockScale); blocksize.width = std::max( blocksize.width, minBlockSize - templ.cols + 1 ); blocksize.width = std::min( blocksize.width, corr.cols ); blocksize.height = cvRound(templ.rows*blockScale); blocksize.height = std::max( blocksize.height, minBlockSize - templ.rows + 1 ); blocksize.height = std::min( blocksize.height, corr.rows ); dftsize.width = std::max(getOptimalDFTSize(blocksize.width + templ.cols - 1), 2); dftsize.height = getOptimalDFTSize(blocksize.height + templ.rows - 1); if( dftsize.width <= 0 || dftsize.height <= 0 ) CV_Error( CV_StsOutOfRange, "the input arrays are too big" ); // recompute block size blocksize.width = dftsize.width - templ.cols + 1; blocksize.width = MIN( blocksize.width, corr.cols ); blocksize.height = dftsize.height - templ.rows + 1; blocksize.height = MIN( blocksize.height, corr.rows ); Mat dftTempl( dftsize.height*tcn, dftsize.width, maxDepth ); Mat dftImg( dftsize, maxDepth ); int i, k, bufSize = 0; if( tcn > 1 && tdepth != maxDepth ) bufSize = templ.cols*templ.rows*CV_ELEM_SIZE(tdepth); if( cn > 1 && depth != maxDepth ) bufSize = std::max( bufSize, (blocksize.width + templ.cols - 1)* (blocksize.height + templ.rows - 1)*CV_ELEM_SIZE(depth)); if( (ccn > 1 || cn > 1) && cdepth != maxDepth ) bufSize = std::max( bufSize, blocksize.width*blocksize.height*CV_ELEM_SIZE(cdepth)); buf.resize(bufSize); // compute DFT of each template plane for( k = 0; k < tcn; k++ ) { int yofs = k*dftsize.height; Mat src = templ; Mat dst(dftTempl, Rect(0, yofs, dftsize.width, dftsize.height)); Mat dst1(dftTempl, Rect(0, yofs, templ.cols, templ.rows)); if( tcn > 1 ) { src = tdepth == maxDepth ? dst1 : Mat(templ.size(), tdepth, &buf[0]); int pairs[] = {k, 0}; mixChannels(&templ, 1, &src, 1, pairs, 1); } if( dst1.data != src.data ) src.convertTo(dst1, dst1.depth()); if( dst.cols > templ.cols ) { Mat part(dst, Range(0, templ.rows), Range(templ.cols, dst.cols)); part = Scalar::all(0); } dft(dst, dst, 0, templ.rows); } int tileCountX = (corr.cols + blocksize.width - 1)/blocksize.width; int tileCountY = (corr.rows + blocksize.height - 1)/blocksize.height; int tileCount = tileCountX * tileCountY; Size wholeSize = img.size(); Point roiofs(0,0); Mat img0 = img; if( !(borderType & BORDER_ISOLATED) ) { img.locateROI(wholeSize, roiofs); img0.adjustROI(roiofs.y, wholeSize.height-img.rows-roiofs.y, roiofs.x, wholeSize.width-img.cols-roiofs.x); } borderType |= BORDER_ISOLATED; // calculate correlation by blocks for( i = 0; i < tileCount; i++ ) { int x = (i%tileCountX)*blocksize.width; int y = (i/tileCountX)*blocksize.height; Size bsz(std::min(blocksize.width, corr.cols - x), std::min(blocksize.height, corr.rows - y)); Size dsz(bsz.width + templ.cols - 1, bsz.height + templ.rows - 1); int x0 = x - anchor.x + roiofs.x, y0 = y - anchor.y + roiofs.y; int x1 = std::max(0, x0), y1 = std::max(0, y0); int x2 = std::min(img0.cols, x0 + dsz.width); int y2 = std::min(img0.rows, y0 + dsz.height); Mat src0(img0, Range(y1, y2), Range(x1, x2)); Mat dst(dftImg, Rect(0, 0, dsz.width, dsz.height)); Mat dst1(dftImg, Rect(x1-x0, y1-y0, x2-x1, y2-y1)); Mat cdst(corr, Rect(x, y, bsz.width, bsz.height)); for( k = 0; k < cn; k++ ) { Mat src = src0; dftImg = Scalar::all(0); if( cn > 1 ) { src = depth == maxDepth ? dst1 : Mat(y2-y1, x2-x1, depth, &buf[0]); int pairs[] = {k, 0}; mixChannels(&src0, 1, &src, 1, pairs, 1); } if( dst1.data != src.data ) src.convertTo(dst1, dst1.depth()); if( x2 - x1 < dsz.width || y2 - y1 < dsz.height ) copyMakeBorder(dst1, dst, y1-y0, dst.rows-dst1.rows-(y1-y0), x1-x0, dst.cols-dst1.cols-(x1-x0), borderType); dft( dftImg, dftImg, 0, dsz.height ); Mat dftTempl1(dftTempl, Rect(0, tcn > 1 ? k*dftsize.height : 0, dftsize.width, dftsize.height)); mulSpectrums(dftImg, dftTempl1, dftImg, 0, true); dft( dftImg, dftImg, DFT_INVERSE + DFT_SCALE, bsz.height ); src = dftImg(Rect(0, 0, bsz.width, bsz.height)); if( ccn > 1 ) { if( cdepth != maxDepth ) { Mat plane(bsz, cdepth, &buf[0]); src.convertTo(plane, cdepth, 1, delta); src = plane; } int pairs[] = {0, k}; mixChannels(&src, 1, &cdst, 1, pairs, 1); } else { if( k == 0 ) src.convertTo(cdst, cdepth, 1, delta); else { if( maxDepth != cdepth ) { Mat plane(bsz, cdepth, &buf[0]); src.convertTo(plane, cdepth); src = plane; } add(src, cdst, cdst); } } } } }
static bool convolve_dft(InputArray _image, InputArray _templ, OutputArray _result) { ConvolveBuf buf; CV_Assert(_image.type() == CV_32F); CV_Assert(_templ.type() == CV_32F); buf.create(_image.size(), _templ.size()); _result.create(buf.result_size, CV_32F); UMat image = _image.getUMat(); UMat templ = _templ.getUMat(); UMat result = _result.getUMat(); Size& block_size = buf.block_size; Size& dft_size = buf.dft_size; UMat& image_block = buf.image_block; UMat& templ_block = buf.templ_block; UMat& result_data = buf.result_data; UMat& image_spect = buf.image_spect; UMat& templ_spect = buf.templ_spect; UMat& result_spect = buf.result_spect; UMat templ_roi = templ; copyMakeBorder(templ_roi, templ_block, 0, templ_block.rows - templ_roi.rows, 0, templ_block.cols - templ_roi.cols, BORDER_ISOLATED); dft(templ_block, templ_spect, 0, templ.rows); // Process all blocks of the result matrix for (int y = 0; y < result.rows; y += block_size.height) { for (int x = 0; x < result.cols; x += block_size.width) { Size image_roi_size(std::min(x + dft_size.width, image.cols) - x, std::min(y + dft_size.height, image.rows) - y); Rect roi0(x, y, image_roi_size.width, image_roi_size.height); UMat image_roi(image, roi0); copyMakeBorder(image_roi, image_block, 0, image_block.rows - image_roi.rows, 0, image_block.cols - image_roi.cols, BORDER_ISOLATED); dft(image_block, image_spect, 0); mulSpectrums(image_spect, templ_spect, result_spect, 0, true); dft(result_spect, result_data, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT | cv::DFT_SCALE); Size result_roi_size(std::min(x + block_size.width, result.cols) - x, std::min(y + block_size.height, result.rows) - y); Rect roi1(x, y, result_roi_size.width, result_roi_size.height); Rect roi2(0, 0, result_roi_size.width, result_roi_size.height); UMat result_roi(result, roi1); UMat result_block(result_data, roi2); result_block.copyTo(result_roi); } } return true; }
int main(int argc, char **argv){ int opcion; //Opcion para el getopt int vflag=0, rflag=0, nflag=0, glfag=0, iflag=0, mflag=0, oflag=0; //Flags para el getopt float r=0.5, g=1.0; int n=2; string nombreImagen; string nombreMascara; string nombreSalida = "output.png"; Mat imagen, padded, complexImg, filter, filterAux, imagenSalida, filterSalida, imagenFrecuencias, imagenFrecuenciasSinOrden, imagenHSV; Mat complexAux; Mat salida; Mat imagenPasoBaja; Mat mascara; vector<Mat> canales; while((opcion=getopt(argc, argv, "vr:n:g:i:o:m:")) !=-1 ){ switch(opcion){ case 'v': vflag=1; break; case 'r': rflag=1; r=atof(optarg); if(r<0 || r>1){ cout << "Valor de 'r' introducido invalido" << endl; exit(-1); } break; case 'n': nflag=1; n = atoi(optarg); if(n<0 || n>10){ cout << "Valor de 'n' introducido invalido" << endl; exit(-1); } break; case 'g': glfag=1; g = atof(optarg); if(g<0.0 || g>5.0){ cout << "Valor de 'g' introducido invalido" << endl; exit(-1); } break; case 'i': iflag=1; nombreImagen = optarg; break; case 'm': mflag=1; nombreMascara=optarg; break; case 'o': oflag=1; nombreSalida=optarg; break; case '?': //Algo ha ido mal help(); exit(-1); break; default: help(); exit(-1); break; } } //Primero cargaremos la imagen if(iflag==1){ imagen = imread(nombreImagen, CV_LOAD_IMAGE_ANYDEPTH); if(imagen.empty()){ cout << "Imagen especificada invalida" << endl; exit(-1); }else{ cout << "Imagen cargada con exito" << endl; if(vflag==1){ namedWindow("Imagen", CV_WINDOW_AUTOSIZE); imshow("Imagen", imagen); waitKey(0); destroyWindow("Imagen"); } } }else{ cout << "La imagen es necesaria" << endl; exit(-1); } //Calculamos r r=(r)*(sqrt(pow((imagen.rows),2.0)+pow((imagen.cols),2.0))/2); int M = getOptimalDFTSize(imagen.rows); int N = getOptimalDFTSize(imagen.cols); //Miramos si tiene mascara para cargarla if(mflag==1){ //Cargamos la mascara mascara = imread(nombreMascara, 0); if(mascara.empty()){ cout << "Mascara especificada invalida" << endl; exit(-1); }else{ cout << "Mascara cargada con exito" << endl; } } //Ahora miramos los canales para hacer cosas distintas dependiendo if(imagen.channels()==1){ //Imagen monocromatica imagen.convertTo(imagenPasoBaja,CV_32F, 1.0/255.0); copyMakeBorder(imagenPasoBaja, padded, 0, M-imagenPasoBaja.rows, 0, N - imagenPasoBaja.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; merge(planes, 2, complexImg); dft(complexImg, complexImg); filter = complexImg.clone(); filterAux = complexImg.clone(); complexAux = complexImg.clone(); shiftDFT(complexImg); shiftDFT(complexAux); butterworth(filter, r, n); butterworth(filterAux, r, 0); mulSpectrums(complexImg, filter, complexImg, 0); mulSpectrums(complexAux, filterAux, complexAux, 0); shiftDFT(complexImg); shiftDFT(complexAux); //Falta hacer lo de poder mostrarla imagenFrecuencias = create_spectrum(complexImg); imagenFrecuenciasSinOrden = create_spectrum(complexAux); //Hacemos la inversa idft(complexImg, complexImg, DFT_SCALE); split(complexImg, planes); normalize(planes[0], imagenSalida, 0, 1, CV_MINMAX); split(filter, planes); normalize(planes[0], filterSalida, 0, 1, CV_MINMAX); salida = imagenPasoBaja.clone(); if(mflag==1){ //Con mascara procesaremos pixel por pixel //Recorremos la imagen for(int i=0; i<imagen.rows; i++){ for(int j=0; j<imagen.cols;j++){ if(mascara.at<uchar>(i,j)!=0){ salida.at<float>(i,j) = (g+1)*(imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } }else{ //Sin mascara lo haremos de forma inmediata for(int i=0; i<imagen.rows; i++){ for(int j=0; j<imagen.cols;j++){ salida.at<float>(i,j) = ((g+1)*imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } salida.convertTo(salida, CV_8U, 255.0, 0.0); if(vflag==1){ imshow("Imagen final", salida); imshow("Filtro Butterworth", filterSalida); imshow("Espectro", imagenFrecuencias); imshow("Espectro de imagen sin orden", imagenFrecuenciasSinOrden); waitKey(0); } }else{ //Spliteamos la imagen en canales cvtColor(imagen, imagenHSV, CV_BGR2HSV); split(imagenHSV, canales); Mat temporal; canales[2].convertTo(imagenPasoBaja, CV_32F, 1.0/255.0); copyMakeBorder(imagenPasoBaja, padded, 0, M-imagenPasoBaja.rows, 0, N - imagenPasoBaja.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; merge(planes, 2, complexImg); dft(complexImg, complexImg); filter = complexImg.clone(); shiftDFT(complexImg); butterworth(filter, r, n); mulSpectrums(complexImg, filter, complexImg, 0); shiftDFT(complexImg); //Falta hacer lo de poder mostrarla imagenFrecuencias = create_spectrum(complexImg); //Hacemos la inversa idft(complexImg, complexImg, DFT_SCALE); split(complexImg, planes); normalize(planes[0], imagenSalida, 0, 1, CV_MINMAX); split(filter, planes); normalize(planes[0], filterSalida, 0, 1, CV_MINMAX); Mat salida = imagen.clone(); canales[2] = imagenPasoBaja.clone(); if(mflag==1){ //Con mascara for(int i=0; i<canales[2].rows; i++){ for(int j=0; j<canales[2].cols;j++){ if(mascara.at<uchar>(i,j)!=0){ canales[2].at<float>(i,j) = ((g+1)*imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } }else{ //Sin mascara for(int i=0; i<canales[2].rows; i++){ for(int j=0; j<canales[2].cols;j++){ canales[2].at<float>(i,j) = ((g+1)*imagenPasoBaja.at<float>(i,j)) - (g*imagenSalida.at<float>(i,j)); } } } canales[2].convertTo(canales[2], CV_8U, 255.0, 0.0); merge(canales, salida); cvtColor(salida, salida, CV_HSV2BGR); salida.convertTo(salida, CV_8U, 255.0, 0.0); if(vflag==1){ imshow("Imagen final", salida); imshow("Filtro Butterworth", filterSalida); imshow("Espectro", imagenFrecuencias); imshow("Espectro de imagen sin orden", imagenFrecuenciasSinOrden); waitKey(0); } } //Y escribimos la imagen a fichero imwrite(nombreSalida, salida); return 0; }
/* degraded : degraded input image filter : filter which caused degradation return : restorated output image */ Mat Dip4::inverseFilter(Mat& degraded, Mat& filter){ // be sure not to touch them degraded = degraded.clone(); filter = filter.clone(); Mat tempA = Mat::zeros(degraded.size(), CV_32FC1); Mat degradedFreq = degraded.clone(); Mat filterFreq = Mat::zeros(degraded.size(), CV_32F); // add Border for (int x = 0; x < filter.rows; x++) for (int y = 0; y < filter.cols; y++) { filterFreq.at<float>(x, y) = filter.at<float>(x, y); } filterFreq = circShift(filterFreq, -1, -1); // transform to complex Mat planes[] = {degradedFreq, Mat::zeros(degraded.size(), CV_32F)}; Mat planesFilter[] = {filterFreq, Mat::zeros(filterFreq.size(), CV_32F)}; merge(planes, 2, degradedFreq); merge(planesFilter, 2, filterFreq); // convert to frequency spectrum dft(degradedFreq, degradedFreq, DFT_COMPLEX_OUTPUT); // degradedFreq == S dft(filterFreq, filterFreq, DFT_COMPLEX_OUTPUT); // filterFreq == P // create Q split(filterFreq, planes); Mat Re = planes[0]; Mat Im = planes[1]; // calculate Threshold double thresholdFactor = 0.05, threshold; double max = 0; // find maximum for (int x = 0; x < filterFreq.rows; x++) for (int y = 0; y < filterFreq.cols; y++) { float resq = Re.at<float>(x, y) * Re.at<float>(x, y); float imsq = Im.at<float>(x, y) * Im.at<float>(x, y); float absreim = sqrt(resq + imsq); if (absreim > max) { max = absreim; } } threshold = thresholdFactor * max; for (int x = 0; x < filterFreq.rows; x++) for (int y = 0; y < filterFreq.cols; y++) { float resq = Re.at<float>(x, y) * Re.at<float>(x, y); float imsq = Im.at<float>(x, y) * Im.at<float>(x, y); float absreim = sqrt(resq + imsq); if (absreim >= threshold) { Re.at<float>(x, y) = Re.at<float>(x, y) / (resq + imsq); Im.at<float>(x, y) = Im.at<float>(x, y) / (resq + imsq); } else { Re.at<float>(x, y) = 0; Im.at<float>(x, y) = 0; } } Mat Q = Mat::zeros(filterFreq.size(), CV_32F); merge(planes, 2, Q); Mat original; mulSpectrums(degradedFreq, Q, original, 1); dft(original, original, DFT_INVERSE + DFT_SCALE); split(original, planes); original = planes[0]; normalize(original, original, 0, 255, CV_MINMAX); original.convertTo(original, CV_8UC1); return original; }
static Mat inverseAndWiener(Mat& s, Mat& p, double snr, bool inverse) { const bool wiener = !inverse; // Pad input image to avoid ringing artifacts along image borders. int bH = p.cols; int bV = p.rows; Mat sBorder; copyMakeBorder(s, sBorder, bV, bV, bH, bH, BORDER_REPLICATE); // Allocate some memory like it is going out of style. Mat pBigShifted = Mat::zeros(sBorder.size(), CV_32F); Mat P = Mat::zeros(sBorder.size(), CV_32F); Mat S = Mat::zeros(sBorder.size(), CV_32F); Mat OApprox = Mat::zeros(sBorder.size(), CV_32F); Mat oApprox = Mat::zeros(sBorder.size(), CV_32F); // Shift kernel. const int pHalf = p.rows / 2; circShiftXXX(p, pBigShifted, -pHalf, -pHalf); // Transform shifted kernel and degrated input image into frequency domain. // Note: DFT_COMPLEX_OUTPUT means that we want the complex result to be stored // in a two-channel matrix as opposed to the default compressed output. dft(pBigShifted, P, DFT_COMPLEX_OUTPUT); dft(sBorder, S, DFT_COMPLEX_OUTPUT); if (inverse) { const double epsilon = 0.05f; // Remove frequencies whose magnitude is below epsilon * max(freqKernel magnitude). double maxMagnitude; minMaxLoc(abs(P), 0, &maxMagnitude); const double threshold = maxMagnitude * epsilon; for (int ri = 0; ri < P.rows; ri++) { for (int ci = 0; ci < P.cols; ci++) { if (norm(P.at<Vec2f>(ri, ci)) < threshold) { P.at<Vec2f>(ri, ci) = threshold; } } } } // OpenCV only provides a multiplication operation for complex matrices, so we need // to calculate the inverse (1/H) of our filter spectrum first. Since it is complex // we need to compute 1/H = H*/(HH*) = H*/(Re(H)^2+Im(H)^2), where H* -> complex conjugate of H. // Multiply spectrum of the degrated image with the complex conjugate of the frequency spectrum // of the filter. const bool conjFreqKernel = true; mulSpectrums(S, P, OApprox, DFT_COMPLEX_OUTPUT, conjFreqKernel); // I * H* // Split kernel spectrum into real and imaginary parts. Mat PChannels[] = {Mat::zeros(sBorder.size(), CV_32F), Mat::zeros(sBorder.size(), CV_32F)}; split(P, PChannels); // 0:real, 1:imaginary // Calculate squared magnitude (Re(H)^2 + Im(H)^2) of filter spectrum. Mat freqKernelSqMagnitude = Mat::zeros(sBorder.rows, sBorder.cols, CV_32F); magnitude(PChannels[0], PChannels[1], freqKernelSqMagnitude); // freqKernelSqMagnitude = magnitude pow(PChannels[0], 2, freqKernelSqMagnitude); // freqKernelSqMagnitude = magnitude^2 = Re(H)^2 + Im(H)^2 if (wiener) { // Add 1 / SNR^2 to the squared filter kernel magnitude. freqKernelSqMagnitude += 1 / pow(snr, 2.0); } // Split frequency spectrum of degradedPadded image into real and imaginary parts. Mat OApproxChannels[] = {Mat::zeros(sBorder.size(), CV_32FC1), Mat::zeros(sBorder.size(), CV_32F)}; split(OApprox, OApproxChannels); // Divide each plane by the squared magnitude of the kernel frequency spectrum. // What we have done up to this point: (I * H*) / (Re(H)^2 + Im(H)^2) = I/H divide(OApproxChannels[0], freqKernelSqMagnitude, OApproxChannels[0]); // Re(I) / (Re(H)^2 + Im(H)^2) divide(OApproxChannels[1], freqKernelSqMagnitude, OApproxChannels[1]); // Im(I) / (Re(H)^2 + Im(H)^2) // Merge real and imaginary parts of the image frequency spectrum. merge(OApproxChannels, 2, OApprox); // Inverse DFT. // Note: DFT_REAL_OUTPUT means that we want the output to be a one-channel matrix again. dft(OApprox, oApprox, DFT_INVERSE | DFT_SCALE | DFT_REAL_OUTPUT); // Crop output image to original size. oApprox = oApprox(Rect(bH, bV, oApprox.cols - (bH * 2), oApprox.rows - (bV * 2))); return oApprox; }