简略物体追寻和几许转化

一、更改色彩空间

有时候,咱们需求对图画的色彩空间进行转化,比如说在图画进行阈值处理、边际检测时,三个通道的图画难以进行梯度检测,所以咱们进行色域转化:BGR <-> gray, BGR <-> HSV

别的,接下来咱们将会测验将一个视频中的有色物体提取出来。

下面咱们将会学习两个函数:cv.cvtColor()转化色彩空间,cv.inRange()等

1. 改变图画色域

OpenCV里面包含了150多种色域转化的办法,可是咱们只需关注两种:BGR <-> gray, BGR <-> HSV,色域转化函数如下:

  • cv.cvtColor(input_image, flag) ,其间flag决议了转化类型,有如下取值:
    1. cv.COLOR_BGR2GRAY,完成BGR -> gray 转化
    2. 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图画中,咱们更易于表示一种色彩。接下来的运用中,咱们将运用以下进程来提取有色物体:

  1. 获取到视频的每一帧
  2. 将帧图画的色域从BGR转化到HSV
  3. 将HSV图画阈值处理为蓝色规模
  4. 单独提取出蓝色,便于咱们之后处理
  • cv.inRange的用法: cv.inRange( src, lowerb, upperb[, dst] ) -> dst,得到一副二值图画
  • OpenCV中HSV的BGR视点规模:
    1. 赤色:0
    2. 绿色:60
    3. 蓝色:120
    4. 黄色:30
    5. 青色:90
    6. 紫色: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()

OpenCV Tutorials 03 - 简单物体追踪和几何转换

  • 留意: 能够看见图画中存在一些噪声,稍后咱们会讨论解决办法,这是图画追寻的最最简略的一种办法,若是学写了轮廓函数,咱们就能做许多事情,比如找到物体的质心,然后用它来盯梢物体,只是经过在摄像机前移动你的手绘制图表,还有其他风趣的事情。

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)

OpenCV Tutorials 03 - 简单物体追踪和几何转换

# 进行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函数完成此功用。图画巨细能手动设置也能够传入缩放因子。依据传入缩放因子的不同,完成的功用也不同:
  1. cv.INTER_AREA:缩小
  2. 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)

OpenCV Tutorials 03 - 简单物体追踪和几何转换

  • 留意:cv.warpAffine ()函数的第三个参数是输出图画的巨细,它应该是 (width,height) 的形式。记住 width = 列数,height = 行数。

3. 图画旋转

旋转视点为\theta的图画旋转是透过改换矩阵来到达的:M=[cos⁡−sin⁡sin⁡cos⁡]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)

OpenCV Tutorials 03 - 简单物体追踪和几何转换

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()

OpenCV Tutorials 03 - 简单物体追踪和几何转换

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()

OpenCV Tutorials 03 - 简单物体追踪和几何转换