(02)python-opencv图像处理——更改颜色空间HSV

前言

1、更改颜色空间

1.1BGR 到 Gray 的示例

1.2 BGR 到 HSV 的示例: 

​编辑 1.3 通过HSV进行颜色追踪 

1.3.1hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

1.3.2 BGR vs HSV:

1.3.3 为什么使用 HSV 颜色空间?

1.3.4 cv.inRange(hsv, lower_red1, upper_red1)

1.3.5 cv.bitwise_and(frame, frame, mask=mask)

参数解释:

返回值:

 1.4 通过HSV进行颜色追踪-框选出目标区域

1.4.1 cv.morphologyEx(mask, cv.MORPH_OPEN, np.ones((3, 3), np.uint8))函数

1.4.2 cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)函数

1.4.3 cv.contourArea(contour)函数

1.5 通过HSV进行颜色追踪-围绕边缘实现框选

参考文献

前言

主要案例是实现对颜色的追踪操作,这是一个案例可以直接复制代码进行展示

1、更改颜色空间

在本教程中:

  • 你会学到如何将图片从一个颜色空间转换到另一个,例如 BGR 到 Gray,BGR 到 HSV 等。
  • 另外,我们会创建一个从视频中提取彩色对象的应用。
  • 你会学到如下函数:cv.cvtColor()cv.inRange()

1.1BGR 到 Gray 的示例

BGR 是 OpenCV 中的默认颜色空间,它的顺序是蓝-绿-红,而不是红-绿-蓝。将 BGR 图像转换为灰度图像,可以通过以下代码实现:

import cv2 as cv
# 读取图片
image = cv.imread('images/demo2.png')
# 将 BGR 图片转换为灰度图像
gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# 显示原图和灰度图
cv.imshow('Original Image', image)
cv.imshow('Gray Image', gray_image)

cv.waitKey(0)
cv.destroyAllWindows()

1.2 BGR 到 HSV 的示例: 

HSV 是色相 (Hue),饱和度 (Saturation) 和亮度 (Value) 的颜色空间。它在许多应用中,例如颜色分割时非常有用。

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

import cv2 as cv
# 读取图片
image = cv.imread('images/demo2.png')
# 将 BGR 图片转换为 HSV 图像
hsv_image = cv.cvtColor(image, cv.COLOR_BGR2HSV)
# 显示原图和 HSV 图像
cv.imshow('Original Image', image)
cv.imshow('HSV Image', hsv_image)

cv.waitKey(0)
cv.destroyAllWindows()

 1.3 通过HSV进行颜色追踪 

现在我们知道了如何将 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()
    if not ret:
        print("无法从摄像头获取帧")
        break
    # 将 BGR 帧转换为 HSV 颜色空间
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    # 定义红色的 HSV 范围(红色有两个范围)
    lower_red1 = np.array([0, 120, 70])    # 红色的低端色调范围
    upper_red1 = np.array([10, 255, 255])
    lower_red2 = np.array([170, 120, 70])  # 红色的高端色调范围
    upper_red2 = np.array([180, 255, 255])
    # 创建两个掩膜
    mask1 = cv.inRange(hsv, lower_red1, upper_red1)  # 对应第一个红色范围
    mask2 = cv.inRange(hsv, lower_red2, upper_red2)  # 对应第二个红色范围
    # 将两个掩膜合并,覆盖所有红色区域
    mask = mask1 + mask2
    # 使用位操作将掩膜应用到原图像,提取红色对象
    result = cv.bitwise_and(frame, frame, mask=mask)
    # 显示原始帧和提取的红色对象
    cv.imshow('Original Frame', frame)
    cv.imshow('Red Object Extraction', result)
    # 按下 'q' 键退出
    if cv.waitKey(1) & 0xFF == ord('q'):
        break
# 释放摄像头并关闭所有窗口
cap.release()
cv.destroyAllWindows()

如果mask = mask2的时候效果更好哈

1.3.1hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

cv.cvtColor() 是 OpenCV 中用于转换图像颜色空间的函数。在你的例子中,hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) 将图像从 BGR 颜色空间转换为 HSV 颜色空间。这个操作在图像处理任务(如颜色对象提取)中非常常见,因为 HSV 颜色空间在颜色检测方面比 BGR 更直观和方便。

参数解释:

  1. frame:这是输入图像,通常是 BGR 格式的彩色图像(BGR 是 OpenCV 默认的颜色格式)。

  2. cv.COLOR_BGR2HSV:这是颜色空间转换的标志,表示将输入图像从 BGR 颜色空间转换为 HSV 颜色空间。OpenCV 中预定义了多种颜色空间转换的标志,BGR2HSV 是其中之一。

