简略物体追寻和几许转化
一、更改色彩空间
有时候,咱们需求对图画的色彩空间进行转化,比如说在图画进行阈值处理、边际检测时,三个通道的图画难以进行梯度检测,所以咱们进行色域转化:BGR <-> gray, BGR <-> HSV
别的,接下来咱们将会测验将一个视频中的有色物体提取出来。
下面咱们将会学习两个函数:cv.cvtColor()转化色彩空间,cv.inRange()等
1. 改变图画色域
OpenCV里面包含了150多种色域转化的办法,可是咱们只需关注两种:BGR <-> gray, BGR <-> HSV,色域转化函数如下:
- cv.cvtColor(input_image, flag) ,其间flag决议了转化类型,有如下取值:
- cv.COLOR_BGR2GRAY,完成BGR -> gray 转化
- cv.COLOR_BGR2HSV,完成BGR -> HSV 转化
import cv2 as cv
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
def cv_show(name, img):
cv.imshow(name, img)
cv.waitKey(0)
cv.destroyAllWindows()
def compare(imgs):
# for i in range(len(imgs)):
# imgs[i][:,-3:-1,:] = [255,255,255]
res = np.hstack(imgs)
cv_show('Compare', res)
# 打印检查flag的取值
flags = [i for i in dir(cv) if i.startswith('COLOR_')]
flags
['COLOR_BAYER_BG2BGR', 'COLOR_BAYER_BG2BGRA', 'COLOR_BAYER_BG2BGR_EA', 'COLOR_BAYER_BG2BGR_VNG', 'COLOR_BAYER_BG2GRAY', ... 'COLOR_YUV420sp2GRAY', 'COLOR_YUV420sp2RGB', 'COLOR_YUV420sp2RGBA', 'COLOR_mRGBA2RGBA']
- 留意:对于 HSV,色相规模是[0,179] ,饱和度规模是[0,255] ,值规模是[0,255]。不同的软件运用不同的尺度。因此,如果在OpenCV中运用HSV ,则需规范化这些取值规模
2. 物体盯梢
在了解到BGR图画转化为HSV图画的办法之后,咱们能够运用它来提取有色目标。相比较BGR图画爱,在HSV图画中,咱们更易于表示一种色彩。接下来的运用中,咱们将运用以下进程来提取有色物体:
- 获取到视频的每一帧
- 将帧图画的色域从BGR转化到HSV
- 将HSV图画阈值处理为蓝色规模
- 单独提取出蓝色,便于咱们之后处理
- cv.inRange的用法: cv.inRange( src, lowerb, upperb[, dst] ) -> dst,得到一副二值图画
- OpenCV中HSV的BGR视点规模:
- 赤色:0
- 绿色:60
- 蓝色:120
- 黄色:30
- 青色:90
- 紫色:150
cap = cv.VideoCapture(0)
if not cap.isOpened():
print('翻开文件失利!')
exit()
while(1):
# 逐帧提取
_, frame = cap.read()
# 转化色域
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
# 设定蓝色色域的上下限,参数分别为:色彩视点、饱和度、明度
lower_blue = np.array([0,50,50])
upper_blue = np.array([20,255,255])
# 在对应色彩规模就置为255,不在的话就归0
mask = cv.inRange(hsv, lower_blue, upper_blue)
# 滤出对应的色彩规模图画
res = cv.bitwise_and(frame,frame, mask= mask)
cv.imshow('frame',frame)
cv.imshow('mask',mask)
cv.imshow('res',res)
k = cv.waitKey(1) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
- 留意: 能够看见图画中存在一些噪声,稍后咱们会讨论解决办法,这是图画追寻的最最简略的一种办法,若是学写了轮廓函数,咱们就能做许多事情,比如找到物体的质心,然后用它来盯梢物体,只是经过在摄像机前移动你的手绘制图表,还有其他风趣的事情。
3. 怎样了解咱们需求盯梢的HSV值?
咱们能够在网站:www.stackoverflow.com/ 寻求相关答案。别的,咱们也能够运用 cv.cvtColor()函数来进行BGR到HSV的转化。不需求传入图画,只需求传入对应的BGR值便可。
# 检查Green的HSV值
# 现将BGR格式的纯绿色界说出来
green_BGR = np.uint8([[[0, 255, 0]]])
green_BGR.shape
(1, 1, 3)
一行一列三通道,界说多行多列能够直接运用np.zeros
red_BGR = np.zeros((255, 400, 3))
red_BGR[...,2] = 255
cv_show('Red', red_BGR)
# 进行BGR2HSV转化
green_HSV = cv.cvtColor(green_BGR, cv.COLOR_BGR2HSV)
green_HSV
array([[[ 60, 255, 255]]], dtype=uint8)
现在你把[ H-10,100,100] 和 [ H + 10,255,255]分别作为下界和上界。除了这个办法,你能够运用任何图画编辑工具,如 GIMP 或任何在线转化器来找到这些值,但不要忘记调整 HSV 规模(主要是第一个视点的规模,要除二)。
4. 练习
测验提取出多种色彩的物体,如蓝色、绿色一起提取
cap = cv.VideoCapture('Tg.mp4')
if not cap.isOpened():
print('翻开文件失利!')
exit()
while(1):
# 逐帧提取
_, frame = cap.read()
# 转化色域
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
# 设定黄色色域的上下限,参数分别为:色彩视点、饱和度、明度
lower_yellow = np.array([20,100,100])
upper_yellow = np.array([40,255,255])
# 设定赤色色域的上下限,参数分别为:色彩视点、饱和度、明度
lower_red = np.array([0,100,100])
upper_red = np.array([20,255,255])
# 在对应色彩规模就置为255,不在的话就归0
mask_yellow = cv.inRange(hsv, lower_yellow, upper_yellow)
mask_red = cv.inRange(hsv, lower_red, upper_red)
# 要完成多种色彩提取,则需求将多种色彩的mask进行位运算的或操作,将成果再和原图画相与
mask = cv.bitwise_or(mask_yellow,mask_red)
# 滤出对应的色彩规模图画
res = cv.bitwise_and(frame,frame, mask= mask)
cv.imshow('frame',frame)
cv.imshow('mask',mask)
cv.imshow('res',res)
k = cv.waitKey(1) & 0xFF
if k == 27:
break
cv.destroyAllWindows()
二、图画几许改换
本节主要包括运用不同的几许改换图画,如平移,旋转,仿射改换等。主要用到的函数有: cv.getPerspectiveTransform()
1. 重塑图画巨细
OpenCV内置了两个转化函数: cv.warpAffine 和 cv.warpPerspective,能够协助咱们进行各类转化。前者的转化矩阵为 2 * 3,而后者转化矩阵尺度为 3 * 3
- 图画缩放:图画缩放就是重新设置图画的巨细。OpenCV供给了cv.resize函数完成此功用。图画巨细能手动设置也能够传入缩放因子。依据传入缩放因子的不同,完成的功用也不同:
- cv.INTER_AREA:缩小
- cv.INTER_CUBIC(缓慢) 和 cv.INTER_LINEAR:扩大
一般说来,cv.INTER_LINEAR办法适用于所有的重塑图画巨细情况。
img = cv.imread('lena.png')
# 第二个参数是指定图画巨细,传入None或(0,0)则标明要按份额缩放
# 后面要传入fx, fy
res = cv.resize(img, None, fx = 2, fy = 2, interpolation = cv.INTER_CUBIC )
cv_show('T',res)
# 下面功用和上面一致
height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)
2. 图画平移
平移就是图画方位的转化,若你明确了(x, y)方向的偏移,而且让他转化到(tx,ty)(t_x, t_y),那么你就能够构造出一个改换矩阵M ,M=[10tx01ty] M =\begin{bmatrix} 1 & 0 & t_x\\ 0 & 1 & t_y \end{bmatrix}。
咱们能够将这个矩阵运用Numpy的数组类型(其间的数据类型要坚持为 np.float32)存储,便于之后的矩阵运算或传递给 cv.warpAffine ()函数
img = cv.imread('lena.png',0)
rows,cols = img.shape
M = np.float32([[1,0,100],[0,1,50]])
dst = cv.warpAffine(img,M,(cols,rows))
cv_show('result', dst)
- 留意:cv.warpAffine ()函数的第三个参数是输出图画的巨细,它应该是 (width,height) 的形式。记住 width = 列数,height = 行数。
3. 图画旋转
旋转视点为\theta的图画旋转是透过改换矩阵来到达的:M=[cos−sinsincos]M=\left[\begin{array}{cc} \cos \theta & -\sin \theta \\ \sin \theta & \cos \theta \end{array}\right],这种办法未指定旋转中心。
可是 OpenCV 供给了可调理旋转中心的缩放旋转,这样便能够以任何方位为中心旋转。修改后的改换矩阵为:[(1−)⋅center.x−⋅center.y−⋅center.x+(1−)⋅center.y]\left[\begin{array}{ccc} \alpha & \beta & (1-\alpha) \cdot \text { center. } x-\beta \cdot \text { center. } y \\ -\beta & \alpha & \beta \cdot \text { center. } x+(1-\alpha) \cdot \text { center. } y \end{array}\right],
其间 center.x, center.y代表了旋转中心的坐标,而=scale⋅cos=scale⋅sin\begin{aligned} \alpha &=\text { scale } \cdot \cos \theta \\ \beta &=\text { scale } \cdot \sin \theta \end{aligned},scale是缩放份额
上面仅是数学推理进程,OpenCV供给了cv.getRotationMatrix2D 函数来协助咱们找到上面的改换矩阵。
img = cv.imread('lena.png',-1)
rows,cols = img.shape[:2]
# (cols-1)/2.0,(rows-1)/2.0)为图画中心坐标,第二个参数为旋转视点theta(逆时针),第三个参数为缩放份额
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),180,2)
dst = cv.warpAffine(img,M,(cols,rows))
cv_show('result', dst)
4. 仿射改换
在仿射改换中,原始图画中的所有平行线在输出图画中仍然是平行的。为了找到改换矩阵,咱们需求从输入图画中找到3个点,并在输出图画中找到它们的对应方位。然后,cv.getafinetransform 将创建一个2×3矩阵,该矩阵将传递给 cv.warpAffine进行仿射改换。
img = cv.imread('lena.png',-1)
rows,cols,ch = img.shape
# 找到原图点
pts1 = np.float32([[50,50],[200,50],[50,200]])
# 规定原图改换后所在点
pts2 = np.float32([[10,100],[200,50],[100,250]])
# 解出仿射改换矩阵
M = cv.getAffineTransform(pts1,pts2)
# 改换
dst = cv.warpAffine(img,M,(cols,rows))
plt.subplot(121),plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)),plt.title('Input')
plt.subplot(122),plt.imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB)),plt.title('Output')
plt.show()
5. 透视改换
对于透视转化,你需求一个3 3的改换矩阵。直线即便在改换之后也会坚持直线。为了找到这个改换矩阵,你需求在输入图画和输出图画上对应的4个点。在这4点中,有3点不该该是共线的。然后能够经过函数 cv.getPerspectiveTransform 找到改换矩阵。然后运用 cv.warpPerspective 填入这个3×3改换矩阵。
rows,cols,ch = img.shape
# 找到四个透视点
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
# 解出透视改换矩阵
M = cv.getPerspectiveTransform(pts1,pts2)
# 运用透视改换矩阵得到成果
dst = cv.warpPerspective(img,M,(300,300))
plt.subplot(121),plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)),plt.title('Input')
plt.subplot(122),plt.imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB)),plt.title('Output')
plt.show()