首先需求是:一个名为draw_rect(pic),将传过来的图片对象,根据设定的颜色范围,画出这个颜色范围内图片中存在的最大矩形,并将矩形在图片中的x,y坐标,矩形的大小w,h返回

比如,我是想将jx3中科举界面的矩形画出,然后根据比例计算出问题所在的位置科举答题器画出科举界面的矩形

Setp1.获取科举界面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值

Step2.根据得到的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)

Setp3.根据设定好的颜色范围调用OpenCV的 inRange 函数

mask = cv2.inRange(hsv, lower, upper)
cv2.imshow('Mask', mask)


科举答题器HSV滤色

可以看到其他的颜色都被去除了,但需要注意的是,如果用户使用Win7系统,并且主题设置为经典主题,会导致软件的背景色和科举界面的背景色过于接近,没能去除。但科举界面比软件界面大,因此选出最大的矩形即可解决

不过首先,我们还是需要填充中心、去除噪声

Step4.填充中心和去噪

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)


科举答题器滤色后去噪

可以看到,只剩下两个矩形了,那么接下来寻找轮廓并画出就可以了

Step5.寻找轮廓并画出矩形

# 寻找轮廓
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)

OpenCV滤色后画出所有符合的矩形

至此,就大概完成了。矩形的信息存在 contours 中

但我是要画出最大的矩形,并且返回x,y,w,h

Setp6.找出最大的矩形,并返回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[i])
            if w * h > 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[0]), y + int(h * pic_ratio[1])), (x + int(w * pic_ratio[2]), y + int(h * pic_ratio[3])), (0, 0, 255), 2)
        # # 显示结果
        cv2.imshow("result", img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    return (x, y, w, h);

科举答题器框选区域

可以看到,正好框柱了问题,至此,本文结束。