使用opencv查找特定颜色的矩形
首先需求是:一个名为draw_rect(pic),将传过来的图片对象,根据设定的颜色范围,画出这个颜色范围内图片中存在的最大矩形,并将矩形在图片中的x,y坐标,矩形的大小w,h返回
比如,我是想将jx3中科举界面的矩形画出,然后根据比例计算出问题所在的位置
获取科举界面HSV颜色值,该程序实现点击图片输出RGB/HSV值
# coding=utf-8
import cv2
# 读取图片并缩放
img = cv2.imread('test.jpg')
height, width = img.shape[:2]
size = (int(width/2), int(height/2))
# 缩放
img = cv2.resize(img, size, interpolation=cv2.INTER_AREA)
# BGR转化为HSV
HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 鼠标点击响应事件
def getposHsv(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
print("HSV is", HSV[y, x])
def getposBgr(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
print("Bgr is", img[y, x])
cv2.imshow("imageHSV", HSV)
cv2.imshow('image', img)
cv2.setMouseCallback("imageHSV", getposHsv)
cv2.setMouseCallback("image", getposBgr)
cv2.waitKey(0)
结果如下:
根据得到的HSV值设定颜色范围,并将待识别图片转为HSV格式
def draw_rect(pic):
# 颜色范围,这里我设置±10
lower = (16, 8, 206)
upper = (36, 28, 226)
img = cv2.imread(pic)
# 图片转成HSV格式
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
根据设定好的颜色范围调用OpenCV的 inRange 函数
mask = cv2.inRange(hsv, lower, upper)
cv2.imshow('Mask', mask)
可以看到其他的颜色都被去除了,但需要注意的是,如果用户使用Win7系统,并且主题设置为经典主题,会导致软件的背景色和科举界面的背景色过于接近,没能去除。但科举界面比软件界面大,因此选出最大的矩形即可解决。不过在此之前,我们还是需要填充中心、去除噪声
填充中心和去噪
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25))
# 填充中心
closed = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# 执行50次形态学腐蚀与膨胀
closed = cv2.erode(closed, None, iterations=50)
closed = cv2.dilate(closed, None, iterations=50)
cv2.imshow('closed', closed)
可以看到,只剩下两个矩形了,那么接下来寻找轮廓并画出就可以了
寻找轮廓并画出矩形
# 寻找轮廓
contours, hierarchy = cv2.findContours(
closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
allResult = cv2.drawContours(img.copy(), contours, -1, (0, 0, 255), 2)
cv2.imshow('Allresult',allResult)
至此,就大概完成了。矩形的信息存在 contours 中,但我是要画出最大的矩形,并且返回x,y,w,h<
找出最大的矩形,并返回x,y,w,h
length = len(contours)
print(length)
# 如果长度为0,说明不存在,返回0,0,0,0
if length == 0:
x, y, w, h = 0, 0, 0, 0
else:
# 新建5个变量,存储最大矩形的面积,x,y,w,h
max_rectangle = 0
max_rectangle_x, max_rectangle_y, max_rectangle_w, max_rectangle_h = 0, 0, 0, 0
# 如果存在多个,则去最大的一个
for i in range(0, length):
x, y, w, h = cv2.boundingRect(contours&#91;i])
if w * h &amp;gt; max_rectangle:
max_rectangle = w * h
max_rectangle_x = x
max_rectangle_y = y
max_rectangle_w = w
max_rectangle_h = h
x, y, w, h = max_rectangle_x, max_rectangle_y, max_rectangle_w, max_rectangle_h
# 得到最大的矩形后,根据比例计算出科举问题的位置
cv2.rectangle(img, (x + int(w * pic_ratio&#91;0]), y + int(h * pic_ratio&#91;1])), (x + int(w * pic_ratio&#91;2]), y + int(h * pic_ratio&#91;3])), (0, 0, 255), 2)
# # 显示结果
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return (x, y, w, h);
可以看到,正好框柱了问题,至此,本文结束