在第二讲中,我介绍了如何操作每个像素,这次利用操作像素完成简单的图像处理操作。
首先从给图像加入椒盐噪声开始,椒盐噪声其实就是使图像的一些随机的像素为黑色(255)或者白色(0):
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- using namespace cv;
- void salt(Mat& image, int n)
- {
- for(int k=0; k<n; k++)
- {
- int i = rand()%image.cols;
- int j = rand()%image.rows;
- if(image.channels() == 1)
- {
- image.at<uchar>(j,i) = 255;
- }
- else
- {
- image.at<Vec3b>(j,i)[0] = 255;
- image.at<Vec3b>(j,i)[1] = 255;
- image.at<Vec3b>(j,i)[2] = 255;
- }
- }
- }
在看主程序,主程序中通过中滤波来消除噪声的影响:
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <opencv2/imgproc/imgproc.hpp>
- using namespace cv;
- void salt(Mat&, int n=3000);
- int main()
- {
- Mat image = imread("D:/picture/img.tif");
- salt(image, 500);
- cv::namedWindow("image");
- cv::imshow("image",image);
- //测试用滤波的手段消除椒盐噪声
- Mat result;
- Mat kernel;
- int ddepth;
- int kernel_size;
- ddepth = -1;
- int ind = 0;
- while(true)
- {
- //每0.5秒刷新一次图像
- int c = waitKey(500);
- //按esc键退出程序
- if((char)c == 27)
- {
- break;
- }
- kernel_size = 3+2*(ind%5);
- kernel = Mat::ones(kernel_size,kernel_size,CV_32F)/(float)(kernel_size*kernel_size);
- filter2D(image,result,ddepth,kernel);
- imshow("滤波结果",result);
- ind++;
- }
- waitKey(0);
- }
可以看出,滤波器的核越大,对于噪声消除效果越好,但图像轮廓也越模糊。
图像的翻转:
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <iostream>
- using namespace cv;
- using namespace std;
- int main()
- {
- //声明一个变量来承载图片,大小为0*0
- Mat image ;
- cout<<"size:"<<image.size().height<<","<<image.size().width<<std::endl;
- //读取一幅图像
- image= imread("D:/picture/img.tif");
- if (!image.data)
- {
- std::cout<<"read image fail!"<<std::endl;
- }
- //创建名为“My Image”的图像窗口
- namedWindow("My Image");
- //显示一幅图像
- imshow("My Image",image);
- //等待按键:返回值为按键的asc码值或者-1(当等待时间到了时,如果没有按键按下)
- waitKey(0);
- Mat result;
- result.create(image.rows,image.cols,image.type());
- int rows = image.rows;
- int cols = image.cols;
- //对图像做水平翻转
- for(int i = 0;i < rows;i++)
- {
- for(int j = 0;j < cols;j++)
- {
- result.at<Vec3b>(i,j)[0] = image.at<Vec3b>(i,cols-j-1)[0];
- result.at<Vec3b>(i,j)[1] = image.at<Vec3b>(i,cols-j-1)[1];
- result.at<Vec3b>(i,j)[2] = image.at<Vec3b>(i,cols-j-1)[2];
- }
- }
- //flip(image,result,1);//正值水平变换
- //0垂直变换
- //负值二者都有
- namedWindow("output image");
- imshow("output image",result);
- waitKey(0);
- return 0;
- }
使用for循环完成的水平翻转效果与使用flip函数的效果相同。
接下来完成改变图像的对比度和亮度:
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <iostream>
- using namespace cv;
- using namespace std;
- //控制对比度
- double alpha;
- //控制亮度
- int beta;
- int main()
- {
- Mat image = imread("D:/picture/img.tif");
- if(!image.data)
- {
- cout<<"fail to read a image"<<endl;
- return -1;
- }
- Mat new_image = Mat::zeros(image.size(),image.type());
- cout << " Basic Linear Transforms " << endl;
- cout << "-------------------------" << endl;
- cout << "* Enter the alpha value [1.0-3.0]: ";
- cin>>alpha;
- cout << "* Enter the beta value [0-100]: ";
- cin>>beta;
- for(int i = 0;i < image.rows;i++)
- {
- for(int j = 0;j < image.cols;j++)
- {
- for(int c = 0;c < 3;c++)
- {
- //由于运算结果可能不是整数,所以需要格式转换
- new_image.at<Vec3b>(i,j)[c] = saturate_cast<uchar>(alpha*(image.at<Vec3b>(i,j)[c])+beta);
- }
- }
- }
- namedWindow("源图像");
- imshow("源图像",image);
- namedWindow("改变对比度和亮度的结果图像");
- imshow("改变对比度和亮度的结果图像",new_image);
- waitKey(0);
- return 0;
- }
最后是图像锐化:
- #include <opencv2\core\core.hpp>
- #include <opencv2\highgui\highgui.hpp>
- #include <opencv2/imgproc/imgproc.hpp>
- using namespace cv;
- int main()
- {
- Mat image;
- image = imread("D:/picture/img.tif",0);//读取的是图像的灰度值,所以在sharpen函数中没有考虑通道数
- Mat result;
- result.create(image.rows,image.cols,image.type());
- //使用3*3滤波器,所以遍历的像素中不能包括图像最外围的一圈
- for(int i = 1;i < image.rows-1;i++)
- {
- //前一行、当前行、后一行的指针
- uchar* previous = image.ptr< uchar>(i-1);
- uchar* current = image.ptr< uchar>(i);
- uchar* next = image.ptr< uchar>(i+1);
- //输出结果图像的行指针
- uchar* output = result.ptr<uchar>(i);
- for(int j = 1;j < image.cols - 1;j++)
- {
- //图像锐化操作
- *output++= cv::saturate_cast<uchar>(5*current[j]-current[j-1]-current[j+1]-previous[j]-next[j]); //saturate_cast<uchar>会将小于0的置零,大于255的改为255
- }
- }
- result.row(0).setTo(cv::Scalar(0));
- result.row(result.rows-1).setTo(cv::Scalar(0));
- result.col(0).setTo(cv::Scalar(0));
- result.col(result.cols-1).setTo(cv::Scalar(0));
- /*
- //调用滤波函数来完成图像的锐化
- //滤波器的核
- Mat kernel(3,3,CV_32F,Scalar(0));
- // 分配像素置
- kernel.at<float>(1,1) = 5.0;
- kernel.at<float>(0,1) = -1.0;
- kernel.at<float>(2,1) = -1.0;
- kernel.at<float>(1,0) = -1.0;
- kernel.at<float>(1,2) = -1.0;
- //调用滤波函数
- filter2D(image,result,image.depth(),kernel);
- */
- imshow("源图像",image);
- imshow("锐化结果",result);
- waitKey(0);
- return 0;
- }
个人觉得,对于灰度图像的锐化程序都有点长了,对于彩色图像就更麻烦了,还是直接调用滤波函数完成图像锐化比较方便