返回值:

  • hsv:输出图像,这是输入图像在 HSV 颜色空间下的表现形式。

1.3.2 BGR vs HSV:

  • BGR (蓝-绿-红) 是 OpenCV 使用的默认颜色空间,它表示的是三个颜色通道的强度值。

    • 例如,BGR(255, 0, 0) 代表蓝色,BGR(0, 255, 0) 代表绿色,BGR(0, 0, 255) 代表红色。

  • HSV (色调-饱和度-亮度) 是另一种表示颜色的方法,它将颜色信息分为三个独立的属性:

    1. H (Hue,色调):表示颜色的种类,范围为 [0, 179],例如 0 表示红色,120 表示绿色,240 表示蓝色。

    2. S (Saturation,饱和度):表示颜色的纯度,范围为 [0, 255],值越高表示颜色越纯,越低表示颜色越灰。

    3. V (Value,亮度):表示颜色的亮度,范围为 [0, 255],值越高表示颜色越亮。

1.3.3 为什么使用 HSV 颜色空间?

在颜色对象检测的任务中,HSV 比 BGR 更直观:

  1. 颜色分离更明显:在 BGR 中,颜色是由各通道的组合决定的,而在 HSV 中,色调 H 值直接表示颜色种类,使得对特定颜色的检测更方便。

  2. 更容易调节阈值:在 HSV 中,只需要调整色调(Hue)的范围来检测特定颜色,而在 BGR 中,你可能需要分别考虑三个通道的值。

如果你想检测红色对象,在 BGR 中可能很复杂,因为红色会涉及到 B、G、R 通道的值。而在 HSV 中,你只需要设定 H 在 0 和 10 或 170 和 180 之间,即可轻松提取红色。

HSV 转换的常见用途:

  • 颜色对象提取:例如,你想从图像或视频中提取某种颜色的物体,可以先将图像转换为 HSV 颜色空间,再通过定义 HSV 的范围,使用 cv.inRange() 来提取特定颜色。

  • 颜色过滤:你可以通过 HSV 的颜色空间,过滤掉不需要的颜色,保留或高亮感兴趣的部分。

1.3.4 cv.inRange(hsv, lower_red1, upper_red1)

参数说明:

  1. hsv:输入图像,通常是已经转换为 HSV 颜色空间的图像。

  2. lower_red1:颜色范围的下界,表示最低的 HSV 值。例如 [0, 120, 70],对应的是色调 (H)、饱和度 (S)、亮度 (V) 的最小值。

  3. upper_red1:颜色范围的上界,表示最高的 HSV 值。例如 [10, 255, 255],对应的是色调 (H)、饱和度 (S)、亮度 (V) 的最大值。

返回值:

  • mask:输出的二值图像(掩膜)。在这个掩膜中,符合给定 HSV 范围的像素会被设置为白色(255),不符合的像素会被设置为黑色(0)。

1.3.5 cv.bitwise_and(frame, frame, mask=mask)

cv.bitwise_and() 是 OpenCV 中用于按位与运算的函数。该函数的主要作用是将两个图像的每个像素按位进行与操作(AND),并生成一个新图像。结合掩膜使用时,它可以用于提取特定颜色或区域。

参数解释:
  1. src1:输入图像的第一个源,可以是 BGR 或其他颜色空间的图像。
  2. src2:输入图像的第二个源,通常与 src1 相同。这表示将 src1 中的像素与 src2 中的像素进行按位与运算。
  3. mask(可选):掩膜图像,指定哪些区域需要进行运算。掩膜中的白色区域(255)表示保留对应像素,黑色区域(0)表示不保留对应像素。
返回值:
  • output:输出图像,包含 src1src2 按位与运算的结果,或仅保留掩膜指定的区域。

 1.4 通过HSV进行颜色追踪-框选出目标区域

