颜色识别与 OLED 显示:实时检测红色、绿色和白色物体
import cv2 import numpy as np import serial from luma.core.interface.serial import i2c, spi from luma.core.render import canvas from luma.oled.device import ssd1306, ssd1325, ssd1331, sh1106 from PIL import ImageFont
颜色阈值
lower_red = np.array([0, 178, 71]) # 红色阈值下界 higher_red = np.array([56, 255, 207]) # 红色阈值上界 lower_green = np.array([86, 122, 37]) # 绿色阈值下界 higher_green = np.array([96, 255, 191]) # 绿色阈值上界 lower_white = np.array([0, 0, 221]) # 白色阈值下界 higher_white = np.array([180, 0, 255])# 白色阈值上界
初始化 OLED 屏幕
ss = i2c(port=1, address=0x3C) device = ssd1306(ss)
连接串口
ser = serial.Serial('/dev/ttyAMA0', 9600, timeout=2)
预设信号接收标志为 False
received_signal = False
定义函数:检测红色物体
def detect_red(draw_frame): kernel = np.ones((5, 5), np.uint8) frame_hsv = cv2.cvtColor(draw_frame, cv2.COLOR_BGR2HSV)
# 颜色识别
img = cv2.inRange(frame_hsv, lower_red, higher_red)
# 膨胀操作
dilation = cv2.dilate(img, kernel, iterations=1)
# 闭操作
closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel)
# 高斯滤波
closing = cv2.GaussianBlur(closing, (5, 5), 0)
# 边缘检测
edges = cv2.Canny(closing, 10, 20)
'''上面进行那么多操作就是为了得到更好的目标图形,具体效果因环境而异'''
# 寻找轮廓
cnts, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 判断轮廓数量也就是判断是否寻找到轮廓,如果没有找到轮廓就不继续进行操作
if len(cnts) > 0:
# 存放轮廓面积的列表
s = []
# 存放最大轮廓的索引
max_index = 0
# 获得排序后的轮廓列表以及每个轮廓对应的外接矩形
(cnts, boundingRects) = cv2.sortContours(cnts, cv2.SORT_DESCENDING)
# 寻找面积最大的轮廓的索引
for cnt in cnts:
s.append(cv2.contourArea(cnt))
max_index = s.index(max(s))
# 根据面积最大轮廓的索引找到它的外接矩形的信息
(x, y, w, h) = boundingRects[max_index]
# 画矩形
frame_out = cv2.rectangle(draw_frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
center_x, center_y = (int(x + w / 2), int(y + h / 2))
box_size = 10
center_box = draw_frame[center_y - box_size:center_y + box_size, center_x - box_size:center_x + box_size]
# 在屏幕上绘制矩形框
cv2.rectangle(img, (center_x - box_size, center_y - box_size), (center_x + box_size, center_y + box_size),
(0, 255, 0), 2)
red_mask = cv2.inRange(center_box, lower_red, higher_red)
red_pixels = cv2.countNonZero(red_mask)
data = 'red'
ser.write(data.encode())
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline='white', fill='black')
draw.text((30, 20), 'red', fill='white')
return True
else:
return False
定义函数:检测绿色物体
def detect_green(draw_frame): kernel = np.ones((5, 5), np.uint8) frame_hsv = cv2.cvtColor(draw_frame, cv2.COLOR_BGR2HSV)
# 颜色识别
img = cv2.inRange(frame_hsv, lower_green, higher_green)
# 膨胀操作
dilation = cv2.dilate(img, kernel, iterations=1)
# 闭操作
closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel)
# 高斯滤波
closing = cv2.GaussianBlur(closing, (5, 5), 0)
# 边缘检测
edges = cv2.Canny(closing, 10, 20)
'''上面进行那么多操作就是为了得到更好的目标图形,具体效果因环境而异'''
# 寻找轮廓
cnts, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 判断轮廓数量也就是判断是否寻找到轮廓,如果没有找到轮廓就不继续进行操作
if len(cnts) > 0:
# 存放轮廓面积的列表
s = []
# 存放最大轮廓的索引
max_index = 0
# 获得排序后的轮廓列表以及每个轮廓对应的外接矩形
(cnts, boundingRects) = cv2.sortContours(cnts, cv2.SORT_DESCENDING)
# 寻找面积最大的轮廓的索引
for cnt in cnts:
s.append(cv2.contourArea(cnt))
max_index = s.index(max(s))
# 根据面积最大轮廓的索引找到它的外接矩形的信息
(x, y, w, h) = boundingRects[max_index]
# 画矩形
frame_out = cv2.rectangle(draw_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
center_x, center_y = (int(x + w / 2), int(y + h / 2))
box_size = 10
center_box = draw_frame[center_y - box_size:center_y + box_size, center_x - box_size:center_x + box_size]
# 在屏幕上绘制矩形框
cv2.rectangle(img, (center_x - box_size, center_y - box_size), (center_x + box_size, center_y + box_size),
(0, 255, 0), 2)
green_mask = cv2.inRange(center_box, lower_green, higher_green)
green_pixels = cv2.countNonZero(green_mask)
data = 'green'
ser.write(data.encode())
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline='white', fill='black')
draw.text((30, 20), 'green', fill='white')
return True
else:
return False
定义函数:检测白色物体
def detect_white(draw_frame): kernel = np.ones((5, 5), np.uint8) frame_hsv = cv2.cvtColor(draw_frame, cv2.COLOR_BGR2HSV)
# 颜色识别
img = cv2.inRange(frame_hsv, lower_white, higher_white)
# 膨胀操作
dilation = cv2.dilate(img, kernel, iterations=1)
# 闭操作
closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel)
# 高斯滤波
closing = cv2.GaussianBlur(closing, (5, 5), 0)
# 边缘检测
edges = cv2.Canny(closing, 10, 20)
'''上面进行那么多操作就是为了得到更好的目标图形,具体效果因环境而异'''
# 寻找轮廓
cnts, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
if len(cnts) > 0:
# 存放轮廓面积的列表
s = []
# 存放最大轮廓的索引
max_index = 0
# 获得排序后的轮廓列表以及每个轮廓对应的外接矩形
(cnts, boundingRects) = cv2.sortContours(cnts, cv2.SORT_DESCENDING)
# 寻找面积最大的轮廓的索引
for cnt in cnts:
s.append(cv2.contourArea(cnt))
max_index = s.index(max(s))
# 根据面积最大轮廓的索引找到它的外接矩形的信息
(x, y, w, h) = boundingRects[max_index]
frame_out = cv2.rectangle(draw_frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
center_x, center_y = (int(x + w / 2), int(y + h / 2))
box_size = 10
center_box = draw_frame[center_y - box_size:center_y + box_size, center_x - box_size:center_x + box_size]
# 在屏幕上绘制矩形框
cv2.rectangle(img, (center_x - box_size, center_y - box_size), (center_x + box_size, center_y + box_size),
(0, 255, 0), 2)
white_mask = cv2.inRange(center_box, lower_white, higher_white)
white_pixels = cv2.countNonZero(white_mask)
data = 'white'
ser.write(data.encode())
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline='white', fill='black')
draw.text((30, 20), 'white', fill='white')
return True
else:
return False
打开摄像头
vc = cv2.VideoCapture(0)
while True: flag, frame = vc.read() draw_frame = frame.copy()
# 读取串口数据
data = ser.readline().decode('utf-8').strip()
if data == 'g':
print('received_signal')
received_signal = True
# 执行颜色检测函数
red_result = detect_red(draw_frame)
green_result = detect_green(draw_frame)
white_result = detect_white(draw_frame)
# 统计颜色像素点数量
red_pixels = 0
green_pixels = 0
white_pixels = 0
if red_result:
red_pixels = 1 # 这里直接设置 red_pixels 为 1,因为 detect_red 函数已经计算了红色像素点
if green_result:
green_pixels = 1 # 同理,设置 green_pixels 为 1
if white_result:
white_pixels = 1 # 设置 white_pixels 为 1
# 判断颜色
color_name = ''
if red_pixels > white_pixels and red_pixels > green_pixels:
color_name = 'red'
elif white_pixels > red_pixels and white_pixels > green_pixels:
color_name = 'white'
elif green_pixels > red_pixels and green_pixels > white_pixels:
color_name = 'green'
# 发送识别结果
if received_signal:
if color_name:
ser.write(color_name.encode('utf-8'))
received_signal = False # 处理完信号后将其重置为 False
else:
print('Color not recognized!')
# 显示图像
cv2.imshow('frame', frame)
cv2.waitKey(1)
释放资源
vc.release() cv2.destroyAllWindows() ser.close()
原文地址: https://www.cveoy.top/t/topic/nXSu 著作权归作者所有。请勿转载和采集!