利用python+opencv对某颜色范围进行识别
1、 Pycharm 开发环境
2、 Python 3.8.3
3、 opencv4 HSV基本颜色分量范围
其目标是为了检测颜色为黄色的物体,然后对其质心和轮廓标注出来。黄色设置的上下限来自转载博客 HSV基本颜色分量范围(侵权即删)
检测图像为下方(图片网上找到的,侵权即删):
程序比较简单,主要流程为:
Videocapture获取图像 --> set重置图像大小提高程序速度 --> cvtColor转换成hsv图像格式 --> inRange二值化 --> medianBlur中值滤波 --> erode腐蚀 --> dilate膨胀 --> findContours找轮廓 --> max找到最大的轮廓 --> minEnclosingCircle找到包含该轮廓最小的圆 --> moment计算矩 --> 由矩计算质心 --> 标注质心和圆
import cv2 as cv
import numpy as np
import matplotlib as plt
import imutils
colorLower = (26, 43, 46) # 二值化下限
colorUpper = (34, 255, 255) # 二值化上限
cap = cv.VideoCapture(0)
# cap.set(3, 320) # 为快速运算,把图片变成缩小成320*240
# cap.set(4, 240)
kerne = np.ones((10, 10), np.uint8) # 开运算参数
while True:
ret, frame = cap.read() # 读取图像
# cv.namedWindow('frame', cv.WINDOW_AUTOSIZE)
# cv.imshow('frame', frame)
hsv = cv.cvtColor(frame.copy(), cv.COLOR_BGR2HSV) # 转化成hsv格式
# cv.namedWindow('hsv', cv.WINDOW_AUTOSIZE)
# cv.imshow('hsv', frame)
mask = cv.inRange(hsv.copy(), colorLower, colorUpper) # 根据范围二值化
# cv.namedWindow('mask', cv.WINDOW_AUTOSIZE)
# cv.imshow('mask', mask)
# # ################## 先开运算再滤波测试 ###################
# opening = cv.morphologyEx(mask.copy(), cv.MORPH_OPEN, kerne)
# cv.namedWindow('opening', cv.WINDOW_AUTOSIZE)
# cv.imshow('opening', opening)
#
# median = cv.medianBlur(opening.copy(), 3)
# cv.namedWindow('median', cv.WINDOW_AUTOSIZE)
# cv.imshow('median', median)
# # ########################################################
median = cv.medianBlur(mask.copy(), 3) # 中值滤波 去掉椒盐噪点,参数3表示中值运算方块3*3
# cv.namedWindow('median', cv.WINDOW_AUTOSIZE)
# cv.imshow('median', median)
# # ########################### 开运算(先腐蚀再运算) ###########################
# opening = cv.morphologyEx(median.copy(), cv.MORPH_OPEN, kerne) # 进行开运算
# cv.namedWindow('opening', cv.WINDOW_AUTOSIZE)
# cv.imshow('opening', opening)
# # ####################################################################
# ########################### 先腐蚀再膨胀 ###########################
erode = cv.erode(mask.copy(), None, iterations=2)
dilate = cv.dilate(erode.copy(), None, iterations=2)
# cv.namedWindow('dilate', cv.WINDOW_AUTOSIZE)
# cv.imshow('dilate', dilate)
# 开运算去掉的比较多
# #####################################################################
# 找轮廓
cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[-2]
center = None
# 如果在图中找到一定的轮廓就进行计算,否则不进行计算
if len(cnts) > 0:
c = max(cnts, key=cv.contourArea) # 找到图像中最大的轮廓
((x, y), radius) = cv.minEnclosingCircle(c) # 找到最小的圆包含这个轮廓,返回坐标和半径
M = cv.moments(c) # 计算图像的矩
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])) # 通过矩计算图像的质心
# 判断以下他的半径,太小的话就认为是噪声,就忽略掉
if radius > 10:
cv.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 2) # 在检测到的轮廓周围画圆圈
cv.circle(frame, center, 5, (0, 0, 255), -1)
cv.namedWindow('frame', cv.WINDOW_AUTOSIZE)
cv.imshow('frame', frame)
if cv.waitKey(1) == 27: # 按下Esc键就停止
break
cap.release()
cv.destroyAllWindows()
(以下函数均为转载,侵权即删,(写的都特别好))
在这个程序中,有很多函数被注释掉,比如说开运算等等,这些都是在调试程序的时候,去看看最终的效果在目测的情况下到底是那种方法最好。要是你问我为啥这样弄,为啥滤波用中值滤波而不用高斯滤波,我只能说这是我调的结果。我掌握的知识还特别少,还不足以直接通过计算找到一个效果比较好的算法,目前还是停留在通过不断地调试,改变参数,查网上资料去找到一个识别度相对不错的流程。