背景:
在水下环境中,由于水质、光线和拍摄设备的影响,图像通常会出现色彩失真、对比度降低等问题。这些问题对于色块识别任务来说是一个挑战。要求使用OpenCV库,设计一个算法,实现对水下环境中特定色块的识别。
RGB三色卡
水下识别的任务需求为在一组水下拍摄的视频中逐帧识别,即一套算法在应对光照变化、颜色失真等问题下依然可以正常识别,为模拟水下的实践识别需求,本题目数据由多组色块在泳池中的实拍合成,不同组别色块环境(光照,角度)不同。
要求:
要求对下图进行识别,将图中的色块圈出,并进行图像识别。
对此整图进行识别↑
示例:
识别示例1-较差
识别示例2-较好
注意事项:
1.考虑到水下环境的特殊性,算法应具有较好的鲁棒性,能够应对光照变化、颜色失真等问题。
2.在实现算法时,注意代码的可读性和可维护性,适当添加注释和说明。
工具:
Rgbhsv转换工具:https://www.rapidtables.org/zh-CN/convert/color/rgb-to-hsv.html
解题:
import cv2
import numpy as np
import matplotlib.pyplot as plt
def find_color_blocks(image):
# 将图像转换为HSV颜色空间
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 定义背景的HSV颜色范围
lower_bg = np.array([90, 50, 50])
upper_bg = np.array([160, 255, 255])
# 根据背景的颜色范围创建背景掩码
mask_bg = cv2.inRange(hsv, lower_bg, upper_bg)
# 对图像进行二值化处理,将背景设置为白色,前景设置为黑色
_, binary = cv2.threshold(mask_bg, 100, 255, cv2.THRESH_BINARY)
# 反转二值化图像,使前景为白色,背景为黑色
binary = cv2.bitwise_not(binary)
# 查找图像中的轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
result = image.copy()
cv2.drawContours(result, contours, -1, (0, 255, 0), 2)
# 显示二值化结果和轮廓
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(binary, cmap='gray')
plt.title('Binary Image')
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
plt.title('Contours')
plt.axis('off')
plt.show()
# 对每个轮廓进行颜色判断
for contour in contours:
area = cv2.contourArea(contour)
if area > 100: # 忽略面积小于100的轮廓
# 获取轮廓的外接矩形
x, y, w, h = cv2.boundingRect(contour)
roi = image[y:y+h, x:x+w]
# 在图像中绘制外接矩形
cv2.rectangle(image, (x, y), (x+w, y+h), (255, 0, 0), 2)
# 计算外接矩形区域的颜色平均值
mean_color = cv2.mean(roi)[:3]
color = get_color_name(mean_color)
# 在图像中显示颜色标签
cv2.putText(image, color, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
# 显示最终结果
plt.figure(figsize=(5, 5))
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Final Result')
plt.axis('off')
plt.show()
def get_color_name(color):
# 定义颜色名称
colors = {'Red': (0, 0, 255),
'Green': (0, 255, 0),
'Blue': (255, 0, 0)}
# 计算颜色与已知颜色的距离
distances = {name: np.linalg.norm(np.array(color) - np.array(value)) for name, value in colors.items()}
# 找到距离最小的颜色名称
color_name = min(distances, key=distances.get)
return color_name
# 读取图像
image = cv2.imread('test.png')
# 查找并标记色块
find_color_blocks(image)
cv2.imshow('Result', image)
结果: