10_Opencv图像均值滤波(模糊)

10_Opencv图像均值滤波(模糊)

一.图像均值滤波

图像均值滤波是指,先对图像的卷积核做归一化处理后(即均值滤波器),再与图像进行卷积,例如一个3x3的归一化的卷积核如下:
kernel=19[111111111]kernel=\frac{1}{9} \left[ \begin{matrix} 1 & 1 & 1\\ 1 & 1 & 1\\ 1 & 1 & 1 \end{matrix} \right]
关于图像卷积可以参考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函数实现图像均值滤波(模糊)
10_Opencv图像均值滤波(模糊)