一.前言

今天事情有点多,写的会少一点,感谢观看

二.主要内容

一.图像处理

1改变颜色空间
1.改变颜色空间

  在 OpenCV 中有超过 150 种颜色空间转换的方法。但我们仅需要研究两个最常使用的方法,他们是 BGR 到 Gray,BGR 到 HSV。我们使用 cv.cvtColor(input_image, flag)函数进行颜色转换,其中 flag 决定了转换的类型。对于 BGR 到 Gray 转换我们令 flag 为 cv.COLOR_BGR2GRAY。 同样,对于 BGR 到 HSV, 我们令 flag 为 cv.COLOR_BGR2HSV。如想得到其他 flag 值,只需要在 Python 终端中输入如下命令:

注意 对于 HSV, 色调(Hue)范围为 [0,179], 饱和度(Saturation)范围为 [0,255] ,明亮度(Value)为 [0,255]. 不同的软件使用不同的比例. 所以如果你想用 OpenCV 的值与别的软件的值作对比,你需要归一化这些范围。(说实话,看不懂直接跳过,因为我也能看不懂)

2.目标追踪

现在我们知道了如何将 BGR 图片转化为 HSV 图片,我们可以使用它去提取彩色对象。HSV 比 BGR 在颜色空间上更容易表示颜色。在我们的应用中,我们会尝试提取一个蓝色的彩色对象,方法为:

  • 提取每一视频帧。
  • 将 BGR 转化为 HSV 颜色空间。
  • 我们用蓝色像素的范围对该 HSV 图片做阈值。
  • 现在提取出了蓝色对象,我们可以随意处理图片了 。

下面是代码:

import cv2 as cv
import numpy as np

# 初始化摄像头
cap = cv.VideoCapture(0)

while True:
    # 读取视频帧
    ret, frame = cap.read()
    
    # 将BGR颜色空间转换为HSV颜色空间
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    
    # 定义蓝色的HSV范围
    lower_blue = np.array([110, 50, 50])
    upper_blue = np.array([130, 255, 255])
    
    # 创建蓝色区域的掩膜
    mask = cv.inRange(hsv, lower_blue, upper_blue)
    
    # 将掩膜应用于原始图像
    res = cv.bitwise_and(frame, frame, mask=mask)
    
    # 显示原始画面、掩膜和结果
    cv.imshow('Original', frame)
    cv.imshow('Blue Mask', mask)
    cv.imshow('Blue Detection', res)
    
    # 按ESC键退出
    if cv.waitKey(5) & 0xFF == 27:
        break

# 释放资源
cap.release()
cv.destroyAllWindows()
 

注意 在图片中有一些噪声,在之后的章节中我们会学习如何消除。 这是目标追踪最简单的例子。当你学会了轮廓函数,你就可以做的更多,例如找到对象的质心并且使用它来追踪对象,只需在相机前面移动你的手,手指或者掌心的轨迹就可以绘制图形,还有许多其他有趣的东西。

3.如何找到 HSV 值去追踪?

  这在 stackoverflow.com 中是经常见到的问题。 这个问题非常简单,你可以使用相同的函数:cv.cvtColor()。 不需要输入图片,你只需要输入你需要的 BGR 值即可. 例如, 为了找到绿色的 HSV 值, 可以在 Python 终端中输入以下代码:

import numpy as np
import cv2 as cv

green = np.uint8([[[0, 255, 0]]])
hsv_green = cv.cvtColor(green, cv.COLOR_BGR2HSV)
print(hsv_green)
 
2.图像的几何变换
1.变换

OpenCV 提供了两个转换函数,cv.warpAffine 和 cv.warpPerspective,可以进行各种转换。 cv.warpAffine 采用 2x3 变换矩阵,而 cv.warpPerspective 采用 3x3 变换矩阵作为输入。

常见变换

  • cv.INTER_NEAREST - 最近邻插值(最快)

  • cv.INTER_LINEAR - 双线性插值(默认)

  • cv.INTER_CUBIC - 双三次插值(质量较好)

  • cv.INTER_AREA - 区域插值(适合缩小图像)

  • cv.INTER_LANCZOS4 - Lanczos插值(质量最好)

  • 默认情况下,所使用的插值方法都是 cv.INTER_AREA 。

代码如下

import numpy as np
import cv2 as cv

# 读取图像文件
img = cv.imread('test.jpg')
if img is None:
    print("无法读取图像")
    exit()

# 执行2倍放大操作
enlarged_img = cv.resize(img, None, fx=2, fy=2, interpolation=cv.INTER_CUBIC)

