在第二讲中,我介绍了如何操作每个像素,这次利用操作像素完成简单的图像处理操作。
首先从给图像加入椒盐噪声开始,椒盐噪声其实就是使图像的一些随机的像素为黑色(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; }
个人觉得,对于灰度图像的锐化程序都有点长了,对于彩色图像就更麻烦了,还是直接调用滤波函数完成图像锐化比较方便。