import cv2 as cv
import numpy as np
# 打开摄像头
cap = cv.VideoCapture(0)
while True:
    # 读取摄像头的一帧
    ret, frame = cap.read()
    if not ret:
        print("无法从摄像头获取帧")
        break
    # 将 BGR 帧转换为 HSV 颜色空间
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
    # 定义红色的 HSV 范围
    lower_red1 = np.array([0, 120, 70])
    upper_red1 = np.array([10, 255, 255])
    lower_red2 = np.array([170, 120, 70])
    upper_red2 = np.array([180, 255, 255])
    # 创建两个掩膜,分别对应红色的低端和高端
    mask1 = cv.inRange(hsv, lower_red1, upper_red1)
    mask2 = cv.inRange(hsv, lower_red2, upper_red2)
    # 合并掩膜,提取所有红色区域
    mask = mask2
    # 对掩膜进行形态学操作,去除噪点(可选)
    mask = cv.morphologyEx(mask, cv.MORPH_OPEN, np.ones((3, 3), np.uint8))
    mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, np.ones((3, 3), np.uint8))
    # 找到红色区域的轮廓
    contours, _ = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    # 在原图上绘制轮廓
    for contour in contours:
        if cv.contourArea(contour) > 500:  # 过滤掉较小的轮廓
            x, y, w, h = cv.boundingRect(contour)  # 获取包围轮廓的矩形框
            cv.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)  # 绘制矩形框
    # 显示原始帧和红色区域的掩膜
    cv.imshow('Original Frame', frame)
    cv.imshow('Red Object Mask', mask)
    # 按下 'q' 键退出
    if cv.waitKey(1) & 0xFF == ord('q'):
        break
# 释放摄像头并关闭所有窗口
cap.release()
cv.destroyAllWindows()

1.4.1 cv.morphologyEx(mask, cv.MORPH_OPEN, np.ones((3, 3), np.uint8))函数

cv.morphologyEx() 是 OpenCV 中用于执行形态学操作的函数。形态学操作常用于图像处理,特别是在处理二值图像时,如去除噪声、填补孔洞等。cv.MORPH_OPEN 是形态学操作中的一种,称为开运算。后期的形态学中会进行进一步深入。

参数解释:

  1. src:输入图像,通常是二值图像(即掩膜),在这个情况下是你之前提到的 mask

  2. op:指定要执行的形态学操作。在你的例子中,使用的是 cv.MORPH_OPEN,表示执行开运算。

  3. kernel:结构元素,是一个用于形态学操作的卷积核。通常使用 np.ones() 创建一个全为 1 的矩阵,指定卷积核的大小和形状。例如,在你的例子中,使用的是一个 3x3 的矩阵。

返回值:

  • output:输出图像,经过形态学操作后的结果。

开运算 (cv.MORPH_OPEN) 的作用:

开运算是一个由两个基本操作组成的组合操作:

  1. 腐蚀(Erosion):用结构元素对图像进行腐蚀操作,通常用于去除小的噪声点。

  2. 膨胀(Dilation):随后对腐蚀后的图像进行膨胀操作,恢复原始图像中大部分的结构。

开运算的效果是:

  • 去除小的噪声和细小的连接。

  • 保留较大的结构,平滑边缘。

import cv2 as cv
import numpy as np

# 创建一个二值掩膜
mask = cv.imread('mask.jpg', cv.IMREAD_GRAYSCALE)

# 使用开运算去除噪声
kernel = np.ones((3, 3), np.uint8)  # 创建一个3x3的结构元素
cleaned_mask = cv.morphologyEx(mask, cv.MORPH_OPEN, kernel)

# 显示结果
cv.imshow('Cleaned Mask', cleaned_mask)
cv.waitKey(0)
cv.destroyAllWindows()

处理过程:

  1. 读取掩膜:首先读取一个二值掩膜 mask

  2. 创建结构元素:使用 np.ones((3, 3), np.uint8) 创建一个 3x3 的结构元素。

  3. 应用开运算:调用 cv.morphologyEx(mask, cv.MORPH_OPEN, kernel) 执行开运算,去除掩膜中的小噪声。

  4. 显示结果:输出的 cleaned_mask 是经过开运算处理后的二值图像。

实际效果:

  • 开运算的输出图像将减少小的白色噪声点,同时保持较大物体的形状。这样可以为后续的图像处理(如轮廓检测)提供更清晰的输入。

总结:

  • cv.morphologyEx() 是一个强大的函数,用于执行多种形态学操作。

  • 开运算(cv.MORPH_OPEN)是处理二值图像中的噪声和细节的常用技术,特别适合于图像分割和目标提取等应用。

1.4.2 cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)函数

cv.findContours() 是 OpenCV 中用于检测图像中的轮廓的函数。轮廓是图像中相同颜色或相似亮度的边界曲线,可以用于形状分析和对象检测等任务。

contours, hierarchy = cv.findContours(image, mode, method)

