10_Opencv图像均值滤波(模糊)
10_Opencv图像均值滤波(模糊)
一.图像均值滤波
图像均值滤波是指,先对图像的卷积核做归一化处理后(即均值滤波器),再与图像进行卷积,例如一个3x3的归一化的卷积核如下:
关于图像卷积可以参考09_Opencv图像卷积。
二.通过像素指针实现图像均值滤波(模糊)
//1.初始化卷积核,即均值滤波器
Size size(9, 9);
Mat kernel(size, CV_64F);
for(int i=0; i<kernel.rows; i++) {
for(int j=0; j<kernel.cols; j++) {
kernel.ptr<double>(i)[j] = 1.0/(kernel.rows*kernel.cols);
}
}
int kRows = kernel.rows;
int kCols = kernel.cols;
int offsetX = (kCols+1)/2;
int offsetY = (kRows+1)/2;
//2.获取图像宽度、高度和通道数
int channels = src.channels();
int rows = src.rows;
int cols = src.cols;
//通过像素指针实现图像均值滤波(模糊)
Mat dst = Mat::zeros(src.size(), src.type());
for(int row=offsetY; row<rows-offsetY; row++) {
for(int col=offsetX; col<(cols-offsetX); col++) {
//从图像中截取与卷积核相同大小的像素信息
Mat subMat = src(Rect(col - offsetX, row - offsetY, kCols, kRows));
for(int channel=0; channel<channels; channel++) {
//将每一个通道的像素信息与卷积核对应位置相乘相加
double pixel = 0;
for(int i=0; i<subMat.rows; i++) {
for(int j=0; j<subMat.cols; j++) {
pixel += (subMat.ptr<uchar>(i)[j*channels + channel])*kernel.ptr<double>(i)[j];
}
}
//所得结果再放回中心位置
dst.ptr<uchar>(row)[col*channels + channel] = saturate_cast<uchar>(pixel);
}
}
}
三.通过遍历Mat对象实现图像均值滤波(模糊)
//1.初始化卷积核,即均值滤波器
Size size(9, 9);
Mat kernel(size, CV_64F);
for(int i=0; i<kernel.rows; i++) {
for(int j=0; j<kernel.cols; j++) {
kernel.ptr<double>(i)[j] = 1.0/(kernel.rows*kernel.cols);
}
}
int kRows = kernel.rows;
int kCols = kernel.cols;
int offsetX = (kCols+1)/2;
int offsetY = (kRows+1)/2;
//2.获取图像宽度、高度和通道数
int channels = src.channels();
int rows = src.rows;
int cols = src.cols;
//通过遍历Mat对象实现图像均值滤波(模糊)
Mat dst = Mat::zeros(src.size(), src.type());
for(int row=offsetY; row<rows-offsetY; row++) {
for(int col=offsetX; col<(cols-offsetX); col++) {
//6.获取待卷积的局部图像
Mat subMat = src(Rect(col - offsetX, row - offsetY, kCols, kRows));
//7.做卷积运算
if(channels == 4) {
//四通道
double b = 0, g = 0, r = 0, a = 0;
for(int i=0; i<kRows; i++) {
for(int j=0; j<kCols; j++) {
b += subMat.at<Vec4b>(i, j)[0]*kernel.at<double>(i, j);
g += subMat.at<Vec4b>(i, j)[1]*kernel.at<double>(i, j);
r += subMat.at<Vec4b>(i, j)[2]*kernel.at<double>(i, j);
a += subMat.at<Vec4b>(i, j)[3]*kernel.at<double>(i, j);
}
}
dst.at<Vec4b>(row, col)[0] = saturate_cast<uchar>(b);
dst.at<Vec4b>(row, col)[1] = saturate_cast<uchar>(g);
dst.at<Vec4b>(row, col)[2] = saturate_cast<uchar>(r);
dst.at<Vec4b>(row, col)[3] = saturate_cast<uchar>(a);
} else if(channels == 3) {
//三通道
double b = 0, g = 0, r = 0;
for(int i=0; i<kRows; i++) {
for(int j=0; j<kCols; j++) {
b += subMat.at<Vec3b>(i, j)[0]*kernel.at<double>(i, j);
g += subMat.at<Vec3b>(i, j)[1]*kernel.at<double>(i, j);
r += subMat.at<Vec3b>(i, j)[2]*kernel.at<double>(i, j);
}
}
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b);
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g);
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r);
} else if(channels == 1) {
//单通道
double value = 0;
for(int i=0; i<kRows; i++) {
for(int j=0; j<kCols; j++) {
value += subMat.at<uchar>(i, j)*kernel.at<double>(i, j);
}
}
dst.at<uchar>(row, col) = saturate_cast<uchar>(value);
}
}
}
四.通过cv::filter2D函数实现图像均值滤波(模糊)
//1.初始化卷积核,即均值滤波器
Size size(9, 9);
Mat kernel(size, CV_64F);
for(int i=0; i<kernel.rows; i++) {
for(int j=0; j<kernel.cols; j++) {
kernel.ptr<double>(i)[j] = 1.0/(kernel.rows*kernel.cols);
}
}
//通过filter2D函数实现图像均值滤波(模糊)
Mat dst = Mat(src.size(), src.type());
filter2D(src, dst, src.depth(), kernel);
五.通过cv::blur函数实现图像均值滤波(模糊)
//1.初始化卷积核,即均值滤波器
Size size(9, 9);
Mat kernel(size, CV_64F);
for(int i=0; i<kernel.rows; i++) {
for(int j=0; j<kernel.cols; j++) {
kernel.ptr<double>(i)[j] = 1.0/(kernel.rows*kernel.cols);
}
}
//通过blur函数实现图像均值滤波(模糊)
Mat dst = Mat(src.size(), src.type());
blur(src, dst, size);
六.运行结果
从左到右依次是:通过像素指针实现图像均值滤波(模糊)、通过遍历Mat实现图像均值滤波(模糊)、cv::filter2D实现图像均值滤波(模糊)、cv:blur函数实现图像均值滤波(模糊)