颜色识别与串口传输:基于 Python OpenCV 和 OLED 屏幕的实现
import cv2
import numpy as np
#from imutils import contours
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 time import sleep
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])# 白色阈值上界
ss = i2c(port=1, address=0x3C)
# 初始化设备,这里改ssd1306, ssd1325, ssd1331, sh1106
device = ssd1306(ss)
# 连接串口
ser = serial.Serial('/dev/ttyAMA0', 9600, timeout=2) # 连接COM14,波特率位115200
def 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) = contours.sort_contours(cnts)
# 寻找面积最大的轮廓的索引
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)
#img2 = cv2.circle(frame_out, center, 3, (0, 0, 255), 5) # 传入圆心信息,并画在原图上
#print(center) # 输出各个中心点
data = 'red'
ser.write(data.encode())
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline='white', fill='black')
font = ImageFont.truetype('FreeMonoBold.ttf', 12)
draw.text((30, 20), 'red', fill='white', font=font)
return True
else:
return False
def 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) = contours.sort_contours(cnts)
# 寻找面积最大的轮廓的索引
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)) # 画center圆心时。x,y必须是整数
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)
#img2 = cv2.circle(frame_out, center, 3, (0, 255, 0), 5) # 传入圆心信息,并画在原图上
#print(center) # 输出各个中心点
data = 'green'
ser.write(data.encode())
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline='white', fill='black')
font = ImageFont.truetype('FreeMonoBold.ttf', 12)
draw.text((30, 20), 'green', fill='white', font=font)
return True
else:
return False
def 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) = contours.sort_contours(cnts)
# 寻找面积最大的轮廓的索引
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)) # 画center圆心时。x,y必须是整数
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)
#print(center) # 输出各个中心点
data = 'white'
ser.write(data.encode())
with canvas(device) as draw:
draw.rectangle(device.bounding_box, outline='white', fill='black')
font = ImageFont.truetype('FreeMonoBold.ttf', 12)
draw.text((30, 20), 'white', fill='white', font=font)
return True
else:
return False
# 打开摄像头
vc = cv2.VideoCapture(0)
received_signal = False
red_pixels = 0
green_pixels = 0
white_pixels = 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
if red(draw_frame):
red_pixels = cv2.countNonZero(red_mask)
if green(draw_frame):
green_pixels = cv2.countNonZero(green_mask)
if white(draw_frame):
white_pixels = cv2.countNonZero(white_mask)
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)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
vc.release()
cv2.destroyAllWindows()
ser.close()
原文地址: https://www.cveoy.top/t/topic/nXRp 著作权归作者所有。请勿转载和采集!