赞
踩
使用C++和OpenCV库来实现MATLAB中imread、fspecial和imfilter的读取图像,并应用滤波器的功能实现图像的模拟运动模糊。确保你已经安装了OpenCV库并正确配置了你的C++项目以使用它。
originalRGB = imread('peppers.png');
imshow(originalRGB);
h = fspecial('motion', 50, 45);%创建一个滤波器
filteredRGB = imfilter(originalRGB, h);
imshow(filteredRGB);
imfilter函数是一种计算机函数,也叫做实现线性空间滤波函数,功能是对任意类型数组或多维图像进行滤波,函数形式是B = imfilter(A,H)。
imfilter函数
函数形式 B = IMFILTER()
函数功能
对数组或多维图像进行滤波
函数形式
imfilter函数解释
用法:
B = imfilter(A,H) B = imfilter(A,H,option1,option2,…)
或写作
g = imfilter(f, w, filtering_mode, boundary_options, size_options)其中,f为输入图像,w为滤波掩模,g为滤波后图像。filtering_mode用于指定在滤波过程中是使用“相关”还是“卷积”。boundary_options用于处理边界充零问题,边界的大小由滤波器的大小确定。
以下示例代码中的fspecial(‘motion’,…)并没有直接的OpenCV对应函数,所以使用了一个一维高斯滤波器并旋转它以模拟运动模糊。然而,这只是一个近似的方法,可能不会完全等同于MATLAB的fspecial(‘motion’,…)。以下是一个使用OpenCV在C++中实现类似功能的示例代码:
/* OpenCV4的安装 sudo apt install gcc sudo apt install g++ sudo apt install cmake sudo apt install libgtk2.0-dev sudo apt install pkg-config unzip opencv-4.5.5.zip cd opencv-4.5.5 mkdir build cmake .. make -j2 cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local .. make -j2 sudo make install 配置环境变量 1、进入root权限,在终端输入: sudo -i vim /etc/ld.so.conf.d/opencv.conf 2、在vim中进入编辑模式输入:/usr/local/lib,退出保存。 按下“i”进入插入模式 输入“/usr/local/lib” 按下“Esc”退出插入模式 保存并退出Vim:按下'Shift'键,然后输入':',接着输入‘wq’并按下'Enter'。 3、在终端输入:vim /etc/bash.bashrc,进入bash.bashrc文件,在尾行输入: PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lic/pkgconfig export PKG_CONFIG_PATH 4、配置成功,退出root。 exit ldconfig -v | grep opencv sudo apt-get install libopencv-dev OpenCV2的安装 OpenCV Github地址:GitHub - opencv/opencv: Open Source Computer Vision Library 先选择2.4的分支,然后下载zip包或者用git下载 git clone -b 2.4 https://github.com/opencv/opencv.git sudo apt install gcc sudo apt install g++ sudo apt install cmake sudo apt install libgtk2.0-dev sudo apt install pkg-config unzip opencv-2.4.13.7.zip cd opencv-2.4.13.7 mkdir build cmake .. make -j2 cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local .. make -j2 sudo make install 然后解压缩编译等等其他的步骤就参考上面的代码段,是一样的! 在cmake的时候应该是会报错,然后报错信息见日志: 1. fatal error: sys/videoio.h: No such file or directory, 解决方式 // cmake .. 替换成下面 cmake .. -DCMAKE_BUILD_TYPE=Release -DCUDA_nppi_LIBRARY=true -DWITH_CUDA=OFF -DBUILD_TIFF=ON 2. 可能还有一个是版本不能识别的问题 CPACK_PACKAGE_VERSION does not match version provided by version.hpp 大概是这样, 解决方式 修改opencv目录下的CMakeList.txt set(OPENCV_VCSVERSION "2.4.13.7") 用这种方式装出来的版本是2.4.13.7 */ #include <opencv2/opencv.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/imgproc.hpp> int main() { // 读取图像 cv::Mat originalRGB = cv::imread("peppers.png"); if (originalRGB.empty()) { std::cout << "无法读取图像" << std::endl; return -1; } // 创建一个运动模糊滤波器 // 注意:OpenCV没有直接对应于MATLAB的fspecial('motion',...)的函数 // 但我们可以使用getGaussianKernel创建一个一维高斯滤波器,然后将其旋转以模拟运动模糊 int kernelSize = 50; // 滤波器大小,需要是奇数 double angle = 45 * CV_PI / 180; // 运动方向的角度(转换为弧度) cv::Point2f center(kernelSize / 2, kernelSize / 2); // 滤波器中心 cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, angle, 1); // 旋转矩阵 // 创建一个一维高斯滤波器 cv::Mat gaussianKernel = cv::getGaussianKernel(kernelSize, 0, CV_32F); cv::Mat motionKernel(kernelSize, kernelSize, CV_32F, cv::Scalar(0)); // 将一维高斯滤波器复制到二维滤波器中,并应用旋转 for (int i = 0; i < kernelSize; ++i) { motionKernel.row(i).copyTo(motionKernel.col(kernelSize - 1 - i).rowRange(0, 1)); } cv::warpAffine(motionKernel, motionKernel, rotationMatrix, motionKernel.size()); // 应用滤波器 cv::Mat filteredRGB; cv::filter2D(originalRGB, filteredRGB, originalRGB.depth(), motionKernel); // 显示或保存处理后的图像 cv::imshow("Original Image", originalRGB); cv::imshow("Filtered Image", filteredRGB); cv::waitKey(0); cv::imwrite("filtered_peppers.png", filteredRGB); return 0; }
还有以下代码用于实现模糊运动的添加与消除。
原理:在已知模糊运动核的前提下,可通过核线性卷积的形式对图像添加运动模糊,反之也可利用该核精确的去除该运动模糊。
本例代码仅使用了C++常用库与OpenCV 2.4.5,因为AddMotionBlur的createLinearFilter函数在OpenCV 3+版本中已经去除,故而建议只用OpenCV 2+,ker 核的大小不能过大,例如,以lena图为例,ker的len为20时,会导致无法复原。
// Input: // 彩色三通道图像,在读取时转化为灰度图 // output: // 添加运动模糊的单通道灰度图,或去除运动模糊后的单通道灰度图 // version: 1.0 // date: 2018/6/6 // by xie qunyi // 转载请注明: /*------------------------------------------------------------------------------------------*/ #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; // Create an image of complex number type (2 channels to store // real part and imaginary part) from an input grayscale image // src : single channel grayscale image input // dst : two channel complex image output void i2z(cv::Mat src, cv::Mat& dst) { //convert the image to float type, create another one filled with zeros, //and make an array of these 2 images cv::Mat im_array[] = { cv::Mat_<float>(src), cv::Mat::zeros(src.size(), CV_32F) }; //combine as a 2 channel image to represent a complex number type image cv::Mat im_complex; cv::merge(im_array, 2, im_complex); //copy to destination im_complex.copyTo(dst); } // convert a 2 channel complex image to a single channel grayscale image // by getting magnitude // src : two channel complex image input // dst : single channel grayscale image output void z2i(cv::Mat src, cv::Mat& dst) { //split the complex image to 2 cv::Mat im_tmp[2]; cv::split(src, im_tmp); //get absolute value cv::Mat im_f; cv::magnitude(im_tmp[0], im_tmp[1], im_f); //copy to destination im_f.copyTo(dst); } // return complex image C = A./B // if A = a+b*i and B = c+d*i; // then C = A./B = ((a*c+b*d)/(c^2+d^2))+((b*c-a*d)/(c^2+d^2))*i cv::Mat complexDiv(const cv::Mat& A, const cv::Mat& B) { cv::Mat A_tmp[2]; cv::split(A, A_tmp); cv::Mat a, b; A_tmp[0].copyTo(a); A_tmp[1].copyTo(b); cv::Mat B_tmp[2]; cv::split(B, B_tmp); cv::Mat c, d; B_tmp[0].copyTo(c); B_tmp[1].copyTo(d); cv::Mat C_tmp[2]; cv::Mat g = (c.mul(c)+d.mul(d)); C_tmp[0] = (a.mul(c)+b.mul(d))/g; C_tmp[1] = (b.mul(c)-a.mul(d))/g; cv::Mat C; cv::merge(C_tmp, 2, C); return C; } // add motion blur to the src image // motion degree is depended on the kernel ker // ker can be product by matlab func : fspecial // matlab code : {LEN = 3; THETA = 0; ker = fspecial('motion', LEN, THETA);} cv::Mat AddMotionBlur(const cv::Mat& src, const cv::Mat& ker) { // convert to float data cv::Mat sample_float; src.convertTo(sample_float, CV_32FC1); // motion blur cv::Point anchor(0, 0); double delta = 0; cv::Mat dst = cv::Mat(sample_float.size(), sample_float.type()); Ptr<cv::FilterEngine> fe = cv::createLinearFilter(sample_float.type(), ker.type(), ker, anchor, delta, BORDER_WRAP, BORDER_CONSTANT, cv::Scalar(0)); fe->apply(sample_float, dst); return dst; } // remove motion blur which is added by the special kernel ker // the same function in matlab is: // {[hei,wid,~] = size(blurredimage);If = fft2(blurredimage); // Pf = fft2(ker,hei,wid); deblurred = ifft2(If./Pf);} cv::Mat DemotionBlur(const cv::Mat& src, const cv::Mat& ker) { // If Mat blurred_co; i2z(src, blurred_co); Mat If; dft(blurred_co, If); // Pf Mat im_complex_ker; cv::Mat tmp = cv::Mat::zeros(src.rows, src.cols, CV_32FC1); ker.copyTo(tmp(cv::Rect(0,0,ker.cols,ker.rows))); Mat tmp_co; i2z(tmp, tmp_co); Mat Pf; dft(tmp_co, Pf); // If./Pf cv::Mat im_co = complexDiv(If, Pf); //Convert the DFT result into grayscale Mat im_de; dft(im_co, im_de, DFT_INVERSE+DFT_SCALE); Mat im_deblur; z2i(im_de, im_deblur); return im_deblur; } int main(int argc, char** argv){ // 读取测试样例 const std::string ImageName = "./lena.jpg"; cv::Mat DemoImage = cv::imread(ImageName, CV_LOAD_IMAGE_GRAYSCALE); // 运动模糊核 float kernel[1][3] = {{0.333333333,0.33333333,0.33333333}}; cv::Mat ker = cv::Mat(1, 3, CV_32FC1, &kernel); // 添加运动模糊 cv::Mat blur = AddMotionBlur(DemoImage, ker); cv::imwrite("./blur.jpg", blur); // 去除运动模糊 cv::Mat deblur = DemotionBlur(blur, ker); cv::imwrite("./deblur.jpg", deblur); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。