涉及内容:
你将需要两个主要的库,第三个可选:python-OpenCV,Numpy 和 Matplotlib。
一、加载图片
首先,我们正在导入一些东西,我已经安装了这三个模块。接下来,我们将img定义为cv2.read(image file, parms)。默认值是IMREAD_COLOR,这是没有任何 alpha 通道的颜色。如果你不熟悉,alpha 是不透明度(与透明度相反)。如果你需要保留 Alpha 通道,也可以使用IMREAD_UNCHANGED。很多时候,你会读取颜色版本,然后将其转换为灰度。如果你没有网络摄像机,这将是你在本教程中使用的主要方法,即加载图像。
你可以不使用IMREAD_COLOR …等,而是使用简单的数字。你应该熟悉这两种选择,以便了解某个人在做什么。对于第二个参数,可以使用-1,0或1。颜色为1,灰度为0,不变为-1。因此,对于灰度,可以执行cv2.imread(‘watch.jpg’, 0)。
一旦加载完成,我们使用cv2.imshow(title,image)来显示图像。从这里,我们使用cv2.waitKey(0)来等待,直到有任何按键被按下。一旦完成,我们使用cv2.destroyAllWindows()来关闭所有的东西。
import cv2
import matplotlib
import numpy
img = cv2.imread('sources/2.jpg', 0)
cv2.imshow("myWindow", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、加载视频源
在这个 Python OpenCV 教程中,我们将介绍一些使用视频和摄像头的基本操作。 除了起始行,处理来自视频的帧与处理图像是一样的。 我们来举例说明一下:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)#从计算机上的第一个网络摄像头返回视频
while True:
ret, frame = cap.read()
#其中ret是布尔值,如果读取帧是正确的则返回True,如果文件读取到结尾,它的返回值就为False。
#frame就是每一帧的图像,是个三维矩阵。
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', gray)
if cv2.waitKey(0) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
首先,我们导入numpy和cv2,没有什么特别的。 接下来,我们可以cap = cv2.VideoCapture(0)。 这将从你计算机上的第一个网络摄像头返回视频。 如果你正在观看视频教程,你将看到我正在使用1,因为我的第一个摄像头正在录制我,第二个摄像头用于实际的教程源。
while(True): ret, frame = cap.read()
这段代码启动了一个无限循环(稍后将被break语句打破),其中ret和frame被定义为cap.read()。 基本上,ret是一个代表是否有返回的布尔值,frame是每个返回的帧。 如果没有帧,你不会得到错误,你会得到None。
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
在这里,我们定义一个新的变量gray,作为转换为灰度的帧。 注意这个BGR2GRAY。 需要注意的是,OpenCV 将颜色读取为 BGR(蓝绿色红色),但大多数计算机应用程序读取为 RGB(红绿蓝)。 记住这一点。
cv2.imshow(‘frame’,gray)
请注意,尽管是视频流,我们仍然使用imshow。 在这里,我们展示了转换为灰色的源。 如果你想同时显示,你可以对原始帧和灰度执行imshow,将出现两个窗口。
if cv2.waitKey(1) & 0xFF == ord(‘q’): break
这个语句每帧只运行一次。 基本上,如果我们得到一个按键,那个键是q,我们将退出while循环,然后运行:
cap.release()cv2.destroyAllWindows()
这将释放网络摄像头,然后关闭所有的imshow()窗口。
在某些情况下,你可能实际上需要录制,并将录制内容保存到新文件中。 以下是在 Windows 上执行此操作的示例:
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out.write(frame)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
这里主要要注意的是正在使用的编解码器,以及在while循环之前定义的输出信息。 然后,在while循环中,我们使用out.write()来输出帧。 最后,在while循环之外,在我们释放摄像头之后,我们也释放out。
太好了,现在我们知道如何操作图像和视频。 如果你没有网络摄像头,你可以使用图像甚至视频来跟随教程的其余部分。 如果你希望使用视频而不是网络摄像头作为源,则可以为视频指定文件路径,而不是摄像头号码。
现在我们可以使用来源了,让我们来展示如何绘制东西。 此前你已经看到,你可以使用 Matplotlib 在图片顶部绘制,但是 Matplotlib 并不真正用于此目的,特别是不能用于视频源。 幸运的是,OpenCV 提供了一些很棒的工具,来帮助我们实时绘制和标记我们的源,这就是我们将在下一个教程中讨论的内容。
三、在图像上绘制和写字
在这个 Python OpenCV 教程中,我们将介绍如何在图像和视频上绘制各种形状。 想要以某种方式标记检测到的对象是相当普遍的,所以我们人类可以很容易地看到我们的程序是否按照我们的希望工作。 一个例子就是之前显示的图像之一:
鼓励你使用自己的图片。 像往常一样,我们的起始代码可以是这样的:
import numpy as np
import cv2
img = cv2.imread(‘watch.jpg’,cv2.IMREAD_COLOR)
下面,我们可以开始绘制,这样:
cv2.line(img,(0,0),(150,150),(255,255,255),15)
cv2.imshow(‘image’,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.line()接受以下参数:图片,开始坐标,结束坐标,颜色(bgr),线条粗细。
结果在这里:
好吧,很酷,让我们绘制更多形状。 接下来是一个矩形:
cv2.rectangle(img,(15,25),(200,150),(0,0,255),15)
这里的参数是图像,左上角坐标,右下角坐标,颜色和线条粗细。
圆怎么样?
cv2.circle(img,(100,63), 55, (0,255,0), -1)
这里的参数是图像/帧,圆心,半径,颜色和。 注意我们粗细为-1。 这意味着将填充对象,所以我们会得到一个圆。
线条,矩形和圆都很酷,但是如果我们想要五边形,八边形或十八边形? 没问题!
首先,我们将坐标数组称为pts(点的简称)。 然后,我们使用cv2.polylines来画线。 参数如下:绘制的对象,坐标,我们应该连接终止的和起始点,颜色和粗细。
import numpy as np
import cv2
img = cv2.imread('sources/2.jpg', cv2.IMREAD_COLOR)
pts = np.array([[10,5],[200,300],[200,400],[100,400],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv2.polylines(img, [pts], True, (0,255,255), 5)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
你可能想要做的最后一件事是在图像上写字。 这可以这样做:
import numpy as np
import cv2
img = cv2.imread('sources/2.jpg',cv2.IMREAD_COLOR)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, 'OpenCV Tuts!',(10,400), font, 2, (200,255,155), 5, cv2.LINE_AA)
#参数依次为 图片,文字,文字起始位置,font,文字大小,文字颜色,文字粗细,cv2.LINE_AA
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在下一个教程中,我们将介绍我们可以执行的基本图像操作。
四、图像操作
在 OpenCV 教程中,我们将介绍一些我们可以做的简单图像操作。 每个视频分解成帧。 然后每一帧,就像一个图像,分解成存储在行和列中的,帧/图片中的像素。 每个像素都有一个坐标位置,每个像素都由颜色值组成。 让我们列举访问不同的位的一些例子。
我们将像往常一样读取图像(如果可以,请使用自己的图像,但这里是我在这里使用的图像):
import cv2
import numpy as np
img = cv2.imread(‘watch.jpg’,cv2.IMREAD_COLOR)
现在我们可以实际引用特定像素,像这样:
px = img[55,55]
下面我们可以实际修改像素:
img[55,55] = [255,255,255]
之后重新引用:
px = img[55,55]
print(px)
现在应该不同了,下面我们可以引用 ROI,图像区域:
px = img[100:150,100:150]
print(px)
我们也可以修改 ROI,像这样:
img[100:150,100:150] = [255,255,255]
我们可以引用我们的图像的特定特征:
print(img.shape)
print(img.size)
print(img.dtype)
我们可以像这样执行操作:
watch_face = img[37:111,107:194] #[y1:y2,x1:x2] x为纵向,y为横向
img[0:74,0:87] = watch_facecv2.imshow(‘image’,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这会处理我的图像,但是可能不能用于你的图像,取决于尺寸。这是我的输出:
这些是一些简单的操作。 在下一个教程中,我们将介绍一些我们可以执行的更高级的图像操作。
五、图像算术和逻辑运算
欢迎来到另一个 Python OpenCV 教程,在本教程中,我们将介绍一些简单算术运算,我们可以在图像上执行的,并解释它们的作用。 为此,我们将需要两个相同大小的图像来开始,然后是一个较小的图像和一个较大的图像。 首先,我将使用:和
首先,让我们看看简单的加法会做什么:
import cv2
import numpy as np
#500 x 250
img1 = cv2.imread('3D-Matplotlib.png')
img2 = cv2.imread('mainsvmimage.png')
add = img1+img2
cv2.imshow('add',add)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
你不可能想要这种混乱的加法。 OpenCV 有一个“加法”方法,让我们替换以前的“加法”,看看是什么:
add = cv2.add(img1,img2)
这里可能不理想。 我们可以看到很多图像是非常“白色的”。 这是因为颜色是 0-255,其中 255 是“全亮”。 因此,例如:
(155,211,79) + (50, 170, 200) = 205, 381, 279…转换为(205, 255,255)。
接下来,我们可以添加图像,并可以假设每个图像都有不同的“权重”。 这是如何工作的:
import cv2
import numpy as np
img1 = cv2.imread('3D-Matplotlib.png')
img2 = cv2.imread('mainsvmimage.png')
weighted = cv2.addWeighted(img1, 0.6, img2, 0.4, 0)
cv2.imshow('weighted',weighted)
cv2.waitKey(0)
cv2.destroyAllWindows()
对于addWeighted方法,参数是第一个图像,权重,第二个图像,权重,然后是伽马值,这是一个光的测量值。 我们现在就把它保留为零。
这些是一些额外的选择,但如果你真的想将一个图像添加到另一个,最新的重叠在哪里? 在这种情况下,你会从最大的开始,然后添加较小的图像。 为此,我们将使用相同的小黑图像,但使用一个新的 Python 标志:
现在,我们可以选取这个标志,并把它放在原始图像上。 这很容易(基本上使用我们在前一个教程中使用的相同代码,我们用一个新的东西替换了图像区域(ROI)),但是如果我们只想要标志部分而不是白色背景呢? 我们可以使用与之前用于 ROI 替换相同的原理,但是我们需要一种方法来“去除”标志的背景,使得白色不会不必要地阻挡更多背景图像。 首先我将显示完整的代码,然后解释:
import cv2
import numpy as np
#Load two images
img1 = cv2.imread('sources/1.jpg')
img2 = cv2.imread('sources/3.jpg')
#I want to put logo on top-left corner, So I create a ROI
rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]
#Now create a mask of logo and create its inverse mask
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
# add a threshold
ret,mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)
mask_inv = cv2.bitwise_not(mask)
# Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
# Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2, img2, mask=mask)
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols] = dst
cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
这里发生了很多事情,出现了一些新的东西。 我们首先看到的是一个新的阈值:ret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)。
我们将在下一个教程中介绍更多的阈值,所以请继续关注具体内容,但基本上它的工作方式是根据阈值将所有像素转换为黑色或白色。 在我们的例子中,阈值是 220,但是我们可以使用其他值,或者甚至动态地选择一个,这是ret变量可以使用的值。 接下来,我们看到:mask_inv = cv2.bitwise_not(mask)。 这是一个按位操作。 基本上,这些操作符与 Python 中的典型操作符非常相似,除了一点,但我们不会在这里触及它。 在这种情况下,不可见的部分是黑色的地方。 然后,我们可以说,我们想在第一个图像中将这个区域遮住,然后将空白区域替换为图像 2 的内容。
下个教程中,我们深入讨论阈值。
六、阈值
欢迎阅读另一个 OpenCV 教程。在本教程中,我们将介绍图像和视频分析的阈值。阈值的思想是进一步简化视觉数据的分析。首先,你可以转换为灰度,但是你必须考虑灰度仍然有至少 255 个值。阈值可以做的事情,在最基本的层面上,是基于阈值将所有东西都转换成白色或黑色。比方说,我们希望阈值为 125(最大为 255),那么 125 以下的所有内容都将被转换为 0 或黑色,而高于 125 的所有内容都将被转换为 255 或白色。如果你像平常一样转换成灰度,你会变成白色和黑色。如果你不转换灰度,你会得到二值化的图片,但会有颜色。
虽然这听起来不错,但通常不是。我们将在这里介绍多个示例和不同类型的阈值来说明这一点。我们将使用下面的图片作为我们的示例图片,但可以随意使用你自己的图片:
这个书的图片就是个很好的例子,说明为什么一个人可能需要阈值。 首先,背景根本没有白色,一切都是暗淡的,而且一切都是变化的。 有些部分很容易阅读,另一部分则非常暗,需要相当多的注意力才能识别出来。 首先,我们尝试一个简单的阈值:
retval, threshold = cv2.threshold(img, 10, 255, cv2.THRESH_BINARY)
二元阈值是个简单的“是或不是”的阈值,其中像素为 255 或 0。在很多情况下,这是白色或黑色,但我们已经为我们的图像保留了颜色,所以它仍然是彩色的。 这里的第一个参数是图像。 下一个参数是阈值,我们选择 10。下一个是最大值,我们选择为 255。最后是阈值类型,我们选择了THRESH_BINARY。 通常情况下,10 的阈值会有点差。 我们选择 10,因为这是低光照的图片,所以我们选择低的数字。 通常 125-150 左右的东西可能效果最好。
import cv2
import numpy as np
img = cv2.imread('bookpage.jpg')
retval, threshold = cv2.threshold(img, 12, 255, cv2.THRESH_BINARY)
cv2.imshow('original',img)
cv2.imshow('threshold',threshold)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
现在的图片稍微更便于阅读了,但还是有点乱。 从视觉上来说,这样比较好),但是仍然难以使用程序来分析它。 让我们看看我们是否可以进一步简化。
首先,让我们灰度化图像,然后使用一个阈值:
import cv2
import numpy as np
img = cv2.imread('sources/4.jpg')
grayscaled = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
retval, threshold = cv2.threshold(grayscaled, 10, 255, cv2.THRESH_BINARY)
cv2.imshow('original',img)
cv2.imshow('threshold',threshold)
cv2.waitKey(0)
cv2.destroyAllWindows()
更简单,但是我们仍然在这里忽略了很多背景。 接下来,我们可以尝试自适应阈值,这将尝试改变阈值,并希望弄清楚弯曲的页面。
import cv2
import numpy as np
img = cv2.imread('sources/4.jpg')
grayscaled = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
th = cv2.adaptiveThreshold(grayscaled, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)
cv2.imshow('original',img)
cv2.imshow('Adaptive threshold',th)
cv2.waitKey(0)
cv2.destroyAllWindows()
还有另一个版本的阈值,可以使用,叫做大津阈值。 它在这里并不能很好发挥作用
retval2,threshold2 = cv2.threshold(grayscaled,125,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)cv2.imshow(‘original’,img)
cv2.imshow(‘Otsu threshold’,threshold2)
cv2.waitKey(0)
cv2.destroyAllWindows()
七、颜色过滤
在这个 Python OpenCV 教程中,我们将介绍如何创建一个过滤器,回顾按位操作,其中我们将过滤特定的颜色,试图显示它。或者,你也可以专门筛选出特定的颜色,然后将其替换为场景,就像我们用其他方法替换ROI(图像区域)一样,就像绿屏的工作方式。
为了像这样过滤,你有几个选项。通常,你可能会将你的颜色转换为 HSV,即“色调饱和度纯度”。例如,这可以帮助你根据色调和饱和度范围,使用变化的值确定一个更具体的颜色。如果你希望的话,你可以实际生成基于 BGR 值的过滤器,但是这会有点困难。如果你很难可视化 HSV,不要感到失落,查看维基百科页面上的 HSV,那里有一个非常有用的图形让你可视化它。我最好亲自描述颜色的色调饱和度和纯度。现在让我们开始:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([78,43,46])
upper_red = np.array([99,255,255])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
if cv2.waitKey(5) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
cap.release()
这只是一个例子,以红色为目标。 它的工作方式是,我们所看到的是我们范围内的任何东西,基本上是 30-255,150-255 和 50-180。 它用于红色,但可以随便尝试找到自己的颜色。 HSV 在这里效果最好的原因是,我们想要范围内的颜色,这里我们通常需要相似的颜色。 很多时候,典型的红色仍然会有一些绿色和蓝色分量,所以我们必须允许一些绿色和蓝色,但是我们会想要几乎全红。 这意味着我们会在这里获得所有颜色的低光混合。
为了确定 HSV 的范围,我认为最好的方法就是试错。 OpenCV 内置了将 BGR 转换为 HSV 的方法。 如果你想挑选单一的颜色,那么 BGR 到 HSV 将会很好用。 为了教学,下面是这个代码的一个例子:
dark_red = np.uint8([[[12,22,121]]])
dark_red = cv2.cvtColor(dark_red,cv2.COLOR_BGR2HSV)
这里的结果是一个 HSV 值,与dark_red值相同。这很棒…但是,同样…你遇到了颜色范围和 HSV 范围的基本问题。他们根本不同。你可能合理使用 BGR 范围,它们仍然可以工作,但是对于检测一种“颜色”,则无法正常工作。
回到主代码,然而,我们首先要把帧转换成 HSV。那里没什么特别的。接下来,我们为红色指定一些 HSV 值。我们使用inRange函数,为我们的特定范围创建掩码。这是真或假,黑色或白色。接下来,我们通过执行按位操作来“恢复”我们的红色。基本上,我们显示了frame and mask。掩码的白色部分是红色范围,被转换为纯白色,而其他一切都变成黑色。最后我们展示所有东西。我选择了显示原始真,掩码和最终结果,以便更好地了解发生的事情。
在下一个教程中,我们将对这个主题做一些介绍。你可能看到了,我们在这里还是有一些“噪音”。东西有颗粒感,红色中的黑点很多,还有许多其他的小色点。我们可以做一些事情,试图通过模糊和平滑来缓解这个问题,接下来我们将讨论这个问题。
八、模糊和平滑
在这个 Python OpenCV 教程中,我们将介绍如何尝试从我们的过滤器中消除噪声,例如简单的阈值,或者甚至我们以前的特定的颜色过滤器:
正如你所看到的,我们有很多黑点,其中我们喜欢红色,还有很多其他的色点散落在其中。 我们可以使用各种模糊和平滑技术来尝试弥补这一点。 我们可以从一些熟悉的代码开始:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([30,150,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(frame,frame, mask= mask)
现在,让我们应用一个简单的平滑,我们计算每个像素块的均值。 在我们的例子中,我们使用15x15正方形,这意味着我们有 225 个总像素。
kernel = np.ones((15,15),np.float32)/225
smoothed = cv2.filter2D(res,-1,kernel)
cv2.imshow('Original',frame)
cv2.imshow('Averaging',smoothed)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
这个很简单,但是结果牺牲了很多粒度。 接下来,让我们尝试一些高斯模糊:
blur = cv2.GaussianBlur(res,(15,15),0)
cv2.imshow('Gaussian Blurring',blur)
median = cv2.medianBlur(res,15)
cv2.imshow('Median Blur',median)
最后一个选项是双向模糊:
bilateral = cv2.bilateralFilter(res,15,75,75) cv2.imshow(‘bilateral Blur’,bilateral)
所有模糊的对比:
至少在这种情况下,我可能会使用中值模糊,但是不同的照明,不同的阈值/过滤器,以及其他不同的目标和目标可能会决定你使用其中一个。
在下一个教程中,我们将讨论形态变换。
九、形态变换
在这个 Python OpenCV 教程中,我们将介绍形态变换。 这些是一些简单操作,我们可以基于图像形状执行。
我们要谈的第一对是腐蚀和膨胀。 腐蚀是我们将“腐蚀”边缘。 它的工作方式是使用滑块(核)。 我们让滑块滑动,如果所有的像素是白色的,那么我们得到白色,否则是黑色。 这可能有助于消除一些白色噪音。 另一个版本是膨胀,它基本上是相反的:让滑块滑动,如果整个区域不是黑色的,就会转换成白色。 这是一个例子:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
res, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([30,150,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(frame,frame, mask= mask)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(mask,kernel,iterations = 1) dilation = cv2.dilate(mask,kernel,iterations = 1)
cv2.imshow('Original',frame)
cv2.imshow('Mask',mask)
cv2.imshow('Erosion',erosion)
cv2.imshow('Dilation',dilation)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
结果:
下一对是“开放”和“关闭”。 开放的目标是消除“假阳性”。 有时在背景中,你会得到一些像素“噪音”。 “关闭”的想法是消除假阴性。 基本上就是你检测了你的形状,例如我们的帽子,但物体仍然有一些黑色像素。 关闭将尝试清除它们。
cap = cv2.VideoCapture(1)
while(1):
res, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([30,150,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(frame,frame, mask= mask)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) cv2.imshow('Original',frame)
cv2.imshow('Mask',mask)
cv2.imshow('Opening',opening)
cv2.imshow('Closing',closing)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
另外两个选项是tophat和blackhat,对我们的案例并不有用:
# It is the difference between input image and Opening of the image
cv2.imshow('Tophat',tophat)
# It is the difference between the closing of the input image and input image.
cv2.imshow('Blackhat',blackhat)
在下一个教程中,我们将讨论图像渐变和边缘检测。
十、边缘检测和渐变
欢迎阅读另一个 Python OpenCV 教程。 在本教程中,我们将介绍图像渐变和边缘检测。 图像渐变可以用来测量方向的强度,边缘检测就像它所说的:它找到了边缘! 我敢打赌你肯定没看到。
首先,我们来展示一些渐变的例子:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([30,150,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(frame,frame, mask= mask)
laplacian = cv2.Laplacian(frame,cv2.CV_64F)
sobelx = cv2.Sobel(frame,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(frame,cv2.CV_64F,0,1,ksize=5)
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
cv2.imshow('laplacian',laplacian)
cv2.imshow('sobelx',sobelx)
cv2.imshow('sobely',sobely)
if cv2.waitKey(5) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
cap.release()
如果你想知道什么是cv2.CV_64F,那就是数据类型。 ksize是核大小。 我们使用 5,所以每次查询5×5的渔区。
虽然我们可以使用这些渐变转换为纯边缘,但我们也可以使用 Canny 边缘检测!
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while True:
_, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([30,150,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('Original',frame)
edges = cv2.Canny(frame,100,200)
cv2.imshow('Edges',edges)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
cap.release()
这真是太棒了! 但是,这并不完美。 注意阴影导致了边缘被检测到。 其中最明显的是蓝狗窝发出的阴影。
在下一个 OpenCV 教程中,我们将讨论如何在其他图像中搜索和查找相同的图像模板。