所谓模糊,就是像素间所有差值不大,差值越各不相同图像越清晰
Smooth/Blur 是图像处理中最简单和常用的操作之一
使用该操作的原因之一就为了给图像预处理时候减低噪声(图像特征提取时,去掉不必要的,比如边缘处理)
使用Smooth/Blur操作其背后是数学的卷积计算
g(i,j) = ∑ f(i+k, j+l) * h(k,l) f()表示一副图像,i j表示图像的行和列,h(k,l)表示卷积算子(和)(也可以叫掩膜),k l又可以叫窗口大小(掩膜的大小,比如3*3)
k,l g()表示输出的像素值 离散数学
通常这些卷积算子计算都是线性操作,所以又叫线性滤波
假设有6x6的图像像素点矩阵。
卷积过程:6x6上面是个3x3的窗口(掩膜),从左向右,从上向下移动,黄色的每个像素点值之和取平均值赋给中心红色像素作为它卷积处理之后新的像素值。每次移动一个像素格。
对于边缘的处理,可以利用临近像素进行线性插值给空白的像素,然后再进行卷积计算(掩膜)
模糊原理: 同样的卷积因子,均值模糊会比高斯模糊更模糊些。 不管对于哪种模糊,卷积和(比如3*3)的大小最好是奇数
归一化盒子滤波(均值滤波): 就是上面的卷积计算,卷积算子(掩膜)中的格子权重都是1,所以卷积和之后还要除以卷积因子的大小取均值
高斯滤波: 相比于均值滤波,权重是不一样,但是权重和为1,所以计算卷积和之后不用取均值了
VS代码
#include "../common/common.hpp"
void main1_9(int argc, char** argv)
{
Mat src = imread(getCVImagesPath("images/test1_3.png"), IMREAD_COLOR);
imshow("src", src);
Mat dst1, dst2, dst3;
//Size()的参数必须是正数
blur(src, dst1, Size(15, 15), Point(-1, -1));//均值模糊,Size(15, 15)表示卷积算子(掩膜)大小(不一定要正方形)为15*15, Point(-1, -1) 表示取掩膜中心点为计算结果
blur(src, dst2, Size(29, 1), Point(-1, -1));//x方向模糊看起来像是瞬间移动一样
blur(src, dst3, Size(1, 15), Point(-1, -1));//y方向模糊看起来会把图像拉高一点点
imshow("blur1", dst1);
imshow("blur2", dst2);
imshow("blur3", dst3);
Mat dst4, dst5, dst6;
//同样的卷积因子,均值模糊会比高斯模糊更模糊些
//Size()的参数必须是正数而且是奇数,否则会报错
//参数sigma x 11, sigma y 11 是控制x,y方向高斯权重分布的,似乎是值越大,图像越模糊,但不是线性关系
GaussianBlur(src, dst4, Size(15, 15), 11, 11);//高斯模糊,Size(15, 15)表示卷积算子(掩膜)大小(不一定要正方形)为15*15
GaussianBlur(src, dst5, Size(15, 1), 11, 11);//x方向模糊看起来像是瞬间移动一样
GaussianBlur(src, dst6, Size(1, 15), 11, 11);//y方向模糊看起来会把图像拉高一点点
imshow("gaussian blur1", dst4);
imshow("gaussian blur2", dst5);
imshow("gaussian blur3", dst6);
waitKey(0);
}
效果图
Android代码
@BindView(R.id.iv_cv1_9_input) ImageView mSrcIv;
@BindView(R.id.iv_cv1_9_output1) ImageView mBlurIv;
@BindView(R.id.iv_cv1_9_output2) ImageView mBlurXIv;
@BindView(R.id.iv_cv1_9_output3) ImageView mBlurYIv;
@BindView(R.id.iv_cv1_9_output4) ImageView mGaussianBlurIv;
@BindView(R.id.iv_cv1_9_output5) ImageView mGaussianBlurXIv;
@BindView(R.id.iv_cv1_9_output6) ImageView mGaussianBlurYIv;
private Bitmap mSrcBmp;
private Bitmap mBlurBmp;
private Bitmap mBlurXBmp;
private Bitmap mBlurYBmp;
private Bitmap mGaussianBlurBmp;
private Bitmap mGaussianBlurXBmp;
private Bitmap mGaussianBlurYBmp;
private Mat mSrcMat = new Mat();
private Mat mBlurMat = new Mat();
private Mat mBlurXMat = new Mat();
private Mat mBlurYMat = new Mat();
private Mat mGaussianBlurMat = new Mat();
private Mat mGaussianBlurXMat = new Mat();
private Mat mGaussianBlurYMat = new Mat();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cv1_9);
mUnbinder = ButterKnife.bind(this);
//src
mSrcBmp = CV310Utils.getBitmapFromAssets(this, "opencv/test1_3.png");
mSrcIv.setImageBitmap(mSrcBmp);
Utils.bitmapToMat(mSrcBmp, mSrcMat);
initBitmaps(mSrcBmp);
//blur
//Size()的参数必须是正数
Imgproc.blur(mSrcMat, mBlurMat, new Size(15, 15), new Point(-1, -1), 4);//均值模糊,Size(15, 15)表示卷积算子(掩膜)大小(不一定要正方形)为15*15, Point(-1, -1) 表示取掩膜中心点为计算结果
Imgproc.blur(mSrcMat, mBlurXMat, new Size(29, 1), new Point(-1, -1), 4);//x方向模糊看起来像是瞬间移动一样
Imgproc.blur(mSrcMat, mBlurYMat, new Size(1, 15), new Point(-1, -1), 4);//y方向模糊看起来会把图像拉高一点点
CV310Utils.mat2bitmapAndShowInIv(mBlurMat, mBlurBmp, mBlurIv);
CV310Utils.mat2bitmapAndShowInIv(mBlurXMat, mBlurXBmp, mBlurXIv);
CV310Utils.mat2bitmapAndShowInIv(mBlurYMat, mBlurYBmp, mBlurYIv);
//GaussianBlur
//同样的卷积因子,均值模糊会比高斯模糊更模糊些
//Size()的参数必须是正数而且是奇数,否则会报错
//参数sigma x 11, sigma y 11 是控制x,y方向高斯权重分布的,似乎是值越大,图像越模糊,但不是线性关系
Imgproc.GaussianBlur(mSrcMat, mGaussianBlurMat, new Size(15, 15), 11, 11);//高斯模糊,Size(15, 15)表示卷积算子(掩膜)大小(不一定要正方形)为15*15
Imgproc.GaussianBlur(mSrcMat, mGaussianBlurXMat, new Size(15, 1), 11, 11);//x方向模糊看起来像是瞬间移动一样
Imgproc.GaussianBlur(mSrcMat, mGaussianBlurYMat, new Size(1, 15), 11, 11);//y方向模糊看起来会把图像拉高一点点
CV310Utils.mat2bitmapAndShowInIv(mGaussianBlurMat, mGaussianBlurBmp, mGaussianBlurIv);
CV310Utils.mat2bitmapAndShowInIv(mGaussianBlurXMat, mGaussianBlurXBmp, mGaussianBlurXIv);
CV310Utils.mat2bitmapAndShowInIv(mGaussianBlurYMat, mGaussianBlurYBmp, mGaussianBlurYIv);
}
/*初始化bitmap*/
private void initBitmaps(Bitmap bmp){
mBlurBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mBlurXBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mBlurYBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mGaussianBlurBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mGaussianBlurXBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mGaussianBlurYBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
}
效果图