参数解释:

  1. image:输入图像,通常是一个二值图像(如掩膜)。该图像将用于检测轮廓,轮廓通常是图像中物体的边界。注意,这个输入图像会被修改,通常在调用该函数前需要对其进行复制(如果需要保留原图像)。

  2. mode:轮廓检索模式,决定了如何检索轮廓。常用的选项包括:

    • cv.RETR_EXTERNAL:仅检索外部轮廓,忽略内部轮廓。

    • cv.RETR_LIST:检索所有轮廓,并将其放入列表中,但不建立层级关系。

    • cv.RETR_TREE:检索所有轮廓,并建立轮廓之间的层级关系。

  3. method:轮廓逼近方法,决定了如何存储轮廓的点。常用的选项包括:

    • cv.CHAIN_APPROX_SIMPLE:压缩轮廓,存储轮廓的端点,节省存储空间。

    • cv.CHAIN_APPROX_NONE:存储所有轮廓点,不进行任何压缩。

返回值:

  • contours:返回一个列表,其中包含图像中所有检测到的轮廓。每个轮廓是一个由轮廓点组成的 numpy 数组。

  • hierarchy:返回一个层级数组,表示轮廓之间的关系(可选,通常用于需要分析轮廓层级的场景)。

1.4.3 cv.contourArea(contour)函数

cv.contourArea() 是 OpenCV 中用于计算轮廓面积的函数。它接受一个轮廓作为输入,并返回该轮廓所围成区域的面积。

参数解释:

  • contour:输入轮廓,通常是通过 cv.findContours() 函数获得的轮廓。轮廓是一个由多个点组成的数组,定义了物体的边界。

返回值:

  • area:返回轮廓所围成区域的面积,单位是像素。

使用示例:

在你的示例 cv.contourArea(contour) > 500 中,函数的作用可以分为以下几步:

  1. 计算轮廓面积:调用 cv.contourArea(contour) 计算当前轮廓的面积。

  2. 与阈值比较:将计算出的面积与阈值(例如 500 像素)进行比较,以筛选出较大的轮廓。

1.5 通过HSV进行颜色追踪-围绕边缘实现框选

import cv2 as cv
import numpy as np

# 打开摄像头
cap = cv.VideoCapture(0)

while True:
    # 读取摄像头的一帧
    ret, frame = cap.read()
    if not ret:
        print("无法从摄像头获取帧")
        break

    # 将 BGR 帧转换为 HSV 颜色空间
    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)

    # 定义红色的 HSV 范围
    lower_red1 = np.array([0, 120, 70])
    upper_red1 = np.array([10, 255, 255])
    lower_red2 = np.array([170, 120, 70])
    upper_red2 = np.array([180, 255, 255])

    # 创建两个掩膜,分别对应红色的低端和高端
    mask1 = cv.inRange(hsv, lower_red1, upper_red1)
    mask2 = cv.inRange(hsv, lower_red2, upper_red2)

    # 合并掩膜,提取所有红色区域
    mask = cv.add(mask1, mask2)

    # 对掩膜进行形态学操作,去除噪点(可选)
    mask = cv.morphologyEx(mask, cv.MORPH_OPEN, np.ones((3, 3), np.uint8))
    mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, np.ones((3, 3), np.uint8))

    # 找到红色区域的轮廓
    contours, _ = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

    # 在原图上绘制轮廓
    for contour in contours:
        if cv.contourArea(contour) > 500:  # 过滤掉较小的轮廓
            cv.drawContours(frame, [contour], -1, (0, 255, 0), 2)  # 用绿色绘制轮廓

    # 显示原始帧和红色区域的掩膜
    cv.imshow('Original Frame', frame)
    cv.imshow('Red Object Mask', mask)

    # 按下 'q' 键退出
    if cv.waitKey(1) & 0xFF == ord('q'):
        break

# 释放摄像头并关闭所有窗口
cap.release()
cv.destroyAllWindows()

cv.drawContours(frame, [contour], -1, (0, 255, 0), 2)

这行代码用于在原始帧上绘制轮廓,轮廓的颜色为绿色,线条宽度为 2 像素。通过这种方式,红色区域的边缘将被绘制出来,而不是用矩形框包围。

实际效果:

  • 运行这个修改后的代码时,程序将识别并框选红色对象的边缘,显示更精确的轮廓,而不是简单的矩形框。这种方式能够更好地表现物体的形状和边界。

总结:

  • 使用 cv.drawContours() 代替矩形框绘制,使得检测结果更贴合物体的实际形状,适用于需要对形状进行更细致分析的应用场景。

2、图像的几何变换

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欲游山河十万里

你的鼓励是我们创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值