python+openCV使用SIFT算法实现印章的总相似度检测

python实现,使用SIFT算法和文字相似度检测算法,并使用了pyqt5做的印章相似度检测工具,还有很大优化空间,对于我这水平费了不少力气,记录一下。

首先整体流程是预建了一个印章库,包含若干张图片。目的是输入一张印章图片,与库里图片对比,最终显示相似度最高的三张。记一下关键代码。
python+openCV使用SIFT算法实现印章的总相似度检测_第1张图片

1.图像预处理

主要是红色区域提取、常规灰度二值、对于形态不好的图片做个腐蚀啥的。

def GetRed(img):
    """
    提取图中的红色部分
    """
    # 转化为hsv空间
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # 颜色在HSV空间下的上下限156-180还能改成0-10
    low_hsv = np.array([156, 43, 46])
    high_hsv = np.array([180, 255, 255])

    # 使用opencv的inRange函数提取颜色
    mask = cv2.inRange(hsv, lowerb=low_hsv, upperb=high_hsv)
    Red = cv2.bitwise_and(img, img, mask=mask)

    return Red

2.做一个霍夫圆打开,方便后续文字识别

# 霍夫圆检测
def houghCircle(src):
    gray = cv2.medianBlur(src, 3)
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, \
                               100, param1=200, param2=30, minRadius=200, maxRadius=300)
    isNG = False
    if circles is None:
        print("找圆失败")
    else:
        circles = np.uint16(np.around(circles))
        a, b, c = circles.shape
        for i in range(b):
            cv2.circle(src, (circles[0][i][0], circles[0][i][1]), circles[0][i][2], (0, 0, 255), 3, cv2.LINE_AA)
            cv2.circle(src, (circles[0][i][0], circles[0][i][1]), 2, (0, 255, 0), 3,
                       cv2.LINE_AA)  # draw center of circle

    x = circles[0][i][0] - circles[0][i][2]
    y = circles[0][i][1] - circles[0][i][2]
    w = h = 2 * circles[0][i][2]
    center = (circles[0][i][0], circles[0][i][1])
    radius = circles[0][i][2]
    c = 2 * np.math.pi * radius
    print(c, radius)

    ROI = src[y:y + h, x:x + h].copy()
    trans_center = (center[0] - x, center[1] - y)
    polarImg = cv2.warpPolar(ROI, (int(radius), int(c)), trans_center, radius, cv2.INTER_LINEAR + cv2.WARP_POLAR_LINEAR)
    polarImg = cv2.flip(polarImg, 1)  # 镜像
    polarImg = cv2.transpose(polarImg)  # 转置
    # cv2.imshow('polarImg', polarImg)
    cv2.imwrite('polarImg.png', polarImg)
    return src

3.构建图像标准名称库

# 获取标准库txt数据
        txtData = openreadtxt('../trainText/Imglist.txt')

4.识别文字

识别文字部分使用的是PaddleOCR

def paddleOcr(src):
    ocr = PaddleOCR(use_angle_cls=True, lang='ch')  # need to run only once to download and load model into memory
    img_path = src
    result = ocr.ocr(img_path, cls=True)
    # print('--------------------------result-----------------------------------')
    # print(result)
    # print('--------------------------line-----------------------------------')
    for idx in range(len(result)):
        res = result[idx]
        for line in res:
            print(line)
    result = result[0]
    image = Image.open(img_path).convert('RGB')
    boxes = [line[0] for line in result]
    txts = [line[1][0] for line in result]
    scores = [line[1][1] for line in result]
    # print('--------------------------boxes-----------------------------------')
    # print(boxes)
    # print('--------------------------txts-----------------------------------')
    # print(txts)
    # print('--------------------------scores-----------------------------------')
    # print(scores)

    im_show = draw_ocr(image, boxes, txts, scores)
    im_show = Image.fromarray(im_show)
    im_show.save('result.jpg')
    return txts

5.计算一下文字的相似度

 # 计算文字相似度
        for i in range(len(txtData)):
            Str = txtData[i]
            s1 = textRes

            txt_replace = str(txtData[i]).replace('[', '')
            txt_replace = txt_replace.replace(']', '')
            txt_replace = txt_replace.replace("'", '')
            imgPath = '../trainImg/' + txt_replace + '.jpg'
            simPic = matplotlib2opencv(imgPath)
            simPic_resize = cv2.resize(simPic, (500, 500))
            print('----------------------文字相似度-----------------------------')
            sim = difflib.SequenceMatcher(None, str(Str), str(s1)).quick_ratio()
            print(sim)

6.很常规的图片相似度检测(SIFT)

def picRec(image_label, image_rec):
    # 预处理
    imgRec_res = cv2.resize(image_rec, (image_label.shape[1], image_label.shape[0]))
    imgRec_gray = imgToGray(imgRec_res)

    # 关键点检测
    kp1, des1 = getKeyPoint(image_label)
    kp2, des2 = getKeyPoint(imgRec_gray)
    print("图片1的关键点数目:" + str(len(kp1)))
    print("图片2的关键点数目:" + str(len(kp2)))

    # 绘制
    # imgCir1 = cv2.drawKeypoints(img1, kp1, img1_gray, color=(255, 0, 255))  # 画出特征点,并显示为红色圆圈
    # imgCir2 = cv2.drawKeypoints(img2, kp2, img2_gray, color=(255, 0, 255))  # 画出特征点,并显示为红色圆圈

    # BFMatcher解决匹配
    bf = cv2.BFMatcher()
    matches = bf.knnMatch(des1, des2, k=2)
    # print(matches)
    # print(len(matches))
    # 调整ratio
    good = []
    for m, n in matches:
        if m.distance < 0.9 * n.distance:
            good.append([m])
    print("总体特征数量:" + str(len(matches)))
    print("相似特征数量:" + str(len(good)))
    imgSim = len(good) / len(kp1) * 100
    print("图片相似度为:" + str(imgSim) + str('%'))
    return imgSim

7.最后就是在pyqt上显示图片,像我如果要显示前三张,就需要写三段下面的代码,放入不同的QGraphicsVies里就行了。

  # 图片显示
        txt_replace1 = str(textArr[0][0]).replace('[', '')
        txt_replace1 = txt_replace1.replace(']', '')
        txt_replace1 = txt_replace1.replace("'", '')
        print(txt_replace1)
        path = '../trainImg/' + txt_replace1 + '.jpg'
        img_1 = QtGui.QPixmap(path).scaled(self.graphicsView_2.width(), self.graphicsView_2.height())
        # 在QGraphicsView控件上显示选择的图片
        scene1 = QtWidgets.QGraphicsScene()
        scene1.addPixmap(img_1)  # 將图片加入 scene
        self.graphicsView_2.setScene(scene1)  # 设定 QGraphicsView 的场景為 scene
        self.label_2.setText(str(round(textArr[0][3], 1)) + '%')

7.整理记录时候发现,真的有很多能优化的地方,慢慢学,慢慢写吧。

你可能感兴趣的:(opencv,python,opencv,算法)