一、前言
本内容为通过对opencv进行初步学习,结合python进行多种颜色的基本识别。
二、学习过程
1.颜色空间的转换
初学opencv,首先我对于图像进行了更深层的了解,对于灰度及彩色图像其内部的结构有了认识。之后便开始学习opencv的各种基本功能,如读取图像与视频,使用网络摄像头等等。
在初步了解掌握了opencv的基本函数后,对于颜色识别的学习开始于颜色空间的转换。
在日常生活中颜色空间大都是采用RGB的形式,RGB 适合于显示系统,却并不适合于图像处理,在opencv中采用BGR,HSV颜色空间,将RGB转化为HSV颜色空间则是我们进行颜色识别的基础。
HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)(参考百度)。在HSV模型中,颜色是由色相(Hue),饱和度(Saturation),明度(Value)共同组成。
进行不同颜色空间的转换,需要用到转换函数cv2.cvtColor(),如下图所示代码
import cv2
cv2.namedWindow('window',cv2.WINDOW_NORMAL)
cv2.resizeWindow('window',820,520)
img = cv2.imread("D:/opencv/aaaaa.jpg")
img_1=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图像
cv2.imshow('window',img_1)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
通过上述代码将彩色图像转换成了灰度图像
2.轨迹栏的使用
学习了颜色空间转换后,引入新的功能:轨迹栏的使用。主要两个函数:
cv2.createTrackbar(trackbarName, windowName, value, count, onChange)创建轨迹栏
主要参数:
trackbarName:轨迹栏名称
windowName:附加到的窗口名称
value:默认值
count:最大值
onChange:执行的回调函数每次跟踪栏值更改
cv2.getTrackbarPos(trackbarname, winname)获取轨迹栏的位置
trackbarname:轨迹栏名称
winname:附加到的窗口名称
代码展示:
import cv2
import numpy as np
cv2.namedWindow('window', cv2.WINDOW_NORMAL)
cv2.resizeWindow('window', 820, 520)
def void(value):
print(value)
# 创建颜色变化的轨迹栏
cv2.createTrackbar('R','window',0,255,void)
cv2.createTrackbar('G','window',0,255,void)
cv2.createTrackbar('B','window',0,255,void)
img=np.zeros((520,820,3),np.uint8)# 创建一个黑色的图像,一个窗口
while True:
# 得到四条轨迹的当前位置
r=cv2.getTrackbarPos('R','window')
g=cv2.getTrackbarPos('G','window')
b=cv2.getTrackbarPos('B','window')
img[:]=[b,g,r]
cv2.imshow('window', img)
key=cv2.waitKey(1)
if key==ord('q'):
break
cv2.destroyAllWindows()
运行结果:
如上图通过轨迹栏改变了BGR三通道值来显示不同颜色
3.Opencv 绘制线段、矩形、圆形、多边形操作
OpenCV提供了许多用于绘制图形的方法,包括绘制线段的line()方法、绘制矩形的 rectangle()方法、绘制圆形的 circle()方法、绘制多边形的 polylines()方法和绘制文字的 putText()方法等等
通过学习绘制图形,使得我们可以在图片,视频的基础上添加我们想要的操作。
代码示例:
import cv2
import numpy as np
cv2.namedWindow('ww',cv2.WINDOW_NORMAL)
cv2.resizeWindow('ww',820,420)
img=cv2.imread("D:/opencv/sy.jpg")
width,height=640,480
cv2.line(img,[0,0],[1957,1227],[0,250,0],2)
cv2.rectangle(img,[0,0],[435,876],[250,0,0],2)
cv2.circle(img,[990,596],30,[255,255,0],3)
cv2.putText(img,"Shandong Agricultural University ",(655,236),cv2.FONT_HERSHEY_COMPLEX,2,[54,66,0],2)
p1=np.float32([[849,120],[1132,110],[849,592],[1132,592]])
p2=np.float32([[0,0],[width,0],[0,height],[width,height]])
m=cv2.getPerspectiveTransform(p1,p2)
img_1=cv2.warpPerspective(img,m,(width,height))
cv2.imshow('ww',img)
cv2.imshow('wqw',img_1)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
4.色彩空间转换,利用inrange函数过滤视频中的颜色,实现跟踪某一颜色
要想进行颜色识别,对于特定颜色进行分辨,需要了解各种颜色的对应范围
cv2.inRange()函数的作用是:可以提取你想要的颜色,并把该颜色的区域设置为白色,其余的设置为黑色。
其实原理是这样的:在RGB三通道图像中,该函数会让你输入一个低值数组和高值数组,然后这个函数会扫描图片的每个像素,每个像素的值,即这个数组的每个值,如果相对应的,都在两个你输入的数组的,相对应的位置的数值内,那么这个数值会被设置为白色。否则只要有一个不在这个范围内,那么就会设置为黑色。
可以通过下表对应颜色的数值过滤其他颜色
HSV颜色对应RGB的分量范围:
import cv2
import numpy as np
def back(value):
pass
cv2.namedWindow('ww',cv2.WINDOW_NORMAL)
cv2.resizeWindow('ww',820,420)
cv2.namedWindow('waw',cv2.WINDOW_NORMAL)
cv2.resizeWindow('waw',820,420)
cv2.namedWindow('wzw',cv2.WINDOW_NORMAL)
cv2.resizeWindow('wzw',820,420)
cv2.namedWindow('mask',cv2.WINDOW_NORMAL)
cv2.resizeWindow('mask',820,420)
img=cv2.imread("D:/opencv/aaaaa.jpg")
imghsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
cv2.createTrackbar('a','ww',42,179,back)
cv2.createTrackbar('b','ww',179,179,back)
cv2.createTrackbar('c','ww',49,255,back)
cv2.createTrackbar('d','ww',255,255,back)
cv2.createTrackbar('e','ww',112,255,back)
cv2.createTrackbar('f','ww',255,255,back)
while True:
a=cv2.getTrackbarPos('a','ww')
b=cv2.getTrackbarPos('b','ww')
c=cv2.getTrackbarPos('c','ww')
d=cv2.getTrackbarPos('d','ww')
e=cv2.getTrackbarPos('e','ww')
f=cv2.getTrackbarPos('f','ww')
lower=np.array([a,c,e])
upper=np.array([b,d,f])
mask=cv2.inRange(imghsv,lower,upper)
imgmask=cv2.bitwise_and(img,img,mask=mask)
cv2.imshow('waw',img)
cv2.imshow('wzw',imghsv)
cv2.imshow('mask',imgmask)
k= cv2.waitKey(1)
if k==ord('q'):
break
cv2.destroyAllWindows()
运行结果:
三、问题与解决方法
在刚开始着手颜色识别时,通过这几天的学习,我原计划通过inrange函数将颜色分隔,对于特定颜色进行识别,起初进展顺利,对于单一颜色识别成功但若实现画面内多种颜色识别,我考虑使用for 循环遍历颜色列表,但运行发现中心远点的颜色始终为单一颜色,后来添加count使其自加解决问题,后来运行发现在画面中出现多个颜色但太过杂乱,我便想改变方法,通过中心点对于物体颜色进行识别并通过puttext将物体颜色展示。
四、代码展示
import cv2
import numpy as np
height=640
width=480
vc=cv2.VideoCapture(0)#打开摄像头
vc.set(3,height)
vc.set(4,width)
while vc.isOpened():
ret,img=vc.read()
imghsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
x=int(height/2)
y=int(width/2)
center=imghsv[x,y]
hue=center[0]
color ='wu'
if hue<20:
color="red"
if 30<=hue < 45:
color = "yellow"
if 45<=hue < 90:
color = "green"
if 90<=hue < 150:
color = 'blue'
if 150<=hue < 175:
color = 'purple'
if 175<=hue < 200:
color = 'pink'
centerbgr=img[x,y]
b,g,r=int(centerbgr[0]),int(centerbgr[1]),int(centerbgr[2])
cv2.circle(img,(x,y),5,(b,g,r),cv2.FILLED)
cv2.putText(img,str(color),(10,70),cv2.FONT_HERSHEY_COMPLEX,3,(b,g,r),2)
if not ret:
break
cv2.imshow('window',img)
k=cv2.waitKey(100)
if k==ord('q'):
break
vc.release()
cv2.destroyAllWindows()
五、识别结果
在更加深入地使用OpenCV实现颜色识别。如车牌,人脸识别时,在这个过程中,我遇到了许多挑战,比如如何准确地提取出区域、如何在不同光照条件下保持识别的稳定性等。通过不断地调试和优化代码,我逐渐掌握了利用阈值分割、形态学操作等方法来改进颜色识别的技巧。最终,当我的程序能够准确地识别颜色时,那种成就感无以言表。