基于yanshee的颜色识别任务中,注意:使用opencv3会返回三个值,即img、countours和hierarchy。
cv2.findContours()函数首先返回一个list列表,
list中每个元素都是图像中的一个轮廓。
参数介绍:
Image:寻找轮廓的图像
Mode:表示轮廓的检索模式
Method:轮廓的近似办法
作用:寻找轮廓。
Bb:通过轮廓的面积筛选轮廓并将轮廓画出:
for cnt in contours:
# 计算轮廓的面积
area = cv2.contourArea(cnt)
if area > 50:
# print("面积:{}".format(area))
# 筛选完后将筛选过后的轮廓draw画出来。
cv2.drawContours(frame_copy, cnt, -1, (0, 0, 255), 3)
# 计算轮廓周长
peri = cv2.arcLength(cnt, True)
# print("周长:{}".format(peri))
# 画出的轮廓可能不够规整,比如圆形不像圆形,多边形不像多边形,因此对其进行一个多边形拟合操作approxPolyDP。达到一种轮廓近似的效果。
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
cv2.drawContours(img,contours,contourIndex,color,crudeness)
参数介绍:
Img:指明在哪幅图像上绘制轮廓(ima为三通道才能显示轮廓)
Contours:轮廓本身,是一个list;
contourIndex:指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。
Color:指明颜色(需为三通道,eg:(255,0,0),否则不会显色)
crudeness:线条粗细
作用:画出轮廓。 ps:(在本代码中,此行代码只用于测试,没有也不影响)
cv2.aprroxPolyDP(cnt, epsilon, True)
参数介绍:
Cnt:为输入的轮廓值
Epsilon:为阈值T,通常使用轮廓的周长作为阈值
True:表示的是轮廓是闭合的
作用:画出的轮廓可能不够规整,比如圆形不像圆形,多边形不像多边形,因此对其进行一个多边形拟合操作approxPolyDP。达到一种轮廓近似的效果。
(小说明:进行完上述的操作之后,我们基本已经精准地找到了我们目标(小球)的位置,接下来的任务就是通过找出的轮廓,然后用圆圈圈出它。)
1)根据轮廓的位置,对其进行一个跟踪,即用圆圈把它的位置圈出,进行一个标记。
(主要思路:我们可以根据我们所找出的轮廓,求它的最小整矩形,然后借这个最小正矩形的返回值(返回值会返回它左上角的焦点的x点和y点以及它的宽和高)来得到圆圈的圆心还有半径。)
具体步骤:
- 用上述我们已经找出的轮廓,求它的最小正矩形,并返回四个返回值。
# 进行轮廓近似后的图形,用boundingRect函数得到它的最小正矩形。
# 矩形的边界与图像边界平行
(x,y)最小正矩形左上角的点,w为宽,h为高。
x, y, w, h = cv2.boundingRect(approx)
cv2.boundingRect(cnt)
参数介绍:
Cnt:轮廓近似后的图形
作用:得到图形的最小正矩形,得出四个返回值。
- 用得出的四个返回值,来作为cv.circle的参数。
cv2.circle(frame, ((x + w / 2), (y + h / 2)), w / 2, (0, 255, 0), 2)
cv2.Cricle(img, center, radius, (0, 255, 0), 2)
参数介绍:
Img:表示需要画的图片
Center:表示圆的中心点
Radius:表示圆的半径,(0, 255, 0)表示颜色
2:表示线条的粗细
作用: 根据坐标在图上画出圆
具体代码:
1 #!/usr/bin/env python 2 # coding: utf-8 3 4 # In[ ]: 5 6 7 # python2 所需 ↓ 8 9 10 # 导入需要用到的包 11 import time 12 from picamera.array import PiRGBArray 13 from picamera import PiCamera 14 import numpy as np 15 import cv2 16 import math 17 import requests 18 import json 19 20 # 分辨小球颜色需要用到的HSV值。 21 # 样题只要红色 22 # # 红色: 23 # red_min = np.array([0, 128, 46]) 24 # red_max = np.array([5, 255, 255]) 25 # red2_min = np.array([156, 128, 46]) 26 # red2_max = np.array([180, 255, 255]) 27 28 # # 绿色: 29 # green_min = np.array([35, 128, 46]) 30 # green_max = np.array([77, 255, 255]) 31 32 # # 蓝色: 33 # blue_min = np.array([100, 128, 46]) 34 # blue_max = np.array([124, 255, 255]) 35 36 # # 黄色: 37 # yellow_min = np.array([15, 128, 46]) 38 # yellow_max = np.array([34, 255, 255]) 39 40 # 橙色: 41 orange_min = np.array([0, 49, 117]) 42 orange_max = np.array([40, 255, 255]) 43 # # ...等等颜色 44 45 # # 把颜色都汇总到一个数组中,顺带给各自定义一个颜色名。 46 # COLOR_ARRAY = [[red_min, red_max, 'red'], [red2_min, red2_max, 'red'], [green_min, green_max, 'green'], 47 # [blue_min, blue_max, 'blue'], [yellow_min, yellow_max, 'yellow'], [orange_min, orange_max, 'orange']] 48 49 50 //建立与机器人的连接。 51 root_url = "http://127.0.0.1:9090/v1" 52 motions_url = root_url + "/motions" 53 led_url = root_url + "/devices/led" 54 headers = {'Content-Type': 'application/json'} 55 56 57 # 定义一个停止运动的函数。 58 def stopmotion(): 59 motion = {"operation": "stop", "motion": {"name": ""}} 60 json_data = json.dumps(motion) 61 response = requests.put(url=motions_url, data=json_data, headers=headers) 62 63 64 # 定义一个带有颜色参数的函数。 65 # 作用在于传对应参数颜色给机器人,机器人就闪什么颜色。 66 def putled(color): 67 led = {"type": "button", "color": color, "mode": "on"} 68 json_data = json.dumps(led) 69 response = requests.put(url=led_url, data=json_data, headers=headers) 70 71 # 定义一个带有参数的函数。 72 # 作用在于传对应参数方向(左右手)给机器人,机器人就举起哪只手。 73 def putmotion(direction): 74 motion = {"operation": "start", "motion": {"name": "raise","direction": direction}} 75 json_data = json.dumps(motion) 76 response = requests.put(url=motions_url, data=json_data, headers=headers) 77 78 79 80 # 先初始化摄像头: 81 camera = PiCamera() 82 camera.resolution = (320, 240) 83 camera.framerate = 40 84 rawCapture = PiRGBArray(camera, size=(320, 240)) 85 time.sleep(2) 86 # 在初始化摄像头后定义一个全局变量(global ) change,好让机器人在检测到小球的位置后 所执行的次数仅为1,不会死循环执行。 87 change = 0 88 89 90 # 查找颜色小球并圆圈圈出: 91 def find_color(img): 92 global change 93 cv2.imwrite('frame.jpg', img) 94 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 95 cv2.imwrite('hsv.jpg', hsv) 96 97 # for (color_min, color_max, name) in COLOR_ARRAY: 98 99 # 创建一个蒙版,在阈值范围内的像素点全变为255 白色,之外的全都变成0 黑色。 100 # mask = cv2.inRange(hsv, color_min, color_max) 101 # 创建一个蒙版,在阈值范围内的像素点全变为255 白色,之外的全都变成0 黑色。 102 mask = cv2.inRange(hsv, orange_min, orange_max) 103 cv2.imwrite('mask.jpg', mask) 104 # '与'操作,有蒙版参数在内的话,则仅上色蒙版中255的部分。 105 resultImg = cv2.bitwise_and(img, img, mask=mask) 106 cv2.imwrite('res.jpg', resultImg) 107 x, y, w, h = getContours(mask) 108 if x != 0 and y != 0 and w != 0 and h != 0: 109 cv2.circle(frame, ((x + w / 2), (y + h / 2)), w / 2, (0, 255, 0), 2) 110 cv2.putText(frame, 'orange', (x + w / 2, y + h + 10), cv2.FONT_HERSHEY_COMPLEX, 0.4, (0, 0, 255), 1) 111 # print(x + w / 2) 112 if change == 0: 113 change = 1 if (x + w // 2) < 160 else 2 114 print 'change001 = %d' % change 115 if ((x + w // 2) < 160) and (change == 1): 116 print("左手一个慢动作") 117 change = 2 118 putmotion("left") 119 putled("yellow") 120 elif ((x + w // 2) > 160) and (change == 2): 121 print("右手一个慢动作") 122 change = 1 123 putmotion("right") 124 putled("green") 125 126 127 # 找出轮廓: 128 def getContours(img): 129 x, y, w, h = 0, 0, 0, 0 130 # 进行一个均值滤波操作,去除一些不必要的噪点,消除一些影响因素。 131 blured = cv2.blur(img, (5, 5)) 132 # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) 133 # 对进行过滤后的图片进行一个开操作 (先腐蚀再膨胀) 134 # 作用: 135 去除噪声,消除小物体 136 在纤细点处分离物体 137 平滑较大物体的边界的同时并不明显改变其面积 138 139 opened = cv2.morphologyEx(blured, cv2.MORPH_OPEN, (3, 3)) 140 cv2.imwrite('opened.jpg', opened) 141 142 143 144 145 146 147 # 对进行过滤后的图片进行一个闭操作 (先膨胀再腐蚀) 148 # 作用: 149 排除小型空洞(指黑色区域) 150 平滑物体轮廓 151 弥合(连接)窄的间断点,沟壑 152 填补轮廓线断裂 153 154 closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, (3, 3)) 155 cv2.imwrite('closed.jpg', closed) 156 # 对图像进行边缘检测。 157 imgCanny = cv2.Canny(closed, 50, 100) 158 cv2.imwrite('imgCanny.jpg', imgCanny) 159 # 将边缘检测的图像找出来。(其中可能会检测到多个轮廓,因此要对轮廓进行一个筛选。) 160 contours, hierachy = cv2.findContours(imgCanny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) 161 for cnt in contours: 162 area = cv2.contourArea(cnt) 163 if area > 50: 164 # print("面积:{}".format(area)) 165 # 筛选完后将筛选过后的轮廓draw画出来。 166 cv2.drawContours(frame_copy, cnt, -1, (0, 0, 255), 3) 167 peri = cv2.arcLength(cnt, True) 168 # print("周长:{}".format(peri)) 169 # 画出的轮廓可能不够规整,比如圆形不像圆形,多边形不像多边形,因此对其进行一个多边形拟合操作approxPolyDP。达到一种轮廓近似的效果。 170 approx = cv2.approxPolyDP(cnt, 0.02 * peri, True) 171 # 进行轮廓近似后的图形,用boundingRect函数得到它的最小正矩形。 172 # 矩形的边界与图像边界平行 173 # (x,y)为最小正矩形左上角的点,w为宽,h为高。 174 x, y, w, h = cv2.boundingRect(approx) 175 return x, y, w, h 176 177 178 # 关闭摄像头与窗口: 179 def close_it(): 180 camera.close() 181 cv2.destroyAllWindows() 182 stopmotion() 183 184 185 for frame in camera.capture_continuous(rawCapture, format='bgr', use_video_port=True): 186 # 当前帧 187 frame = frame.array 188 frame_copy = frame.copy() 189 find_color(frame) 190 cv2.imshow("Result", frame) 191 rawCapture.truncate(0) 192 if cv2.waitKey(1) & 0xFF == ord('q'): 193 close_it() 194 break
原文地址:https://www.cnblogs.com/simmons99/p/14023716.html