# 执行0.5倍缩小操作
shrunk_img = cv.resize(img, None, fx=0.5, fy=0.5, interpolation=cv.INTER_AREA)

# 显示处理前后的图像对比
cv.imshow('Original', img)
cv.imshow('Resized 2x', enlarged_img)
cv.imshow('Resized 0.5x', shrunk_img)
cv.waitKey(0)
cv.destroyAllWindows()
 
2平移变换

平移变换是物体位置的移动。如果知道 (x,y) 方向的偏移量,假设为 (t_x,t_y),则可以创建如下转换矩阵 M

可以将变换矩阵存为 np.float32 类型的 numpy 数组,并将其作为 cv.warpAffine 的第二个参数。请参见以下转换(100,50)的示例:

import numpy as np
import cv2 as cv

# 读取图像(灰度模式)
img = cv.imread('test.jpg', 0)  # 参数0表示以灰度模式读取

# 获取图像尺寸
rows, cols = img.shape

# 定义平移变换矩阵
# M = [[1, 0, tx],
#      [0, 1, ty]]
M = np.float32([[1, 0, 100], [0, 1, 50]])

# 应用仿射变换
dst = cv.warpAffine(img, M, (cols, rows))

# 显示结果
cv.imshow('img', dst)
cv.waitKey(0)
cv.destroyAllWindows()
 
  1. warpAffine函数参数

    • img:输入图像

    • M:2×3变换矩阵

    • (cols, rows):输出图像尺寸

cv.warpAffine 函数的第三个参数是输出图像的大小,其形式应为(宽度、高度)。记住宽度=列数,高度=行数。

3旋转

Opencv 提供了可变旋转中心的比例变换,所以你可以在任意位置旋转图片,修改后的转换矩阵为:

为了找到这个转换矩阵,opencv 提供了一个函数, cv.getRotationMatrix2D 。请查看下面的示例,它将图像相对于中心旋转 90 度,而不进行任何缩放。

import cv2 as cv

# 读取灰度图像
img = cv.imread('test.jpg', 0)

# 获取图像尺寸
height, width = img.shape

# 计算旋转中心(图像中心点)
center = (width // 2, height // 2)

# 生成旋转矩阵(90度顺时针,缩放比例1.0)
rotation_matrix = cv.getRotationMatrix2D(center, 90, 1.0)

# 执行仿射变换,保持原始图像尺寸
rotated_img = cv.warpAffine(img, rotation_matrix, (width, height))

# 显示结果(可选)
cv.imshow('Rotated Image', rotated_img)
cv.waitKey(0)
cv.destroyAllWindows()
 
4仿射变换

  在仿射变换中,原始图像中的所有平行线在输出图像中仍然是平行的。为了找到变换矩阵,我们需要从输入图像中取三个点及其在输出图像中的对应位置。然后 cv.getAffineTransform 将创建一个 2x3 矩阵,该矩阵将传递给 cv.warpAffine 。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt

# 读取图像
img = cv.imread('test.jpg')
# 转换为RGB格式以便Matplotlib显示
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)

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_rgb, M, (cols, rows))

# 显示原始图像和变换结果
plt.subplot(121), plt.imshow(img_rgb), plt.title('Input')
plt.subplot(122), plt.imshow(dst), plt.title('Output')
plt.show()
 
5透视变换

  对透视转换,你需要一个 3x3 变换矩阵。即使在转换之后,直线也将保持直线。要找到这个变换矩阵,需要输入图像上的 4 个点和输出图像上的相应点。在这四点中,任意三点不应该共线。然后通过 cv.getPerspectiveTransform 找到变换矩阵。然后对这个 3x3 变换矩阵使用 cv.warpPerspective

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

img = cv.imread('test.jpg')

if img is None:
    img = np.ones((300, 400, 3), dtype=np.uint8) * 255
    cv.putText(img, 'Test Image', (100, 150), cv.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)

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

img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
dst_rgb = cv.cvtColor(dst, cv.COLOR_BGR2RGB)

plt.subplot(121), plt.imshow(img_rgb), plt.title('Input')
plt.subplot(122), plt.imshow(dst_rgb), plt.title('Output')
plt.show()
 

这些代码在vscode+conda中可以顺利跑出,我没有附上运行截图是为了想让大家都动手试一下,那怕是ctrl+cv,自己看一下总是好的

三最后一语

今天时间不多就写这么多,但是内容很多希望大家和我一起今天吸收掉

昨日种种,譬如昨日之死;今日种种,譬如今日生。感谢观看!!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