之前写过一篇VC++中使用OpenCV进行颜色检测的博文,当然使用opencv-python库也可以实现。
在Python中使用opencv-python库进行颜色检测非常简单,首选读取一张彩色图像,并调用函数imgHSV = cv2.cvtColor(img,cv2.COLOR_BGR2HSV);
函数将原图img转换成HSV图像imgHSV,再设置好HSV三个分量的上限和下限值,调用inRange
函数imask = cv2.inRange(imgHSV,lower,upper)
将HSV色彩图像转换成掩码图,掩码图中只有黑白二值图像,从而达到颜色检测的目的。颜色检测通常可以用于物体检测和跟踪中,尤其在不同的图像和物体中根据特定的颜色去筛选出某个物体。
通过学习油管博主murtazahassan的视频LEARN OPENCV in 3 HOURS with Python | Including 3xProjects | Computer Vision,里面第7个OpenCV示例将到如何从一副兰博基尼的轿车图像中进行颜色检测,相关代码地址为:Learn-OpenCV-in-3-hours
/chapter7.py
如下所示:
import cv2
import numpy as np
def empty(a):
pass
def stackImages(scale,imgArray):
rows = len(imgArray)
cols = len(imgArray[0])
rowsAvailable = isinstance(imgArray[0], list)
width = imgArray[0][0].shape[1]
height = imgArray[0][0].shape[0]
if rowsAvailable:
for x in range ( 0, rows):
for y in range(0, cols):
if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv2.cvtColor( imgArray[x][y], cv2.COLOR_GRAY2BGR)
imageBlank = np.zeros((height, width, 3), np.uint8)
hor = [imageBlank]*rows
hor_con = [imageBlank]*rows
for x in range(0, rows):
hor[x] = np.hstack(imgArray[x])
ver = np.vstack(hor)
else:
for x in range(0, rows):
if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
hor= np.hstack(imgArray)
ver = hor
return ver
path = 'Resources/lambo.png'
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars",640,240)
cv2.createTrackbar("Hue Min","TrackBars",0,179,empty)
cv2.createTrackbar("Hue Max","TrackBars",19,179,empty)
cv2.createTrackbar("Sat Min","TrackBars",110,255,empty)
cv2.createTrackbar("Sat Max","TrackBars",240,255,empty)
cv2.createTrackbar("Val Min","TrackBars",153,255,empty)
cv2.createTrackbar("Val Max","TrackBars",255,255,empty)
while True:
img = cv2.imread(path)
imgHSV = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("Hue Min","TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
print(h_min,h_max,s_min,s_max,v_min,v_max)
lower = np.array([h_min,s_min,v_min])
upper = np.array([h_max,s_max,v_max])
mask = cv2.inRange(imgHSV,lower,upper)
imgResult = cv2.bitwise_and(img,img,mask=mask)
# cv2.imshow("Original",img)
# cv2.imshow("HSV",imgHSV)
# cv2.imshow("Mask", mask)
# cv2.imshow("Result", imgResult)
imgStack = stackImages(0.6,([img,imgHSV],[mask,imgResult]))
cv2.imshow("Stacked Images", imgStack)
cv2.waitKey(1)
import cv2
import numpy as np
"""
@param scale: 图像缩放比例系数
@param imgArray: 二维图像数组
"""
def stackImages(scale,imgArray):
rows = len(imgArray)
cols = len(imgArray[0])
rowsAvailable = isinstance(imgArray[0], list)
width = imgArray[0][0].shape[1]
height = imgArray[0][0].shape[0]
if rowsAvailable:
for x in range ( 0, rows):
for y in range(0, cols):
if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv2.cvtColor( imgArray[x][y], cv2.COLOR_GRAY2BGR)
imageBlank = np.zeros((height, width, 3), np.uint8)
hor = [imageBlank]*rows
hor_con = [imageBlank]*rows
for x in range(0, rows):
hor[x] = np.hstack(imgArray[x])
ver = np.vstack(hor)
else:
for x in range(0, rows):
if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
hor= np.hstack(imgArray)
ver = hor
return ver
# 进度条回调函数
"""
@param val: 用户选择的当前进度条的数值
"""
def onValueChanged(val):
# print("val: ", val)
pass
# 颜色检测
path = "Resources/lambo.png"
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 640, 240) # 创建一个宽为640,高为200的,窗口名称为Trackbars的窗口
# 在窗口名称为Trackbars的窗口中创建一个名为Hue Min的滑动条,最小值默认为0,最大值为179,滑动条所在值即为hmin,用来控制H分量的最小值
cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Hue Max的滑动条,最小值默认为0,最大值为179,滑动条所在值即为hmax,用来控制H分量的最大值
cv2.createTrackbar("Hue Max", "TrackBars", 19, 179, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Sat Min的滑动条,最小值默认为0,最大值为255,滑动条所在值即为smin,用来控制S分量的最小值
cv2.createTrackbar("Sat Min", "TrackBars", 110, 255, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Sat Max的滑动条,最小值默认为0,最大值为255,滑动条所在值即为smax,用来控制S分量的最大值
cv2.createTrackbar("Sat Max", "TrackBars", 240, 255, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Val Min的滑动条,最小值默认为0,最大值为255,滑动条所在值即为vmin,用来控制V分量的最小值
cv2.createTrackbar("Val Min", "TrackBars", 153, 255, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Val Max的滑动条,最小值默认为0,最大值为255,滑动条所在值即为vmax,用来控制V分量的最大值
cv2.createTrackbar("Val Max", "TrackBars", 255, 255, onValueChanged)
# 循环检测用户操作,用户可以通过Trackbars窗口中的滑动条分别控制H、S、V三个分量的最小和最大值,从而控制mask以及Result图像的最终呈现
while True:
img = cv2.imread(path)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
print(h_min, h_max, s_min, s_max, v_min, v_max)
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
mask = cv2.inRange(imgHSV, lower, upper) # 根据lower和upper以及imgHSV图像生成mask图像
imgResult = cv2.bitwise_and(img, img, mask=mask)
# cv2.imshow("Original", img)
# cv2.imshow("HSV", imgHSV)
# cv2.imshow("Mask", mask)
# cv2.imshow("Result", imgResult)
imgStack = stackImages(0.6, ([img, imgHSV], [mask, imgResult]))
cv2.imshow("Stacked Images", imgStack)
cv2.waitKey(1)
cv2.destroyAllWindows()
matplotlib
库将多幅图像在一张图上显示当然我们可以替换掉上面的stackImages(scale,imgArray),借助
matplotlib`库将多幅图像在一张图上显示,相应的代码如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 进度条回调函数
"""
@param val: 用户选择的当前进度条的数值
"""
def onValueChanged(val):
# print("val: ", val)
pass
# 颜色检测
path = "Resources/lambo.png"
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 640, 240) # 创建一个宽为640,高为200的,窗口名称为Trackbars的窗口
# 在窗口名称为Trackbars的窗口中创建一个名为Hue Min的滑动条,最小值默认为0,最大值为179,滑动条所在值即为hmin,用来控制H分量的最小值
cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Hue Max的滑动条,最小值默认为0,最大值为179,滑动条所在值即为hmax,用来控制H分量的最大值
cv2.createTrackbar("Hue Max", "TrackBars", 19, 179, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Sat Min的滑动条,最小值默认为0,最大值为255,滑动条所在值即为smin,用来控制S分量的最小值
cv2.createTrackbar("Sat Min", "TrackBars", 110, 255, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Sat Max的滑动条,最小值默认为0,最大值为255,滑动条所在值即为smax,用来控制S分量的最大值
cv2.createTrackbar("Sat Max", "TrackBars", 240, 255, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Val Min的滑动条,最小值默认为0,最大值为255,滑动条所在值即为vmin,用来控制V分量的最小值
cv2.createTrackbar("Val Min", "TrackBars", 153, 255, onValueChanged)
# 在窗口名称为Trackbars的窗口中创建一个名为Val Max的滑动条,最小值默认为0,最大值为255,滑动条所在值即为vmax,用来控制V分量的最大值
cv2.createTrackbar("Val Max", "TrackBars", 255, 255, onValueChanged)
# 循环检测用户操作,用户可以通过Trackbars窗口中的滑动条分别控制H、S、V三个分量的最小和最大值,从而控制mask以及Result图像的最终呈现
while True:
img = cv2.imread(path)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
print(h_min, h_max, s_min, s_max, v_min, v_max)
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
imgMask = cv2.inRange(imgHSV, lower, upper) # 根据lower和upper以及imgHSV图像生成mask图像
imgResult = cv2.bitwise_and(img, img, mask=imgMask)
# cv2.imshow("Original", img)
# cv2.imshow("HSV", imgHSV)
# cv2.imshow("Mask", mask)
# cv2.imshow("Result", imgResult)
plt.figure(figsize=(8, 6))
plt.subplot(221), plt.axis('off'), plt.title("1.Original Image")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.subplot(222), plt.axis("off"), plt.title("2.HSV Image")
plt.imshow(cv2.cvtColor(imgHSV, cv2.COLOR_BGR2RGB))
plt.subplot(223), plt.axis("off"), plt.title("3.Mask Image")
plt.imshow(cv2.cvtColor(imgMask, cv2.COLOR_BGR2RGB))
plt.subplot(224), plt.axis("off"), plt.title("4.Result Image")
# plt.imshow(imgResult)
plt.imshow(cv2.cvtColor(imgResult, cv2.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()
cv2.waitKey(1)
cv2.destroyAllWindows()
在VScode
中运行结果如下图所示:
注意:由于python-opencv
中彩色图像默认是BGR
,matplotlib
库中默认是RGB
,所以使用matplotlib
库显示图像时,需要对原图像(BGR)使用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
函数进行转换,不然图像显示不正确。如下图所示: