OpenCV进阶图像操作

距离基础操作篇也差不多一周了,其中有许多文章用到了一些常用的但还没来得及介绍的图像操作函数,于是这一篇进阶篇就应运而生了。

本篇会首先通俗地讲解各种图像处理的基本原理以帮助了解,然后运用代码帮助大家学会应用,获得结果帮助大家直观感受其作用。

因为这里很多知识都是我在学习车牌识别时知道的,所以我们拿一个车牌作为示意图。
OpenCV进阶图像操作_第1张图片

平滑图像

什么是平滑呢?我觉得这个词是和陡峭完全相反,说起陡峭我们自然想到了上一篇文章提到的梯度。也就是说,我们希望图像的各个梯度值小一点,那么像素之间就自然平滑起来。

如果大家还是一头雾水的话,那我再换个说法,模糊。我们让边缘变得模糊,不那么明显,其实就是削弱梯度。

平滑图像一般被我们用来消除环境噪声的影响。什么是噪声?我们假设一副理想的图片,其像素值都是128 。但实际中,由于环境的影响,我们拍摄出的真实图片可能在一些像素点上加上或减少一些值,就使得本来应该全是128的一个光滑的平面,偶尔可以看见129,130的凸起,偶尔可以看见127,126的凹陷。所以,为了消除这些噪声的不平滑,从而使图片更接近于它真实的模样,我们需要平滑。

平滑的方法有很多,在这里我介绍一下高斯平滑。
OpenCV进阶图像操作_第2张图片这是一个内核,用这个内核乘以同尺寸的图像区域再除以上面核外的系数就完成了对该区域的高斯平滑。首先,我先解释一下内核里的数值是如何选取的吧。我们看看它的名字,高斯,一下子就能联想到高斯分布,没错,你再仔细观察下内核数字分布的规律就明白这是一个高斯分布。也就是说,我们会对区域中心的像素值给予最高的权重(保证基础特征),然后依次向外递减。我们可以观察到四周方向对应位置的权重值都是一样的,这样就保证了四周的过渡比较平滑。当然,我们应该也要意识到,内核的面积越大,代表图像越平滑(模糊),要如何抉择取决于实际情况。

那我们实践试试吧

导入相应的库和图像

import cv2
import argparse
import imutils

ap=argparse.ArgumentParser()
ap.add_argument("-i","--image",required=True)
args=vars(ap.parse_args())

image=cv2.imread(args["image"])

高斯平滑处理GaussianBlur(),我们平时更改第二个参数内核大小即可。

blurred=cv2.GaussianBlur(image,(11,11),0)
cv2.imshow("Blurred",blurred)
cv2.waitKey(0)

OpenCV进阶图像操作_第3张图片

绘图

看到这标题我猜可能有人要问,我学计算机视觉你教我绘图干啥呀?不急,我相信你肯定看过一些人脸识别,物体识别的图片,你可以看到他们外围有一个框围住他们,然后左上角有个分类名称,这就是我们需要掌握的绘图。

原理我就不过多介绍了,直接上代码吧。

rectangle()函数,第一个参数是长方形左上角的坐标(x,y),第二个参数是右下角的坐标。这里我是提前测好了,填上去的。第三个参数是线的颜色,以B,G,R为顺序,这里就是纯红色了。第四个参数是线的粗细。

output=image.copy()
cv2.rectangle(output,(43,166),(617,349),(0,0,255),2)
cv2.imshow("Rectangle",output)
cv2.waitKey(0)

OpenCV进阶图像操作_第4张图片

putText(),这个我想有了上面的例子我就不过多解释了。

output=image.copy()
cv2.putText(output,"Hello,world",(300,166),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,255,0),2)
cv2.imshow("Text",output)
cv2.waitKey(0)

OpenCV进阶图像操作_第5张图片

边缘检测

边缘检测也可以理解成梯度检测,一般在边缘两侧的像素值会有一个明显的差异,从而导致了梯度数值较大。在这里,我们主要了解下Canny边缘检测的机制。

首先,它先对图像进行平滑处理,即消除噪声的影响。我们刚刚解释了噪声对于梯度的影响。

计算完梯度的数值和方向后,我们会进行非极大值抑制。即遍历所有值,并判断是否是局部最大值,如果是则保留,如果不是则清零(抑制)。

于是,我们得到了一副梯度全都是局部最大值的结果。但是,即使是最大值,也只是局部的,那么到底应不应该把所有的局部最大值都归为边缘呢?我们还要加个判断标准,来避免一些强噪声的影响。

这个方法叫做双阈值,即人为设定一个高阈值和一个低阈值。梯度幅值大于高阈值的我们认为是强边缘,保留;在高阈值和低阈值之间的,我们认为是弱边缘,先保留,后续再处理;对于小于低阈值的,我们进行抑制。对于弱边缘,我们进一步判断其是否与强边缘连接,若不连接则进行抑制。

