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

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

一.图像均值滤波

图像均值滤波是指,先对图像的卷积核做归一化处理后(即均值滤波器),再与图像进行卷积,例如一个3x3的归一化的卷积核如下:
k e r n e l = 1 9 [ 1 1 1 1 1 1 1 1 1 ] kernel=\frac{1}{9} \left[ \begin{matrix} 1 & 1 & 1\\ 1 & 1 & 1\\ 1 & 1 & 1 \end{matrix} \right]
关于图像卷积可以参考09_图像卷积

二.通过遍历Mat对象实现图像均值滤波(模糊)

//1.初始化卷积核,即均值滤波器
Size size = new Size(21,21);
Mat kernel = new Mat(size, CvType.CV_64F);
double[] data = new double[kernel.rows()*kernel.cols()];
for(int i=0; i<data.length; i++) {
    data[i] = 1.0f/data.length;
}
//2.Bitmap转Mat对象
Mat srcMat = new Mat();
Utils.bitmapToMat(src, srcMat);
Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGRA2BGR);
//3.校验卷积核的宽度和高度是否为奇数
int kRows = kernel.rows();
int kCols = kernel.cols();

if(!((kCols%2==1) && (kRows%2==1))) {
    throw new RuntimeException("The size of kernal is not suitable!");
}
//4.计算偏移量
int offsetX = (kCols-1)/2;
int offsetY = (kRows-1)/2;
//5.将kernel沿着中心点旋转180度,即先沿X轴翻转,再沿y轴翻转
Core.flip(kernel, kernel, 0);
Core.flip(kernel, kernel, 1);

double[] kernels = new double[kRows*kCols];
kernel.get(0,0,kernels);

//6.遍历Mat对象
int channels = srcMat.channels();
int rows = srcMat.rows();
int cols = srcMat.cols();
byte[] srcBuffer = new byte[rows*cols*channels];
srcMat.get(0, 0, srcBuffer);
byte[] dstBuffer = new byte[rows*cols*channels];

for(int i=0; i<(rows - kRows + 1); i++) {
    for(int j=0; j<(cols - kCols + 1); j++) {
        //从图像中获取与卷积核同样大小的像素信息,并与卷积核对应位置相乘相加
        int startPos = i*cols + j;
        double[] bgra = new double[channels];
        for (int channel = 0; channel < channels; channel++) {
            for (int k = 0; k < kRows; k++) {
                for (int l = 0; l < kCols; l++) {
                    bgra[channel] += (srcBuffer[(startPos + l + cols * k) * channels + channel] & 0xff) * kernels[k * kCols + l];
                }
            }
            //卷积核对应位置相乘相加的结果设置回中心位置,得到最后的图像
            dstBuffer[(startPos + offsetX + cols * offsetY) * channels + channel] = (byte) saturateCast(bgra[channel]);
        }
    }
}
Mat dst = new Mat(srcMat.size(), srcMat.type());
dst.put(0,0,dstBuffer);
Utils.matToBitmap(dst, src);

三.通过遍历Bitmap实现图像均值滤波(模糊)

//1.初始化卷积核,即均值滤波器
Size size = new Size(21,21);
Mat kernel = new Mat(size, CvType.CV_64F);
double[] data = new double[kernel.rows()*kernel.cols()];
for(int i=0; i<data.length; i++) {
    data[i] = 1.0f/data.length;
}
//2.Bitmap转Mat对象
Mat srcMat = new Mat();
Utils.bitmapToMat(src, srcMat);
Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGRA2BGR);
//3.校验卷积核的宽度和高度是否为奇数
int kRows = kernel.rows();
int kCols = kernel.cols();

if(!((kCols%2==1) && (kRows%2==1))) {
    throw new RuntimeException("The size of kernal is not suitable!");
}
//4.计算偏移量
int offsetX = (kCols-1)/2;
int offsetY = (kRows-1)/2;
//5.将kernel沿着中心点旋转180度,即先沿X轴翻转,再沿y轴翻转
Core.flip(kernel, kernel, 0);
Core.flip(kernel, kernel, 1);

double[] kernels = new double[kRows*kCols];
kernel.get(0,0,kernels);

//6.通过遍历Bitmap实现
int width = src.getWidth();
int height = src.getHeight();

