前言
本文将非常细致的讲解相关与计算机视觉OpenCV图像处理的相关知识即操作,非常的简单易懂。
推荐
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站
1、OpenCV礼帽操作和黑帽操作
图像顶帽操作也叫图像礼帽操作,实际上就是:
结果图像=原图像-图像开运算
那么我们知道图像的开运算就是对图像先腐蚀操作,然后在进行膨胀操作,得到的图像其实就是进行了取噪的一个处理,然后我们所说的礼帽图像操作就是使用原图像-图像的开运算操作。
函数依旧是:
result = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
其中img表示原始图像,cv2.MORPH_TOPHAT表示进行礼帽操作,然后kernel表示卷积核,这里我们之前已经讲过。
核心函数是:
k=np.ones((5,5),np.uint8) r=cv2.morphologyEx(o,cv2.MORPH_TOPHAT,k)
这样我们显示以下我们处理的图像就可以知道:
处理之后我们得到了相应的噪声结果。
图像黑帽操作就是图像的闭运算-原图像
黑帽结果图像=图像闭运算-原图像
我们之前也介绍过这个闭运算操作就是先对图像进行膨胀操作,然后进行腐蚀操作。
函数是:
result = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
其中cv2.MORPH_BLACKHAT表示的就是黑帽操作的意思,kernel表示卷积核。
然后我们看一下图像处理的核心函数:
k=np.ones((5,5),np.uint8) r=cv2.morphologyEx(o,cv2.MORPH_BLACKHAT,k)
得到的结果是:
可以看到我们把图像中的小气泡都取出来了。
2、Sobel算子理论基础及实际操作
首先我们来了解一个边界的定义,看一个图来理解更加的明白。
对于如图中的水平梯度,我们看A、B两个地方,右侧像素值减去左侧像素值不为0,那么我们就说在此图中A列和B列是边界,否则不是边界。同样对于垂直梯度我们也是这样定义。
对于Sobel算子,我们先来看x方向他进行了什么操作:
P5x=(p3-p1)+2*(p6-p4)+(p9-p7)
右侧像素值减去左侧像素值,中间行参数稍大为2。
同样对于y轴方向也做了一个同样的操作,
P5y=(p7-p1)+2*(p8-p2)+(p9-p3)
下一行像素值减去上一行像素值,中间列参数稍大为2
然后我们计算了一个近似梯度值:
G= 根号(𝐺𝑥2 + 𝐺𝑦2)
简化版本就是:
G=|𝐺𝑥|+| 𝐺𝑦|
这中心点的P5的Sobel算子就是按照这个方式进行计算。
对于P5点完成的Sobel算子计算就是这样:
那么好,我们来看一下在python中对于Sobel是一个什么样的函数:
dst = cv2.Sobel( src , ddepth , dx , dy , [ksize] )
其中src表示原始图像,ddeph表示图像的深度,那么我们一般设定为-1,用来表示和原图像保持一致。dx,dy表示x轴的方向或者y轴的方向,ksize表示核大小。
其中我们在已经知道的256色位图中,白色点像素值255,黑色点像素值0。
这里对于dx,dy方向为什么我们取绝对值进行一下解答,因为加入一块黑块在一个白色背景下,那么我们在水平方向上,左侧那么得到的数值就是一个负数,对于右侧那么我们得到的是就是一个正常的正数,那么对于OpenCV来说,当我们没有加绝对值得时候如果出现了负数,统一处理成0。
根据图我们就可以知道,左侧的线被OpenCV处理成了0。所以我们这里要加上一个绝对的运算。无论对于水平方向还是垂直方向都是如此。
然后我们要将原始图像处理成256为的色位图。其函数是:
dst = cv2.convertScaleAbs( src [, alpha[, beta]] )
目标图像=调整(原始图像*alpha+beta)
其中alpha和beta可以理解为权重的意思。
当我们想要计算水平方向上的Sobel算子的时候,那么我们就设定函数中的参数dx=1,dy=0.对于垂直方向也是如此。那么这里我们就会想:如果我们两个方向都一起设置这样是不是比计算完x的方向然后计算y方向,然后进行结合这样是不是更加的方便一些呢?也就是说下图中的方式一比方式二更加的简介方便呢?
事实上不是这样的,而且两个图像有很大的差异,这个我们后续会看到结果。
那么当我们完成了这一步操作之后,我们还要做两个图像的权重和,其函数是:
dst=cv2.addWeighted( src1 , alpha , src2 , beta , gamma )
这里我们说的通俗一点就是,src1表示计算的x轴方向的图像,alpha表示x轴方向上的图像所占的比重,src2表示计算的y轴方向的图像,beta表示y轴方向上的图像所占的比重是多少,最后gamma表示一个修正数值。
dst(I)=saturate(src1(I)*alpha+src2(I)*beta+gamma)
接下来我们来验证一下各个结果:
import cv2 import numpy as np o = cv2.imread('image\\sobel4.bmp',cv2.IMREAD_GRAYSCALE) sobelx = cv2.Sobel(o,-1,1,0) cv2.imshow("original",o) cv2.imshow("x",sobelx) cv2.waitKey() cv2.destroyAllWindows()
这里我们没有加上绝对值计算x轴方向上的Sobel算子,得到的结果是:
很明显左侧的没有计算出来。
import cv2 import numpy as np o = cv2.imread('image\\sobel4.bmp',cv2.IMREAD_GRAYSCALE) sobelx = cv2.Sobel(o,cv2.CV_64F,1,0) sobelx = cv2.convertScaleAbs(sobelx) # 转回uint8 cv2.imshow("original",o) cv2.imshow("x",sobelx) cv2.waitKey() cv2.destroyAllWindows()
当我们加上绝对值后的结果是:
对于垂直方向的结果也是如此。最后我们计算出x,y的方向。进行融合并且和直接将x,y表示成1的结果进行一下对比,我们来看结果:
核心代码:
sobelx = cv2.Sobel(o,cv2.CV_64F,1,0) sobely = cv2.Sobel(o,cv2.CV_64F,0,1) sobelx = cv2.convertScaleAbs(sobelx) # 转回uint8 sobely = cv2.convertScaleAbs(sobely) sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) sobelxy11=cv2.Sobel(o,cv2.CV_64F,1,1) sobelxy11=cv2.convertScaleAbs(sobelxy11)
根据结果我们可以得到:使用了dx,dy的情况下无法检测到边。然后我们用lena来测试一下结果。
在我们相加表示的情况下,边缘检测的线条十分清晰,将分割的地带表达的特别清楚。
【OpenCV】计算机视觉图像处理基础知识(下)+https://developer.aliyun.com/article/1502514