进行这些处理后,我们就得到了我们的边缘图形。

Canny()的第一个参数是输入的图像,第二个第三个分别是我们设定的高阈值和低阈值。

gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

edged=cv2.Canny(gray,30,150)
cv2.imshow("Edged",edged)
cv2.waitKey(0)

OpenCV进阶图像操作_第6张图片

阈值化

阈值化是将一副图像转化为黑(背景)白(前景)的操作,是图像处理管道的重要中间步骤。阈值化可以帮助我们去除图像中较亮或较暗的区域和轮廓。

其具体操作是人为设定一个阈值,如果大于这个阈值则把它赋予一个新值,一般为255(白色)。小于这个阈值的部分设为0(黑色)。

thresh=cv2.threshold(gray,225,255,cv2.THRESH_BINARY_INV)[1]
cv2.imshow("Thresh",thresh)
cv2.waitKey(0)

OpenCV进阶图像操作_第7张图片

检测和描绘轮廓

轮廓的检测其实也和梯度有关,大家稍微细想一下就可以明白。

这个findContours()函数。第一个参数自然是输入的图像,但这里注意我们输入的我们之前阈值化得到的二值图。第二个参数是检索轮廓的方法,文中的是只检测外轮廓,一般足够,其他不再赘述,如果想了解可以专门搜索其函数的参数详解。第三个参数是保存轮廓的方法,在这里提两个,一个是保留轮廓所有点CHAIN_APPROX_NONE,一个是保留可以大致表述出轮廓的点CHAIN_APPROX_SIMPLE。例如一个矩形轮廓,我们可以选择保留所有坐标,也可以选择保留四个角的坐标。

但是,轮廓的检索可能会得到很多我们并不想要的轮廓,于是我们可以通过判断面积大小(此文)或者判断轮廓有多少个角(后续文章会有相关的应用)等方法去筛选我们想要的轮廓。这里我们用sorted方法,将轮廓按面积排序并选取了最大的来显示。

绘制轮廓的函数drawContours(),第二个参数是一个list。第三个参数为-1时指明绘制第二个参数所有的轮廓。

cnts=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=imutils.grab_contours(cnts)
cnt=sorted(cnts,key=cv2.contourArea,reverse=True)[0]
output=image.copy()
cv2.drawContours(output,[cnt],-1,(240,0,159),3)
cv2.imshow("Contours",output)
cv2.waitKey(0)

OpenCV进阶图像操作_第8张图片

腐蚀

腐蚀,我们也可以叫做减肥,等下可以和后面的膨胀进行一个对比。在我们得到的二值化的阈值图中,前景可能存在一些毛刺或者我们不想看到的小瑕疵。比如,我们回看阈值图,在文字和数字的镂空中,存在一些白色的瑕疵,腐蚀就是消除这些瑕疵的。

具体操作是,我们首先设定卷积核的大小iterations。要判断是否是瑕疵,我们就判断以该白色点为中心的卷积核中是否存在黑色(0),如果存在就把该点置为黑色(0)。当然,这种方法势必会使边缘的白色都被置为黑色,所以导致前景看起来,瘦了一圈,就像被腐蚀了一样。

mask=thresh.copy()
mask=cv2.erode(mask,None,iterations=3)
cv2.imshow("Eroded",mask)
cv2.waitKey(0)

OpenCV进阶图像操作_第9张图片

膨胀

膨胀的原理与腐蚀类似,但其操作却是相反,这里不过多赘述。

mask=thresh.copy()
mask=cv2.dilate(mask,None,iterations=3)
cv2.imshow("Dilated",mask)
cv2.waitKey(0)

OpenCV进阶图像操作_第10张图片

屏蔽

有时我们只关注图像的一部分或者我们想要消除掉无关背景的干扰,我们就需要屏蔽掉我们不关心的部分。阈值图其实就像一个面具,白色的前景就是面具显露出来的眼睛,黑色的背景则是我们想要遮掩的面庞。

这里其实是运用了逻辑运算的知识,或者我们可以理解为乘法。将白色看作1,黑色看作0 。1乘以任何数都等于本身,所以这些部分被原本的留了下来。0乘以任何数都等于0,所以这些部分都化作了背景。

mask=thresh.copy()
output=cv2.bitwise_and(image,image,mask=mask)
cv2.imshow("Output",output)
cv2.waitKey(0)

OpenCV进阶图像操作_第11张图片
“本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/kasami_/article/details/123913483。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。”

你可能感兴趣的:(计算机视觉,从头开始,opencv,python,图像处理)