//开辟像素缓冲区(int数组),其长度为(bitmap的宽度 * bitmap的高度)
int[] srcPixels = new int[width * height];
int[] dstPixels = new int[width * height];
//将所有像素取到缓冲区中
src.getPixels(srcPixels, 0, width, 0, 0, width, height);
//通过pixel遍历每一个像素,并对每一个通道的像素进行卷积
for(int i=0; i<(height - kRows + 1); i++) {
    for(int j=0; j<(width - kCols + 1); j++) {
        //从图像中获取与卷积核同样大小的像素信息,并与卷积核对应位置相乘相加
        int startPos = i*width + j;
        double a = 0, r = 0, g = 0, b = 0;
        for (int k = 0; k < kRows; k++) {
            for (int l = 0; l < kCols; l++) {
                a = 255;
                r += ((srcPixels[startPos + l + width * k] >> 16) & 0xff) * kernels[k * kCols + l];
                g += ((srcPixels[startPos + l + width * k] >> 8) & 0xff) * kernels[k * kCols + l];
                b += ((srcPixels[startPos + l + width * k]) & 0xff) * kernels[k * kCols + l];
            }
        }
        //保证卷积核对应位置相乘相加的结果在0到255之间
        a = saturateCast(a);
        r = saturateCast(r);
        g = saturateCast(g);
        b = saturateCast(b);
        //卷积核对应位置相乘相加的结果设置回中心位置,得到最后的图像
        int pixel = (((int)a & 0xff) << 24) | (((int)r & 0xff) << 16) | (((int)g & 0xff) << 8) | ((int)b & 0xff);
        dstPixels[startPos + offsetX + width * offsetY] = pixel;
    }
}
src.setPixels(dstPixels, 0, width, 0, 0, width, height);

四.通过对图像积分实现图像均值滤波(模糊)

//1.初始化卷积核,即均值滤波器
Mat kernel = new Mat(size, CvType.CV_64F);
double[] data = new double[kernel.rows()*kernel.cols()];
for(int i=0; i<data.length; i++) {
    data[i] = 1.0f/data.length;
}
kernel.put(0, 0, data);
int offsetX = (kernel.cols() - 1)/2;
int offsetY = (kernel.rows() - 1)/2;
Mat srcMat = new Mat();
Utils.bitmapToMat(src, srcMat);
int channels = srcMat.channels();
int rows = srcMat.rows();
int cols = srcMat.cols();

Mat inte = new Mat();
Imgproc.integral(srcMat, inte, CvType.CV_64FC(channels));
Mat dst = new Mat(srcMat.size(), srcMat.type());
for(int row=offsetY; row<rows-offsetY; row++) {
    for(int col=offsetX; col<cols-offsetX; col++) {
        double[] leftTop = new double[channels];
        double[] rightBottom = new double[channels];
        double[] rightTop = new double[channels];
        double[] leftBottom = new double[channels];
        inte.get(row-offsetY, col-offsetX, leftTop);
        inte.get(row+offsetY+1, col+offsetX+1, rightBottom);
        inte.get(row-offsetY, col+offsetX+1, rightTop);
        inte.get(row+offsetY+1, col-offsetX, leftBottom);
        byte[] result = new byte[channels];
        for(int i=0; i<channels; i++) {
            result[i] = (byte) saturateCast((leftTop[i] + rightBottom[i] - rightTop[i] - leftBottom[i])/(kernel.rows()*kernel.cols()));
        }
        dst.put(row, col, result);
    }
}
Utils.matToBitmap(dst, src);

五.通过ImgProc.filter2D实现图像均值滤波(模糊)

//1.初始化卷积核,即均值滤波器
Size size = new Size(21,21);
Mat kernel = new Mat(size, CvType.CV_64F);
double[] data = new double[kernel.rows()*kernel.cols()];
for(int i=0; i<data.length; i++) {
    data[i] = 1.0f/data.length;
}
//2.Bitmap转Mat对象
Mat srcMat = new Mat();
Utils.bitmapToMat(src, srcMat);
Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGRA2BGR);
//3.校验卷积核的宽度和高度是否为奇数
int kRows = kernel.rows();
int kCols = kernel.cols();

if(!((kCols%2==1) && (kRows%2==1))) {
    throw new RuntimeException("The size of kernal is not suitable!");
}

Imgproc.filter2D(srcMat, srcMat, srcMat.depth(), kernel);
Utils.matToBitmap(srcMat, src);

六.通过ImgProc.blur实现图像均值滤波

//1.初始化卷积核大小
Size size = new Size(21,21);
//2.Bitmap转Mat对象
Mat srcMat = new Mat();
Utils.bitmapToMat(src, srcMat);
Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGRA2BGR);

Imgproc.blur(srcMat, srcMat, size, new Point(-1,-1));
Utils.matToBitmap(srcMat, src);

七.运行结果

在这里插入图片描述

发布了79 篇原创文章 · 获赞 45 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/gzx110304/article/details/89068651