接上篇OpenCV基于颜色识别目标(入门简单图片版)
这次加入了摄像头
实现思路:视频其实就是每一张图片的叠加,只要对视频中的每一帧读入并作处理,就能实现对视频流中目标的识别。所以这里我们只要将读入图像和处理图像的操作放入while循环中就能实现实时的识别目标了。
具体代码实现
import cv2
import numpy as np
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
#定义一个形态学处理的函数
def good_thresh_img(img):
gs_frame = cv2.GaussianBlur(img, (5, 5), 0) #高斯滤波
hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV) # 转化成HSV图像
erode_hsv = cv2.erode(hsv, None, iterations=2)
return erode_hsv
#定义一个识别目标颜色并处理的函数
def select_color_img(target_color,img):
for i in target_color:
mask=cv2.inRange(erode_hsv,color_dist[i]['Lower'],color_dist[i]['Upper'])
if(i==target_color[0]):
inRange_hsv=cv2.bitwise_and(erode_hsv,erode_hsv,mask = mask)
else:
inRange_hsv1=cv2.bitwise_and(erode_hsv,erode_hsv,mask = mask)
inRange_hsv=cv2.add(inRange_hsv,inRange_hsv1)
return inRange_hsv
#定义一个提取轮廓的函数
def extract_contour(img):
inRange_gray = cv2.cvtColor(final_inRange_hsv,cv2.COLOR_BGR2GRAY)
contours,hierarchy = cv2.findContours(inRange_gray,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
return contours
#定义一个寻找目标并绘制外接矩形的函数
def find_target(contours,draw_img):
for c in contours:
if cv2.contourArea(c) < 2000: #过滤掉较面积小的物体
continue
else:
target_list.append(c) #将面积较大的物体视为目标并存入目标列表
for i in target_list: #绘制目标外接矩形
rect = cv2.minAreaRect(i)
box = cv2.boxPoints(rect)
cv2.drawContours(draw_img, [np.int0(box)], -1, (0, 255, 255), 2)
return draw_img
#定义一个绘制中心点坐标的函数
def draw_center(target_list,draw_img):
for c in target_list:
M = cv2.moments(c) #计算中心点的x、y坐标
center_x = int(M['m10']/M['m00'])
center_y = int(M['m01']/M['m00'])
print('center_x:',center_x)
print('center_y:',center_y)
cv2.circle(draw_img,(center_x,center_y),7,128,-1)#绘制中心点
str1 = '(' + str(center_x)+ ',' +str(center_y) +')' #把坐标转化为字符串
cv2.putText(draw_img,str1,(center_x-50,center_y+40),cv2.FONT_HERSHEY_SIMPLEX,1,(255,255,0),2,cv2.LINE_AA)#绘制坐标点位
return draw_img
###主函数部分
#创建颜色字典
color_dist = {'red': {'Lower': np.array([0, 60, 60]), 'Upper': np.array([6, 255, 255])},
'yellow': {'Lower': np.array([15, 160, 50]), 'Upper': np.array([35, 255, 255])},
'green': {'Lower': np.array([50, 50, 50]), 'Upper': np.array([130, 255, 255])},
}
#目标颜色
target_color = ['green','yellow']
#创建摄像头
capture = cv2.VideoCapture(0)
#初始化保存图片的编号
count=0
#target_list=[]
while True:
#创建目标列表。注意一定要将其放入循环中,可以尝试一下将这一行注释掉,把目标列表建在外面,看看区别
target_list=[]
ret, img = capture.read()
draw_img = img
erode_hsv = good_thresh_img(img)
final_inRange_hsv = select_color_img(target_color,erode_hsv)
contours = extract_contour(final_inRange_hsv)
draw_img = find_target(contours,draw_img)
final_img = draw_center(target_list,draw_img)
cv2.imshow('final_img',final_img)
key = cv2.waitKey(1)
#保存截图或退出
if key == ord('s'): #按's'键保存截图
cv2.imwrite(r"D:lesson/"+str(count)+".jpg",final_img) #路径名+保存的图片以编号命名+要保存的图片
count+=1 #编号加一,实现连续截图
if key==27: #按Esc键退出
break
cv2.destroyAllWindows() #关闭展示窗口
capture.release() #释放摄像头,若不释放,程序结束后摄像头一直处于开启状态
问题总结:了解了视频的原理后,以为只要把每一帧处理好然后放入循环里就ok了,没想到实际操作起来还是会遇到问题。着重记一笔:上面创建的target_list一定要放在循环里,不然每一帧获取到的目标物体会累加在里面,最后展现的图像和返回的坐标会像重影一般给框出很多目标。而放入while循环里之后,每次循环都会重建一个target_list就相当于之前的给清零了。
回顾总结:到这里这个项目算是完成了,虽说是完成了,但是不够完善,也不够完美。主要的问题有:
1、只能识别单一背景下的目标气球,如果是拿到室外等背景比较复杂的多物体环境中就难以准确识别。
2、识别精确度低,因为采取颜色识别的方案,所以只要在颜色字典设置的阈值之内都会被认作是目标。
但是想要实现的基本功能都实现了,所以说还算凑合吧~
效果展示:
继续努力,继续加油!