模糊
卷积
- 卷积常用于实现图像模糊
均值模糊
-
卷积核的所有系数都相同,这种基于相同系数的卷积核完成的卷积操作又称为均值模糊,均值模糊最主要的作用是可以降低图像的噪音、模糊图像、降低图像的对比度
Imgproc.blur(Mat src,Mat dst,Size ksize,Point anchor,int borderType) //src:表示输入图像 //dst:表示卷积模糊之后输出图像 //ksize:表示图像卷积核大小 //anchor:表示卷积核的中心位置 //borderType: 边缘填充的类型,默认情况下为BORDER_DEFAULT方式
-
使用函数实现图像模糊
String path = Environment.getExternalStorageDirectory()+File.separator+"dex"+File.separator+"aaa.jpg"; Mat src = Imgcodecs.imread(path); if (src.empty()){ Log.i(TAG, "loadImg: 图片加载失败"); return; } Mat dsc = new Mat(); Imgproc.blur(src,dsc,new Size(10,10),new Point(-1,-1),Core.BORDER_DEFAULT); //如果想图像只在水平或者垂直方法模式只需要 new Size(15,1)//在水平方法模糊 new Size(1,15)//在垂直方向模糊
高斯模糊
-
根据空间相对位置不同,卷积核中的每个系数具有不同的系数(权重),因为我们经常使用高斯正态分布方式来生成权重系数,因此这种模糊又称为高斯模糊。
Imgproc.GaussianBlur(Mat src,Mat dst,Size ksize,double sigmax,double sigmay,int borderType) //src:输入图像 //dst:输出图像 //ksize:表示图像卷积核大小 //sigmax:表示x方向的模糊程度 //sigmay:表示Y方法的模糊程度,当sigmay不填写的时候,表从sigmax技术得到 //borderType: 边缘填充的类型,默认情况下为BORDER_DEFAULT方式 Imgproc.GaussianBlur(src,dsc,new Size(0,0),15);//后两个参数可以省略 Imgproc.GaussianBlur(src,dsc,new Size(15,15),0);
-
上述的各个参数中,ksize大小可以通过用户输入参数,或者通过sigmax计算得到,当ksize值为非0时候,就表示sigmax将会通过ksize 计算产生,无需填写;当ksize为零值的时候,sigmax就必须为非零值,ksize大小将由sigmax计算产生。
-
均值滤波和高斯模糊经常用于图像预处理,能够起到抑制噪声的作用,使用它们选择的卷积核大小通常为3x3或者5x5
统计排序滤波
中值滤波
-
中值滤波同样也需要一个卷积核,与卷积核滤波不同的是,他不会用卷积核每个系数与对应的像素值做算术计算,而是把对应的像素值做排序,取中间值作为输出。
medianBlur(Mat src,Mat dst,int ksize) //src:表示输入图像,当ksize为3、5的时候输入图像可以为浮点数或者整数类型当ksize大于5时,则只能为字节类型图像,即CV_8UC //dst:表示中值滤波以后输出的图像,其类型与输入图像保持一致 //ksize:模板的大小,常见为3、5,注意模板大小必须为奇数而且必须大于1
-
中值滤波对图像的椒盐噪声有很明显的抑制作用
最大值与最小值滤波
-
最大值与最小值滤波和中值滤波及其相似,唯一不同的就是对于排序之后的像素数组,前两者分别用最大值或者最小值来取代中心像素点作为输出
dilate(Mat src,Mat dst,Mat kernel)//膨胀(最大滤波)用最大值替换中心像素 //src:表示输入图像 //dst:表示输出图像 //kernel:表示结构元素或者卷积核,他可以是任意形状 erode(Mat src,Mat dst,Mat kernel)//腐蚀(最小滤波)用最小值替换中心像素 //src:表示输入图像 //dst:表示输出图像 //kernel:表示结构元素或者卷积核,他可以是任意形状 Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(3,3)) //生成一个3x3大小矩形结构元素
-
统计排序滤波器是最简单的非线性滤波器,他可以帮助我们抑制图像中特定类型噪声,是非常有用的图像滤波器
边缘保留滤波
- OpenCV 中已经实现的边缘保留滤波有高斯双边滤波、金字塔均值迁移滤波,它们无一例外都拥有类似人脸美化或者图像美化效果,是很好的图像边缘保留滤波方法。
1、高斯双边滤波
-
高斯双边滤波是在高斯滤波的基础上进一步拓展与延伸出来的图像滤波方法,blur操作是图像均值模糊,会导致图像出现轮廓与边缘消失的现象,而高斯模糊则会产生类似毛玻璃效果,导致边缘扩展效应明显、图像边缘细节丢失问题。双边滤波可以在很好的保留边缘的同时,抑制平坦区域噪点。高斯滤波函数:
bilateralFilter(Mat src,Mat dsc,int d,double sigmaColor,double sigmaSpace) //src:表示输入图像 //dsc:表示输出图像 //d:表示用来过滤的卷积核直径大小,一般取0,意思是从sigmaColor参数自动计算 //sigmaColor:颜色权重计算时候需要的参数 //sigmaSpace:空间权重计算时候需要的参数 //通常情况下 sigmaColor 的取值范围100~150左右,sigmaSpace的取值范围是10~25之间的时候双边滤波效果比较好
2、均值迁移滤波
-
均值迁移滤波主要通过概率密度计算与中心迁移的方式来实现图像边缘保留滤波,其基本原理是通过创建大小指定卷积核窗口,搜索并计算该窗口的中心像素p(x,y)范围内满足条件的像素,计算他们的中心位置,然后基于新中心位置再次计算更新,知道中心位置不再变化或者两次变化的中心距离满足指定的收敛精度值为止。
pyrMeanShiftFiltering(Mat src,mat dst,double sp,double sr,int maxLevel,TermCriteria termcrit) //src:输入图像 //dst:输出图像 //sp:图像色彩空间也是图像大小 //sr:图像色彩像素值范围,也就是像素色差范围 //maxLevel:表示金字塔的层数,当MaxLevel大于0时候,金字塔层数为Level+1 //termcrit:表示循环或者迭代停止条件 //通常情况下 最后两个参数使用默认值 Imgproc.pyrMeanShiftFiltering(src,dst,10,50)
形态学操作
- OpenCV 支持的形态学主要有膨胀、腐蚀、开操作、闭操作、黑帽、顶帽,形态学梯度。
1、膨胀与腐蚀
-
形态学的腐蚀与膨胀结合使用可以实现图像噪声的消除,分离出独立的图像形状与几何元素,断开或者连接相邻的像素,api 就是dialate与erode。
dilate(Mat src,Mat dst,Mat kernel)//膨胀(最大滤波)用最大值替换中心像素 //src:表示输入图像 //dst:表示输出图像 //kernel:表示结构元素或者卷积核,他可以是任意形状 erode(Mat src,Mat dst,Mat kernel)//腐蚀(最小滤波)用最小值替换中心像素 //src:表示输入图像 //dst:表示输出图像 //kernel:表示结构元素或者卷积核,他可以是任意形状 Mat kernel = Imgproc.getStructuringElement(int shape,ksiez,Point anchor) //生成一个3x3大小矩形结构元素 // shape:表示结构元素的形状 //ksize:表示结构元素的大小 //achor:表示结构元素中心点的位置 //MORPH_RECT:矩形 //MORPH_CROSS:十字交叉 //MORPH_ELLIPSE:椭圆或者圆形 //Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_DILATE, k); // Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_ERODE, k);
膨胀
腐蚀
2、开闭操作
-
开操作是基于膨胀与腐蚀组合形成的新的形态学操作,开操作有点想腐蚀操作,主要是用来去除小的图像噪声或者图像对象黏连,开操作可以定义为一个腐蚀操作再加上一个膨胀操作,两个操作使用相同的结构元素。开操作表示
dst = open(src,element) = diate(erode(src,element),element) //其中src是输入图像,dst是输出图像、element是结构元素 Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_OPEN, k);
-
闭操作有点像膨胀操作,但是它与膨胀操作不同,它只会填充小的闭合区域,闭操作可以定义为一个膨胀操作再接一个腐蚀操作
dst = colse(src,element) = ercode(dilate(src,elemet),element) Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_CLOSE, k);
3、顶帽与黑帽
-
顶帽与黑帽是由形态学的开闭操作之后的结果与原图进行运算得到的结果,用于在灰度图像或者显微镜图像上分离比较暗或者比较明亮的斑点
dst = tophat(src,element) = src - open(src,element) Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_TOPHAT, k);
-
黑帽操作表示是图像闭操作与输入图像直接的不同
dst - blackhat(src,element)= close(src,element)-src Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_BLACKHAT, k);
4、梯度
-
图像的形态学梯度又称基本梯度,是通过最基本的两个形态学操作膨胀与腐蚀之间的差值得到的。
dst = morph-gradient(src,element) = dilate(src,element)-erode(src,element) Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_GRADIENT, k);
-
具体代码:
menu.add(0, 0, 100,"膨胀"); menu.add(0, 1, 100,"腐蚀"); menu.add(0, 2, 100,"开操作"); menu.add(0, 3, 100,"闭操作"); menu.add(0, 4, 100,"黑帽"); menu.add(0, 5, 100,"顶帽"); menu.add(0, 6, 100,"基本梯度"); final Mat k = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(15, 15), new Point(-1, -1)); final Mat src = Imgcodecs.imread(path); if (src.empty()) { Log.i(OpenUtils.TAG, "loadImg: 图片加载失败"); return super.onCreateOptionsMenu(menu); } for (int i = 0; i < menu.size(); i++) { menu.getItem(i).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { Mat dsc = null; switch (item.getItemId()) { case 0: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_DILATE, k); break; case 1: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_ERODE, k); break; case 2: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_OPEN, k); break; case 3: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_CLOSE, k); break; case 4: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_BLACKHAT, k); break; case 5: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_TOPHAT, k); break; case 6: dsc = new Mat(); Imgproc.morphologyEx(src, dsc, Imgproc.MORPH_GRADIENT, k); break; } if (dsc!=null){ OpenUtils.showBitMap(dsc,dscImage); } return false; } }); } return super.onCreateOptionsMenu(menu);
阈值化或阈值
- 对于彩色或者灰度图像,可以设置多个或一个阈值,使用它们就可以实现对图像像素数据的分类,这在图形处理上有一个专门术语—图像分割。对灰度图像来说图像分割本质就是图像阈值化的过程。
1、阈值二值化
- 对于图像阈值二值化,是令大于阈值T的值为最大灰度值-255,小于阈值T的值为最小的灰度值0.
2、反阈值二值化
- 与阈值二值化不同的是反阈值二值化,其定义为若大于阈值T,则赋值等于最小灰度-0,若小于阈值T,则赋值等于最大的灰度值255
3、阈值截断
- 阈值截断的定义为若大于阈值T,则赋值等于阈值T,若小于阈值T,则维持原来灰度值不变;
4、阈值去零
- 阈值去零的定义为若大于阈值,则T保持不变,若小于阈值,则T的像素赋值等于零
5、反阈值取零
-
反阈值取零是与阈值取零相反的操作,它的定义是如大于阈值T,则赋值为零,若小于阈值T,则像素值保持不变
-
OpenCV 中阈值化的API
threshold(Mat src,Mat dst,double thresh,double maxval,int type) //src:输入图像,一般为8位单通道灰度图像 //dst:输出图像,类型与输入图像相同 //thresh:阈值T //maxval:最大灰度值,一般为255 //type:阈值化方法必须是上述五中之一 //THRESH_BINARY=0:阈值二值化 //THRESH_BINARY_INV=1:反阈值二值化 //THRESH_TRUNC=2:阈值截断 // THRESH_TOZERO=3:阈值取零 // THRESH_TOZERO_INV=4:反阈值取零
6、阈值
-
上面几种方法都是介绍如何对灰度图像进行阈值化操作。需要预先知道阈值T,OpenCV还提供了几种计算阈值T的方法,可以帮助我们自动计算阈值,当申明自动计算阈值T的时候,阈值化函数中的thresh赋值将不再起作用。OpenCV支持两种全局自动计算阈值方法分别是OTSU与Triangle这两种方法都是以图像直方图统计数据为基础来自动计算阈值的。
-
(1) OTSU
-
假设阈值为T,将直方图数据分割为两个部分,计算它们的类内方差类间方差,最准最小类方差或者最大类方差对应灰度值就是要计算得到阈值T
dsc = new Mat(); int t = 127; int maxValue = 255; Mat gray = new Mat(); Imgproc.cvtColor(src,gray,Imgproc.COLOR_BGR2GRAY); Imgproc.threshold(gray,dsc,t,maxValue,Imgproc.THRESH_BINARY|Imgproc.THRESH_OTSU);
-
-
(2)Triangle:
-
三角阈值法是对得到的直方图数据寻找最大峰值,从最大峰值得到垂直45度方向的三角形,计算最大斜边到直方图的距离d,对应的直方图灰度值即为图像阈值T\
Imgproc.threshold(gray,dst,t,maxValue,Imgproc.THRESH_BINARY|Imgproc.THRESH_TRIANGLE)
-
-
(3)自适应阈值
-
除了上述两种全局阈值方法,OpenCV还提供了图像自适应阈值化方法,自适应阈值计算方法有c均值与高斯c均值两种
ADAPTIVE_THRESH_MEAN_C ADAPTIVE_THRESH_GAUSSIAN_C adaptiveThreshold(Mat src,Mat dst,double maxValue,int adaptiveMethod,int thresholdType,int blockSize,double c) //src:输入图像,一般为8位单通道灰度图像 //dst:输出图像 //maxValue:最大灰度值,通常为255 //adaptiveMethod:自适应方法,C均值或者高斯C均值 //thresholdType:阈值化方法,五中阈值化方法之一,常见的阈值化方法为THRESH_BINARY //blockSize;分块大小 //C:常量值
- 具体代码:
dsc = new Mat(src.size(),CvType.CV_8UC1); Mat mat = new Mat(); src.convertTo(mat,CvType.CV_8UC1); Mat gray1 = new Mat(); Imgproc.cvtColor(mat,gray1,Imgproc.COLOR_BGRA2GRAY);//灰化 Imgproc.adaptiveThreshold(gray1,dsc,255,Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,Imgproc.THRESH_BINARY,15,10);
-
-