在之前的教程中,我们了解了OpenCV并进行了一些基本的图像处理,然后在下一个教程中我们在OpenCV中进行了一些图像处理,例如裁剪,旋转,图像变换等。在本教程的结尾,我们将构建一些python-opencv程序,以从网络摄像头实时供稿中生成实时草图。该应用程序将使用到目前为止已经学习或将在本教程中学习到的许多图像处理功能,因此这将是涵盖所有功能的一个很好的实际示例。
如上一教程所述, OpenCV是开源通勤者视觉库 ,具有C ++,Python和Java接口,并支持Windows,Linux,Mac OS,iOS和Android。因此,可以在具有Python和Linux环境的Raspberry Pi中轻松安装它。带有OpenCV和附加摄像头的Raspberry Pi可用于创建许多实时图像处理应用程序,例如人脸检测,人脸锁,物体跟踪,汽车车牌检测,家庭安全系统等。
在本教程中,我们将看到更多使用Python OpenCV进行图像处理的方法。在这里,我们将学习使用Python OpenCV在图像上应用以下功能:
- 按位运算和屏蔽
- 卷积与模糊
- 锐化-反转图像模糊
- 阈值化(二值化)
- 膨胀,侵蚀,开/关
- 边缘检测和图像渐变
- 透视和仿射变换
- 实时素描应用
1.按位运算和屏蔽
按位操作可帮助您进行图像遮罩,并帮助您创建一些简单的图像。
做一个正方形
import cv2 import numpy as np #我们仅使用二维图像,因为这是灰度图像,如果我们使用的是 #colored图像,则我们使用了矩形= np.zeros((300,300,3),np.uint8) #制作一个正方形 = np.zeros((300,300),np.uint8) cv2.rectangle(square,(50,50),(250,250),255,-1) cv2.imshow(“ square”,square) cv2。 waitKey(0)
制作椭圆
ellipse = np.zeros((300,300),np.uint8) cv2.ellipse(ellipse,(150,150),(150,150),30,0,180,255,-1) cv2.imshow(“ ellipse”,ellipse) cv2.waitKey(0 )
试验按位运算
#AND_仅显示两个相交的位置
bitwiseAND = cv2.bitwise_and(square,ellipse) cv2.imshow(“ AND”,BitwiseAND) cv2.waitKey(0)
#OR_仅显示正方形或椭圆形的位置
BitwiseOR = cv2.bitwise_or(square,ellipse) cv2.imshow(“ OR”,BitwiseOR) cv2.waitKey(0)
#XOR_仅显示其中一个存在的地方
BitwiseXOR = cv2.bitwise_xor(square,ellipse) cv2.imshow(“ XOR”,BitwiseXOR) cv2.waitKey(0)
#NOT_显示不属于椭圆的所有内容, NOT操作只能应用于单个图形
BitwiseNOT_elp = cv2.bitwise_not(椭圆) cv2.imshow(“ NOT_ellipse”,BitwiseNOT_elp) cv2.waitKey(0) cv2.destroyAllWindows()
2.卷积与模糊
甲卷积是上产生第三功能通常是原始函数的修改版本两个函数执行的数学运算。
输出图像=图像功能内核大小
在计算机视觉中,我们使用内核来指定在图像上运行操纵函数的大小。
模糊是对区域(像素)中的像素进行平均的操作
OpenCV通过应用内核使图像模糊,内核告诉您如何通过将其与不同数量的相邻像素组合来更改任何给定像素的值,内核将内核逐个应用于图像中的每个像素以生成最终图像。
简而言之,图像卷积就是两个矩阵相加后的总和。
我们可以通过以下示例简单地了解它。
上面是一个3X3内核。
我们乘以1/25进行归一化,即总和为1,就像在图像变亮或变暗的情况下,我们一直在增加强度或减小强度。
让我们测试一个由函数cv2.filter2D给定的opencv模糊方法filter2D(图像,-1,内核)
import cv2 import numpy as np image = cv2.imread('elephant.jpg') cv2.imshow('original',image) cv2.waitKey(0)
#创建3x3内核矩阵
kernel_3x3 = np.ones((3,3),np.float32)/ 9
#我们使用cv2.filter2D将内核与图像进行卷积
blurd = cv2.filter2D(image,-1,kernel_3x3) cv2.imshow('3x3_blurring',模糊) cv2.waitKey(0)
#创建7x7内核矩阵
kernel_7x7 = np.ones((7,7),np.float32)/ 49
#我们使用cv2.filter2D将内核与图像进行卷积
blurd = cv2.filter2D(image,-1,kernel_7x7)cv2.imshow('7x7_blurring',模糊)cv2.waitKey(0)cv2.destroyAllWindows()
还有其他类型的模糊方法:
cv2.blur –指定窗口的平均值。
cv2.GaussianBlur –类似,但使用高斯窗口(更多强调中心点)。
cv2.medianBlur –使用窗口中所有元素的中位数。
cv2.bilateralFilter –在保持边缘清晰的同时模糊,它保留了边缘和线条细节。
我们将在下面一个接一个地看到,首先使用以下代码显示原始图像:
import cv2 import numpy as np image = cv2.imread('elephant.jpg') cv2.imshow('original',image) cv2.waitKey(0)
cv2.blur:
在这种方法中,平均是通过使用归一化的框滤镜对图像进行卷积来完成的,取而代之的是在框下并替换中心元素。这里的盒子大小必须是奇数和正数 。
#cv2.blur blur = cv2.blur(image,(3,3)) cv2.imshow('Averaging',blur) cv2.waitKey(0)
cv2.GaussianBlur:
#cv2.GaussianBlur#代替 盒式过滤器,让我们尝试高斯内核 Gaussian = cv2.GaussianBlur(image,(7,7),0) cv2.imshow('Gaussian blurring',Gaussian) cv2.waitKey(0)
cv2.medianBlur:
它需要内核区域下所有像素的中值,并且中心元素将替换为该中值。
#cv2.medianBlur#获取 内核区域下所有像素的中值,并将中心元素 #替换为该中值。 中值= cv2.medianBlur(图像,5)cv2.imshow( '中间模糊',中值) cv2.waitKey(0)
cv2.bilateralFilter:
双边在去除噪声的同时非常有效地保持边缘清晰
#cv2.bilateralFilter#双边 在去除噪声方面非常有效,同时保持边缘的锐利 双边= cv2.bilateralFilter(image,9,75,75) cv2.imshow('bilateral模糊',bilateral) cv2.waitKey(0) cv2。 destroyAllWindows()
图像去噪-非局部意味着去噪
import cv2 import numpy as np image = cv2.imread('elephant.jpg') cv2.imshow('original',image) cv2.waitKey(0)
#无后的参数是滤光强度'h'(5-10是一个很好的范围) #next是颜色分量的h,再次将其设置为与h相同
dst = cv2.fastNlMeansDenoisingColored(image,None,6,6,7,21) cv2.imshow('Fast means denois',dst) cv2.waitKey(0) cv2.destroyAllWindows()
非本地均值去噪有4种变化
cv2.fastNlMeansDenoising() –用于单个灰度图像
cv2.fastNlMeansDenoisingColored() –单色图像
cv2.fastNlmeansDenoisingMulti() –用于图像序列灰度
cv2.fastNlmeansDenoisingcoloredMulti() –用于彩色图像序列
3.锐化-反转图像模糊
锐化与模糊相反,它增强或强调图像边缘。
内核=,,
我们的内核矩阵总和为1,因此无需进行归一化(即乘以与原始亮度相同的亮度),如果内核未归一化为1,则图像会更亮或更暗。
import cv2 import numpy as np image = cv2.imread('elephant.jpg') cv2.imshow('original',image) cv2.waitKey(0)
kernel_sharpening = np.array(,
,
])
#将锐化内核应用于输入图像
sharpened = cv2.filter2D(image,-1,kernel_sharpening) cv2.imshow('sharpened image',sharpened) cv2.waitKey(0) cv2.destroyAllWindows()
4.脱粒(二值化)
阈值化是将图像转换为二进制形式的行为。在opencv中,有一个单独的函数用于阈值定义为
Cv2.threshold(图像,阈值,最大值,阈值类型)
有以下阈值类型:
- cv2.THRESH_BINARY –最常见
- cv2。THRESH_BINARY_INV –最常见
- cv2.THRESH_TRUNC
- cv2.THRESH_TOZERO
- cv2。THRESH_TOZERO_INV
注意:在阈值化之前需要将图像转换为灰度
import cv2 import numpy as np #将图像加载为灰度 图像= cv2.imread('gradient.jpg',0) cv2.imshow('original',image) cv2.waitKey(0)
#value低于127变为0(黑色),高于127则变为255(白色)
_,thresh1 = cv2.threshold(image,127,255,cv2.THRESH_BINARY)cv2.imshow('1 threshold',thresh1) cv2.waitKey(0)
#低于127的值转到255,高于127的值转到0(与上面相反)
_,thresh2 = cv2.threshold(image,127,255,cv2.THRESH_BINARY_INV) cv2.imshow('2 threshold',thresh2) cv2.waitKey(0)
127上的#value在127处被截断(保留),未使用255参数。
_,thresh3 = cv2.threshold(image,127,255,cv2.THRESH_TRUNC) cv2.imshow('3 thresh trunc',thresh3) cv2.waitKey(0)
#低于127的值变为0,高于127的值保持不变
_,thresh4 = cv2.threshold(image,127,255,cv2.THRESH_TOZERO) cv2.imshow('4 threshold',thresh4) cv2.waitKey(0)
#高于127以下的收益不变,高于127变为零
_,thresh5 = cv2.threshold(image,127,255,cv2.THRESH_TOZERO_INV) cv2.imshow('5 threshold',thresh5) cv2.waitKey(0) cv2.destroyAllWindows()
5.膨胀,侵蚀,开/关
这些是数学形态学领域中的操作
扩散-它将像素添加到图像中对象的边界。
侵蚀–删除图像中对象边界处的像素。
开口–侵蚀,然后膨胀。
封闭-膨胀后腐蚀。
开口对图像去噪非常有帮助,因为它首先通过腐蚀使图像变薄(消除噪声),然后对其进行扩张。
与扩张和侵蚀混淆
有时在带有白色背景的图片中,扩张和腐蚀之间有时会混淆,因为opencv认为白色背景是要扩张或腐蚀的图像,而不是原始图片,因此在这种情况下,腐蚀起着扩张的作用,反之亦然,如图像样本所示如下所示。
请记住,“ 膨胀”会将像素添加到图像中对象的边界,而“侵蚀”则会删除图像中对象的边界处的像素
导入cv2 将numpy导入为np image = cv2.imread('imagecv.png',0) cv2.imshow('original',image) cv2.waitKey(0)
# Erosion
#让我们定义内核大小
内核= np.ones((5,5),np.uint8)
#现在我们侵蚀了图像,在这里迭代不再是您想要侵蚀图像的时候了
腐蚀= cv2.erode(图像,内核,迭代次数= 1) cv2.imshow('腐蚀',腐蚀) cv2.waitKey(0)
#扩张
dilation = cv2.dilate(image,kernel,iterations = 1) cv2.imshow('dilation',dilation) cv2.waitKey(0)
#opening,有益于消除噪音
开头= cv2.morphologyEx(图像,cv2.MORPH_OPEN,内核) cv2.imshow('opening',opening) cv2.waitKey(0)
#关闭,适合消除噪音
闭合= cv2.morphologyEx(图像,cv2.MORPH_CLOSE,内核) cv2.imshow('关闭',关闭) cv2.waitKey(0) cv2.destroyAllWindows()
6.边缘检测和图像渐变
边缘检测是计算机视觉中非常重要的领域,尤其是在处理轮廓时。
边缘可以定义为图像的边界,实际上,边缘是在图像中定义对象的边缘,它们保留了大量有关图像的信息。
形式上,边缘可以定义为图像中的突然变化(不连续),并且它们可以编码与像素一样多的信息。
上图显示了计算机视觉如何识别和识别图像。
边缘检测算法:-边缘检测算法有三种主要类型
- Sobel –强调垂直或水平图像。
- 拉普拉斯算子(Laplacian)–由于错误率低,定义良好的边缘和准确的检测而达到最佳。
- Canny Edge检测算法(由john.F.Canny于1986年开发)
1.应用高斯模糊
2.查找图像的强度梯度
3.应用非最大抑制(即,删除不是边缘的像素)。
4.迟滞应用阈值(即,如果像素在上下阈值之内,则视为边缘)
import cv2 import numpy as np image = cv2.imread('input.jpg',0) height,width = image.shape
#sobel
#提取sobel边缘
sobel_x = cv2.Sobel(图像,cv2.CV_64F,0,1,ksize = 5) sobel_y = cv2.Sobel(图像,cv2.CV_64F,1,0,ksize = 5) cv2.imshow('原始',图像) cv2.waitKey(0) cv2.imshow('sobelx',sobel_x)cv2.waitKey(0)
#Sobely
cv2.imshow('sobely',sobel_y) cv2.waitKey(0)
sobel_OR = cv2.bitwise_or(sobel_x,sobel_y)cv2.imshow('sobelOR',sobel_OR)cv2.waitKey(0)
#laplaian
laplacian = cv2.Laplacian(image,cv2.CV_64F) cv2.imshow('Laplacian',laplacian) cv2.waitKey(0)
#canny边缘检测算法使用梯度值作为阈值
#在canny中,我们需要提供两个值:threshold1和threshold2。
#任何大于阈值2的坡度均视为边缘。
#任何大于阈值1的坡度均不视为边缘。
在阈值1和阈值2之间#values要么为边缘或非边缘
#on它们的强度是如何连接的,在这种情况下,低于60的任何值都考虑
#non边缘wheareas高于120的任何值被认为是边缘。
canny = cv2.Canny(图像,60,120) cv2.imshow('canny',canny) cv2.waitKey(0) cv2.destroyAllWindows()
14.透视和仿射变换
让我们退后一步,看一下仿射和非仿射变换,下面显示的原始图像显然是非仿射图像,因为边缘将在某个点相遇,但是,我们可以通过变形和透视图将其拉直转变。
对于此透视变换,我们需要原始图像的四个坐标,然后是输出图像的四个点,它们由points_A和points_B表示。首先,借助这些点,我们借助 getPerspectiveTransform函数 计算一个转换矩阵M。
然后将此矩阵提供给 warpPerspective 函数以生成最终输出。
现在让我们首先尝试透视变换。
导入cv2 导入numpy作为np 导入matplotlib.pyplot作为plt image = cv2.imread('paper.jpg') cv2.imshow('原始',图像) cv2.waitKey(0)
#原始图片四个角的坐标
points_A = np.float32(,,,])
#所需输出的4个角的
坐标#我们使用A4纸的比例为1:1.41
points_B = np.float32(,,,])
#使用两组两个两点计算预期的变换矩阵M
M = cv2.getPerspectiveTransform(points_A,points_B) warped = cv2.warpPerspective(image,M,(420,594)) cv2.imshow('warpprespective',warped) cv2.waitKey(0) cv2.destroyAllWindows()
仿射变换比非仿射变换更容易,因为我们只需要三个点就可以得到变换。整个过程是一样的,但是现在我们有了仿射变换,而不是透视变换,而且我们还通过形状函数在 warpAffine中 定义了cols和rows,而不是手动输入。
导入cv2 导入numpy作为np 导入matplotlib.pyplot作为plt image = cv2.imread('box.jpg') 行,cols = image.shape cv2.imshow('original',image) cv2.waitKey(0)
#原始图片3个角的坐标
points_A = np.float32(,,])
#所需输出的3个角的
坐标#我们使用A4纸的比例为1:1.41
points_B = np.float32(,,])
#使用两组两个两点计算仿射
#变换矩阵,M
M = cv2.getAffineTransform(points_A,points_B) warped = cv2.warpAffine(image,M,(cols,rows)) cv2.imshow('warpaffine',warped) cv2.waitKey(0) cv2.destroyAllWindows()
8.实时素描应用
首先,祝贺您阅读了上面的所有图像处理功能后,您已经组成了这个小型项目。因此,在这个Python OpenCV小型项目中,我们将学习一些新的循环和函数概念。如果您熟悉编程,则必须对功能和循环有更广泛的了解。但是,在python中,循环和函数的基本概念保持不变,但是定义它们的方法有所不同。
因此,在该程序开始时,我们可以在“ def sketch(image): ”下看到特定的一组语句标题,这是函数的正式定义,一组特定的语句共同作用于特定的输出。
因此,此草图是一个函数,在python中,函数由“ def”定义并以“:”标记结束。此外,功能内部需要自动对齐的语句,或者可以说功能正常运行所必需的语句。因此,要从功能中出来,这些语句必须完全左对齐。有关更多参考,您可以向google咨询有关如何在python中定义函数的信息。
因此,在此素描功能中,我们引入了几层图像处理,这些图像处理结合在一起以提供输出。首先,将图像转换为灰度,以便opencv可以轻松地对其进行处理,然后对灰度图像应用高斯模糊,以减少噪声。然后,边在提取与精明的边缘检测算法的帮助,那么二进制逆边缘定义的图像上的应用,这里的二进制逆也可以通过bitwise_NOT完成,但因为它提供了自由,我们故意选择这个阈值的二进制逆设置其参数,直到获得清晰的图像。
还要注意,该函数采用参数image并返回两个参数ret和mask。 ret是布尔值,表示函数是否成功运行,掩码是函数的最终输出,即处理后的图像。
然后第二个概念是通过 cv2.VideoCapture(0) 函数在opencv中操作网络摄像头,该函数将图像存储在对象 cap中 ,可以使用 cap.read() 函数读取 cap ,此处还要注意 cap。 read() 位于无限 while循环 内,因为它必须连续捕获图像,以使其具有实时视频的感觉,其中视频的帧频将是您网络摄像头的帧频,通常在24到60之间fps。
cap.read() 返回ret和frame,其中ret是一个布尔值,指示函数是否成功运行,并且该帧包含网络摄像头拍摄的图像。
以下是用于运行Live Sketch的完整Python OpenCV代码
import cv2 import numpy as np #sketch generation function def sketch(image): #将图像转换为灰度 img_gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) #使用高斯模糊清理图像 img_gray_blur = cv2.GaussianBlur(img_gray 5,5),0) #提取边缘canny_edges = cv2.Canny(img_gray_blur,10,70)# 进行反二值化图像 ret,mask = cv2.threshold(canny_edges,70,255,cv2.THRESH_BINARY_INV) 返回蒙版 #初始化网络摄像头,cap是视频捕获 提供的对象#它包含一个布尔值,指示是否成功(ret ) #it还包含从网络摄像头(frame) cap = cv2.VideoCapture(0) 收集的图像,为True时: ret,frame = cap.read() cv2.imshow('livesketcher',sketch(frame)) 如果cv2.waitKey (1)== 13:#13是Enterkey 中断 #释放摄像头并关闭窗口,请记住在cap.release() cap.release() cv2.destroyAllWindows()的帮助下释放网络摄像头
因此,这是Python-OpenCV中图像处理的第2部分的结尾。为了更好地了解计算机视觉和OpenCV,请阅读以前的文章(Python OpenCV入门和Python OpenCV中的图像处理(第1部分),您将可以使用Computer Vision做出一些很棒的事情。