HSV颜色空间是一种用于颜色处理的颜色空间,它代表了颜色的三个基本属性:色调(Hue)、饱和度(Saturation)和亮度(Value)。
总的来说,HSV颜色空间以更接近人类视觉感知的方式来描述颜色,使得颜色的表示更为直观和易于理解。
Python
import cv2
# 读取图片
image = cv2.imread('color_shape.jpeg')
# 将图片从BGR颜色空间转换为HSV颜色空间
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 显示原始图片和HSV图片
cv2.imshow('Original Image', image)
cv2.imshow('HSV Image', hsv_image)
# 等待用户按下任意键退出
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
使用上述代码将图片从BGR转到HSV颜色空间。
它们的取值范围如下:
根据上图我们可以知道,红色的色调的(0-10)和(170-180),我们接下来提取红色颜色。
一般,我们会使用二值化的方法提取颜色;
import cv2
import numpy as np
# 读取图片
image = cv2.imread('color_shape.jpeg')
# 将图片从BGR颜色空间转换为HSV颜色空间
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义红色在HSV中的范围
lower_red_1 = np.array([0, 50, 50]) # HSV中的红色下限 (0, 50, 50)
upper_red_1 = np.array([10, 255, 255]) # HSV中的红色上限 (10, 255, 255)
lower_red_2 = np.array([170, 50, 50]) # HSV中的红色下限 (170, 50, 50)
upper_red_2 = np.array([180, 255, 255]) # HSV中的红色上限 (180, 255, 255)
# 创建红色掩膜
mask_1 = cv2.inRange(hsv_image, lower_red_1, upper_red_1)
mask_2 = cv2.inRange(hsv_image, lower_red_2, upper_red_2)
mask = mask_1 | mask_2 # 合并两个掩膜
cv2.imshow('Mask', mask)
# 对原始图片和掩膜进行位运算,提取红色区域
red_image = cv2.bitwise_and(image, image, mask=mask)
# 显示原始图片和提取的红色区域
cv2.imshow('Original Image', image)
cv2.imshow('Red Extracted', red_image)
# 等待用户按下任意键退出
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
cv2.inRange() 函数是二值化的核心,用于创建一个掩膜,可以看到掩膜其实也是一个跟原图像素相同的图像,满足颜色阈值的区域在这个图像中像素是255,不满足的像素是0。
最后,使用 cv2.bitwise_and() 函数对原始图片和掩膜进行位运算,以提取出红色区域。
cv2.bitwise_and 是 OpenCV 中的一个函数,用于对两个数组或图像执行按位与操作。
该操作会对应地比较两个输入数组的每一个位,并在输出数组中为每个位置设置相应的位。
函数定义如下:
cv2.bitwise_and(src1, src2, dst=None, mask=None)
参数说明:
这个函数通常用于图像处理中的掩膜操作。例如,你可以使用 cv2.bitwise_and 来提取图像的特定区域或对图像进行某种特定的按位操作。
一个简单的例子:假设你有两个二进制图像,你希望在不改变其他像素的情况下,将其中一个图像中的某个区域复制到另一个图像中。
在这种情况下,你可以使用 cv2.bitwise_and 与一个掩膜来实现这个操作。
注意:在使用 cv2.bitwise_and 时,确保输入图像的大小和数据类型是相同的,否则可能会导致错误或不预期的结果。
结果如下所示:
这样我们就把颜色“抠“出来了;
形态学运算是一种应用于图像处理领域的技术,主要用于描述和处理图像中的形状和结构。形态学运算基于形状的图像处理技术,通过结构元素与图像进行特定运算来改变图像的形态和特征。
其中,结构元素是一种小型、预定义的形状,如矩形、圆形或椭圆形,可以与图像中的像素进行匹配。
形态学运算包括多种基本操作,如腐蚀(Erosion)、膨胀(Dilation)、开运算(Opening)和闭运算(Closing)。
形态学在图像处理中应用广泛,如图像分割、边缘检测、文本识别、计算机视觉等领域中。
通过形态学运算,可以有效地提取图像中的特征、消除噪声、改变图像的形状等,为图像处理和计算机视觉任务提供有力的支持。
import cv2
import numpy as np
# 读取图片
image = cv2.imread('color_shape.jpeg')
# 将图片从BGR颜色空间转换为HSV颜色空间
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义红色在HSV中的范围
lower_red_1 = np.array([0, 50, 50]) # HSV中的红色下限 (0, 50, 50)
upper_red_1 = np.array([10, 255, 255]) # HSV中的红色上限 (10, 255, 255)
lower_red_2 = np.array([170, 50, 50]) # HSV中的红色下限 (170, 50, 50)
upper_red_2 = np.array([180, 255, 255]) # HSV中的红色上限 (180, 255, 255)
# 创建红色掩膜
mask_1 = cv2.inRange(hsv_image, lower_red_1, upper_red_1)
mask_2 = cv2.inRange(hsv_image, lower_red_2, upper_red_2)
mask = mask_1 | mask_2 # 合并两个掩膜
cv2.imshow('Mask', mask)
# 定义一个结构元素,这里使用3x3的矩形作为示例
kernel = np.ones((5, 5), np.uint8)
# 对掩膜进行腐蚀操作
erosion_mask = cv2.erode(mask, kernel, iterations=1)
# 对掩膜进行膨胀操作
dilation_mask = cv2.dilate(mask, kernel, iterations=1)
cv2.imshow('Erosion Mask', erosion_mask)
cv2.imshow('Dilation Mask', dilation_mask)
# 对原始图片和掩膜进行位运算,提取红色区域
red_image = cv2.bitwise_and(image, image, mask=mask)
# 显示原始图片和提取的红色区域
#cv2.imshow('Original Image', image)
#cv2.imshow('Red Extracted', red_image)
# 等待用户按下任意键退出
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
这里我们使用形态学运算的目的,首先,形态学运算能够帮助去除图像中的噪声。
通过腐蚀操作,可以将边界上的像素点去除,使得颜色区域更加清晰,减少噪声的干扰。
这样可以在后续的颜色提取过程中,更准确地定位到目标颜色的区域。
其次,形态学运算可以用来填补颜色区域内的空洞。通过膨胀操作,可以将与目标颜色接触的背景像素点合并到颜色区域中,从而使得颜色区域更加完整。
这对于一些存在断裂或者空洞的颜色区域非常有效。
此外,形态学运算还可以用来平滑颜色区域的边界。
通过开运算和闭运算的组合使用,可以在不改变颜色区域面积的情况下,平滑边界的毛刺和不规整部分,使得提取出的颜色区域更加规整和准确。
OpenCV提取连通域的算法通常是通过遍历图像像素,并标记连通区域的方式实现的。其基本步骤如下:
import cv2
import numpy as np
# 读取图片
image = cv2.imread('color_shape.jpeg')
# 将图片从BGR颜色空间转换为HSV颜色空间
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义红色在HSV中的范围
lower_red_1 = np.array([0, 50, 50]) # HSV中的红色下限 (0, 50, 50)
upper_red_1 = np.array([10, 255, 255]) # HSV中的红色上限 (10, 255, 255)
lower_red_2 = np.array([170, 50, 50]) # HSV中的红色下限 (170, 50, 50)
upper_red_2 = np.array([180, 255, 255]) # HSV中的红色上限 (180, 255, 255)
# 创建红色掩膜
mask_1 = cv2.inRange(hsv_image, lower_red_1, upper_red_1)
mask_2 = cv2.inRange(hsv_image, lower_red_2, upper_red_2)
mask = mask_1 | mask_2 # 合并两个掩膜
cv2.imshow('Mask', mask)
# 寻找连通域
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历每一个连通域
for contour in contours:
# 获取连通域的边界框
x, y, w, h = cv2.boundingRect(contour)
# 在原始图像上画出连通域的边界框
cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 计算边界框的中心点坐标
center_x = x + w // 2
center_y = y + h // 2
# 在边界框中心画十字
# 画水平线
cv2.line(image, (center_x - 5, center_y), (center_x + 5, center_y), (0, 255, 0), 2)
# 画垂直线
cv2.line(image, (center_x, center_y - 5), (center_x, center_y + 5), (0, 255, 0), 2)
# 显示标有连通域边界框的原始图像
cv2.imshow('Original Image with Bounding Boxes', image)
# 等待用户按下任意键退出
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
运行结果如下所示:
这里最重要的一点是我们得到了图像的中心。
有时候我们不仅依靠颜色,还依靠形状来识别图形,这里就要用到霍夫变换。
霍夫变换是一种图像处理中的特征提取技术,广泛应用于图像分析、计算机视觉以及数字图像处理等领域。
其最初被设计用来检测直线和曲线,通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果。
后来霍夫变换被扩展应用到识别任意形状,例如圆和椭圆等。
先通过这个函数提取边界:
# 对Mask应用Canny边缘检测
edges = cv2.Canny(mask, 100, 200)
然后膨胀一下清晰边界:
# 定义一个结构元素,这里使用3x3的矩形作为示例
kernel = np.ones((3, 3), np.uint8)
# 对掩膜进行膨胀操作
dilation_edges = cv2.dilate(edges, kernel, iterations=1)
然后使用霍夫变换提取下面的圆形:
# 使用霍夫变换在边缘检测后的图像中检测圆形
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
# 将检测到的圆形转换为整数
if circles is not None:
circles = np.uint16(np.around(circles))
# 在原始图像上绘制检测到的圆形
for circle in circles[0, :]:
# 绘制圆形
cv2.circle(image, (circle[0], circle[1]), circle[2], (0, 255, 0), 2)
# 绘制圆心
cv2.circle(image, (circle[0], circle[1]), 2, (0, 0, 255), 3)
完整代码如下所示:
import cv2
import numpy as np
# 读取图片
image = cv2.imread('color_shape.jpeg')
# 将图片从BGR颜色空间转换为HSV颜色空间
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义红色在HSV中的范围
lower_red_1 = np.array([0, 50, 50]) # HSV中的红色下限 (0, 50, 50)
upper_red_1 = np.array([10, 255, 255]) # HSV中的红色上限 (10, 255, 255)
lower_red_2 = np.array([170, 50, 50]) # HSV中的红色下限 (170, 50, 50)
upper_red_2 = np.array([180, 255, 255]) # HSV中的红色上限 (180, 255, 255)
# 创建红色掩膜
mask_1 = cv2.inRange(hsv_image, lower_red_1, upper_red_1)
mask_2 = cv2.inRange(hsv_image, lower_red_2, upper_red_2)
mask = mask_1 | mask_2 # 合并两个掩膜
# 对Mask应用Canny边缘检测
edges = cv2.Canny(mask, 100, 200)
# 定义一个结构元素,这里使用3x3的矩形作为示例
kernel = np.ones((3, 3), np.uint8)
# 对掩膜进行膨胀操作
dilation_edges = cv2.dilate(edges, kernel, iterations=1)
# 使用霍夫变换在边缘检测后的图像中检测圆形
circles = cv2.HoughCircles(dilation_edges, cv2.HOUGH_GRADIENT, 1, 10, param1=50, param2=40, minRadius=0, maxRadius=0)
# 将检测到的圆形转换为整数
if circles is not None:
circles = np.uint16(np.around(circles))
# 在原始图像上绘制检测到的圆形
for circle in circles[0, :]:
# 绘制圆形
cv2.circle(image, (circle[0], circle[1]), circle[2], (0, 255, 0), 2)
# 绘制圆心
cv2.circle(image, (circle[0], circle[1]), 2, (255, 0, 0), 3)
# 显示原始图片和提取的红色区域
cv2.imshow('Original Image', image)
# 等待用户按下任意键退出
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
可以看到,形状识别还有些不准确的现象,还需要调整参数。
在使用OpenCV的cv2.HoughCircles函数进行圆形检测时,调参是一个关键的步骤,它直接影响到检测结果的准确性和效率。cv2.HoughCircles函数的参数较多,每个参数都有其特定的作用和调参技巧。以下是对这些参数的详细解释和调参建议:
参数解释
调参建议
这样我们就实现了颜色/形状识别。