颜色分辨
单个颜色识别
代码
import cv2
import numpy as np
def color(lower, upper, name):
Img = cv2.imread('image/origin/all.png') # 读入一幅图像
kernel_3 = np.ones((3, 3), np.uint8) # 3x3的卷积核
if Img is not None: # 判断图片是否读入
HSV = cv2.cvtColor(Img, cv2.COLOR_BGR2HSV) # 把BGR图像转换为HSV格式
# mask是把HSV图片中在颜色范围内的区域变成白色,其他区域变成黑色
if name == 'red':
mask = cv2.inRange(HSV, lower[:3], upper[:3])
mask = mask + cv2.inRange(HSV, lower[3:], upper[3:])
else:
mask = cv2.inRange(HSV, lower, upper)
# 下面四行是用卷积进行滤波
# erode()函数可以对输入图像用特定结构元素进行腐蚀操作,该结构元素确定腐蚀操作过程中的邻域的形状,
# 各点像素值将被替换为对应邻域上的最小值:
erosion = cv2.erode(mask, kernel_3, iterations=1)
erosion = cv2.erode(erosion, kernel_3, iterations=1)
# dilate()函数可以对输入图像用特定结构元素进行膨胀操作,该结构元素确定膨胀操作过程中的邻域的形状,
# 各点像素值将被替换为对应邻域上的最大值:
dilation = cv2.dilate(erosion, kernel_3, iterations=1)
dilation = cv2.dilate(dilation, kernel_3, iterations=1)
# target是把原图中的非目标颜色区域去掉剩下的图像
cv2.bitwise_and(Img, Img, mask=dilation)
# 将滤波后的图像变成二值图像放在binary中
ret, binary = cv2.threshold(dilation, 127, 255, cv2.THRESH_BINARY)
# 在binary中发现轮廓,轮廓按照面积从小到大排列
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for index, contour in enumerate(contours): # 遍历所有的轮廓
x, y, w, h = cv2.boundingRect(contour) # 将轮廓分解为识别对象的左上角坐标和宽、高
# 在图像上画上矩形(图片、左上角坐标、右下角坐标、颜色、线条宽度)
cv2.rectangle(Img, (x, y), (x + w, y + h), (0, 255,), 3)
# 给识别对象写上标号
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(Img, name + str(index+1), (x - 10, y + 10), font, 1, (0, 0, 255), 2) # 加减10是调整字符位置
print(name, '方块的数量是', len(contours), '个') # 终端输出目标数量
# cv2.imshow('target', target)
# cv2.imshow('Mask', mask)
# cv2.imshow("prod", dilation)
cv2.namedWindow('Img', 0)
cv2.imshow('Img', Img)
cv2.imwrite('./image/' + name + '.png', Img) # 将画上矩形的图形保存到当前目录
while True:
key = cv2.waitKey(10) & 0xFF
if key == 27 or cv2.getWindowProperty('Img', cv2.WND_PROP_VISIBLE) < 1.0:
break
if __name__ == '__main__':
# 下面两个值是要识别的颜色范围
lower_yellow = np.array([20, 20, 20]) # 黄色的下限
upper_yellow = np.array([30, 255, 255]) # 黄色上限
# color(lower_yellow, upper_yellow, 'yellow')
# 红色需要特殊处理
lower_red = np.array([0, 43, 46, 156, 43, 46]) # 红色阈值下界
higher_red = np.array([10, 255, 255, 180, 255, 255]) # 红色阈值上界
# color(lower_red, higher_red, 'red')
lower_green = np.array([35, 110, 106]) # 绿色阈值下界
higher_green = np.array([77, 255, 255]) # 绿色阈值上界
# color(lower_green, higher_green, 'green')
lower_blue = np.array([78, 43, 46]) # 蓝色阈值下界
upper_blue = np.array([110, 255, 255]) # 蓝色阈值下界
color(lower_blue, upper_blue, 'blue')
效果
多个颜色识别
代码
import cv2
import numpy as np
def bitwise_or_fun(masks):
if len(masks) <= 1:
return
mask = cv2.bitwise_or(masks[0], masks[1])
for i in range(2, len(masks)):
mask = cv2.bitwise_or(mask, masks[i])
def color(img):
colors, lower_highers = get_params()
frame = cv2.imread(img) # 读入一幅图像
font = cv2.FONT_HERSHEY_SIMPLEX
img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
masks = []
for index, lower_higher in enumerate(lower_highers):
lower_color = lower_higher[0]
higher_color = lower_higher[1]
if colors[index] == 'red':
mask = cv2.inRange(img_hsv, lower_color[:3], higher_color[:3]) # 可以认为是过滤出红色部分,获得红色的掩膜
mask = mask + cv2.inRange(img_hsv, lower_color[3:], higher_color[3:]) # 可以认为是过滤出红色部分,获得红色的掩膜
else:
mask = cv2.inRange(img_hsv, lower_color, higher_color)
mask = cv2.medianBlur(mask, 7) # 中值滤波
masks.append(mask)
bitwise_or_fun(masks)
cntss = []
for mask in masks:
cnts, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 轮廓检测
cntss.append(cnts)
for (colorname, cnts) in zip(colors, cntss):
for index, cnt in enumerate(cnts):
(x, y, w, h) = cv2.boundingRect(cnt) # 该函数返回矩阵四个点
# cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 0), 2) # 将检测到的颜色框起来
cv2.putText(frame, colorname + str(index + 1), (x, y - 5), font, 0.7, (0, 0, 0), 2)
cv2.drawContours(frame, cnts, -1, (0, 0, 0), 3)
# cv2.namedWindow('frame', 0)
cv2.imshow('frame', frame)
cv2.imwrite('image/frame.png', frame) # 将画上矩形的图形保存到当前目录
while True:
key = cv2.waitKey(10) & 0xFF
if key == 27 or cv2.getWindowProperty('frame', cv2.WND_PROP_VISIBLE) < 1.0:
break
def get_params():
# 下面两个值是要识别的颜色范围
lower_yellow = np.array([20, 20, 20]) # 黄色的下限
upper_yellow = np.array([30, 255, 255]) # 黄色上限
# 红色需要特殊处理
lower_red = np.array([0, 43, 46, 156, 43, 46]) # 红色阈值下界
higher_red = np.array([10, 255, 255, 180, 255, 255]) # 红色阈值上界
lower_green = np.array([35, 110, 106]) # 绿色阈值下界
higher_green = np.array([77, 255, 255]) # 绿色阈值上界
lower_blue = np.array([78, 43, 46]) # 蓝色阈值下界
upper_blue = np.array([110, 255, 255]) # 蓝色阈值下界
# 下面两个值是要识别的颜色范围
lower_purple = np.array([125, 43, 46]) # 紫色的下限
upper_purple = np.array([155, 255, 255]) # 紫色上限
params = []
colors = []
params.append([lower_red, higher_red]);colors.append('red')
params.append([lower_yellow, upper_yellow]);colors.append('yellow')
params.append([lower_green, higher_green]);colors.append('green')
params.append([lower_blue, upper_blue]);colors.append('blue')
params.append([lower_purple, upper_purple]);colors.append('purple')
return colors, params
if __name__ == '__main__':
color('./image/origin/all.png')
效果
模板匹配+颜色识别
源码
import cv2
import numpy as np
def bitwise_or_fun(masks):
if len(masks) <= 1:
return
mask = cv2.bitwise_or(masks[0], masks[1])
for i in range(2, len(masks)):
mask = cv2.bitwise_or(mask, masks[i])
def match_color(img,template):
positions = match(img, template)
colors, lower_highers = get_params()
frame = cv2.imread(img) # 读入一幅图像
font = cv2.FONT_HERSHEY_SIMPLEX
img_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
masks = []
for index, lower_higher in enumerate(lower_highers):
lower_color = lower_higher[0]
higher_color = lower_higher[1]
if colors[index] == 'red':
mask = cv2.inRange(img_hsv, lower_color[:3], higher_color[:3]) # 可以认为是过滤出红色部分,获得红色的掩膜
mask = mask + cv2.inRange(img_hsv, lower_color[3:], higher_color[3:]) # 可以认为是过滤出红色部分,获得红色的掩膜
else:
mask = cv2.inRange(img_hsv, lower_color, higher_color)
mask = cv2.medianBlur(mask, 7) # 中值滤波
masks.append(mask)
bitwise_or_fun(masks)
cntss = []
for mask in masks:
cnts, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 轮廓检测
cntss.append(cnts)
for (colorname, cnts) in zip(colors, cntss):
index = 0
for cnt in cnts:
(x, y, w, h) = cv2.boundingRect(cnt) # 该函数返回矩阵四个点
for position in positions:
(x1, y1, w1, h1) = position
if x >= x1 and y >= y1 and x + w <= x1 + w1 and y + h <= y1 + h1:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 0), 2) # 将检测到的颜色框起来
cv2.putText(frame, colorname + str(index + 1), (x, y - 5), font, 0.7, (0, 0, 0), 2)
index = index + 1
break
# 可以进行拉伸图片
# cv2.namedWindow('frame', 0)
cv2.imshow('frame', frame)
while True:
key = cv2.waitKey(10) & 0xFF
if key == 27 or cv2.getWindowProperty('frame', cv2.WND_PROP_VISIBLE) < 1.0:
break
def get_params():
# 下面两个值是要识别的颜色范围
lower_yellow = np.array([20, 20, 20]) # 黄色的下限
upper_yellow = np.array([30, 255, 255]) # 黄色上限
# 红色需要特殊处理
lower_red = np.array([0, 43, 46, 156, 43, 46]) # 红色阈值下界
higher_red = np.array([10, 255, 255, 180, 255, 255]) # 红色阈值上界
lower_green = np.array([35, 110, 106]) # 绿色阈值下界
higher_green = np.array([77, 255, 255]) # 绿色阈值上界
lower_blue = np.array([78, 43, 46]) # 蓝色阈值下界
upper_blue = np.array([110, 255, 255]) # 蓝色阈值下界
# 下面两个值是要识别的颜色范围
lower_purple = np.array([125, 43, 46]) # 紫色的下限
upper_purple = np.array([155, 255, 255]) # 紫色上限
params = []
colors = []
params.append([lower_red, higher_red]);colors.append('red')
params.append([lower_yellow, upper_yellow]);colors.append('yellow')
params.append([lower_green, higher_green]);colors.append('green')
params.append([lower_blue, upper_blue]);colors.append('blue')
params.append([lower_purple, upper_purple]);colors.append('purple')
return colors, params
def match(img_src, template_src):
img = cv2.imread(img_src)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.imread(template_src, 0)
h, w = template.shape[:2]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
loc = np.where(res >= threshold)
position = []
for pt in zip(*loc[::-1]): # *号表示可选参数
position.append([pt[0], pt[1], w, h])
return position
if __name__ == '__main__':
img = 'color2.png'
template = 'tmp2.png'
match_color(img,template)
效果
注意:模板和图片中的大小应当一直
如果需要不一致的请看下面的升级版本
当模板和图片中的大小不一致的时候,就无法识别
模板匹配+颜色识别升级
代码
- get_params() 要进行识别的颜色
- def match(img_src, template_src, wh, ratio)
wh为图片的宽和高,ratio为宽高比例
import cv2
import numpy as np
from imutils import contours
# 传入一个轮廓计算面积
def contourArea(cnt):
rect = cv2.minAreaRect(cnt) # 最小外接矩形
box = cv2.boxPoints(rect)
box = np.int0(box)
return cv2.contourArea(box)
# 绘图展示
def cv_show(name, img):
# cv2.namedWindow(name, 0)
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 初始化颜色参数
def get_params():
# 下面两个值是要识别的颜色范围
lower_yellow = np.array([20, 20, 20]) # 黄色的下限
upper_yellow = np.array([30, 255, 255]) # 黄色上限
lower_green = np.array([35, 110, 106]) # 绿色阈值下界
higher_green = np.array([77, 255, 255]) # 绿色阈值上界
lower_blue = np.array([78, 43, 46]) # 蓝色阈值下界
upper_blue = np.array([110, 255, 255]) # 蓝色阈值下界
# 下面两个值是要识别的颜色范围
lower_purple = np.array([125, 43, 46]) # 紫色的下限
upper_purple = np.array([155, 255, 255]) # 紫色上限
# 红色需要特殊处理
lower_red = np.array([0, 43, 46, 156, 43, 46]) # 红色阈值下界,
higher_red = np.array([10, 255, 255, 180, 255, 255]) # 红色阈值上界
params = []
colors = []
# 进行要识别颜色的添加
params.append([lower_red, higher_red]);colors.append('red')
params.append([lower_yellow, upper_yellow]);colors.append('yellow')
params.append([lower_green, higher_green]);colors.append('green')
params.append([lower_blue, upper_blue]);colors.append('blue')
params.append([lower_purple, upper_purple]);colors.append('purple')
return colors, params
def match_color(img1):
img_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
colors, lower_highers = get_params()
max = 0
i = -1
for index, lower_higher in enumerate(lower_highers):
area = 0
lower_color = lower_higher[0]
higher_color = lower_higher[1]
if colors[index] == 'red':
mask = cv2.inRange(img_hsv, lower_color[:3], higher_color[:3]) # 可以认为是过滤出红色部分,获得红色的掩膜
mask = mask + cv2.inRange(img_hsv, lower_color[3:], higher_color[3:]) # 可以认为是过滤出红色部分,获得红色的掩膜
else:
mask = cv2.inRange(img_hsv, lower_color, higher_color)
mask = cv2.medianBlur(mask, 7) # 中值滤波
cnts, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # 轮廓检测
if len(cnts) > 0:
for cnt in cnts:
area = area + contourArea(cnt)
# area = area+cv2.contourArea(cnt)
if area > max:
max = area
i = index
# print(max, colors[i])
# print("=======================================================")
if i > -1:
return colors[i]
else:
return "no"
# wh为图片的宽和高,ratio为宽高比例
def match(img_src, template_src, wh, ratio):
# 模板处理,固定大小
template = cv2.imread(template_src)
ref = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
# 二值图像
ref = cv2.threshold(ref, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
template = cv2.resize(ref, (wh[0], wh[1]))
# cv_show('ref', template)
# 图像处理
img = cv2.imread(img_src)
# 读取输入图像,预处理
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
# 边缘检测第一种方法
# thresh = cv2.Canny(gray, 10, 200)
# 边缘检测第二种方法(105-118行)
# Sobel算子检测元素的边缘
gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1) # ksize=-1相当于用3*3的
gradX = cv2.convertScaleAbs(gradX)
gradY = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=-1)
gradY = cv2.convertScaleAbs(gradY)
grad = cv2.addWeighted(gradX, 0.5, gradY, 0.5, 0)
# cv_show("grad", grad)
(minVal, maxVal) = (np.min(grad), np.max(grad))
grad = (255 * ((grad - minVal) / (maxVal - minVal)))
grad = grad.astype("uint8")
# 阈值设定,THRESH_OTSU会自动寻找合适的阈值,适合双峰,
thresh = cv2.threshold(grad, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show("thresh", thresh)
# 轮廓检测
cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cur_img = img.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
cv_show("cur_img", cur_img)
# 遍历每一个轮廓中的样本
for (i, c) in enumerate(cnts):
# 计算矩形
(x, y, w, h) = cv2.boundingRect(c)
ar = w / float(h)
# 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
if ratio[0] < ar < ratio[1]:
if (30 < w) and (30 < h):
# 符合的留下来
roi = gray[y - 5:y + h + 5, x - 5:x + w + 5]
roi = cv2.resize(roi, (wh[0], wh[1]))
res = cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED)
# cv_show("roi", roi)
if res >= 0.5:
# 画出来
name = match_color(img[y - 5:y + h + 5, x - 5:x + w + 5])
print(res, name)
# print(res, name + str(i))
print("=======================================================")
cv2.rectangle(img, (x - 5, y - 5), (x + w + 5, y + h + 5), (0, 0, 255), 1)
# cv2.putText(img, name + str(i), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
cv2.putText(img, name, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
cv_show("img", img)
cv2.imwrite('img.png', img)
if __name__ == '__main__':
img = './image/testt.png'
template = './image/test33_tmp.png'
match(img, template, [30, 90], [0.3, 0.45])
效果
原图
testt.png
test33_tmp.png
color2.png
temp2.png
all.png
实际项目
实际项目中干扰太大效果不佳
更好的效果请查看 目标检测算法deformable detr
原图
control-light.jpg
c2.png