PyQt5之QGraphics 011 QGraphicsItem之绘画OpenCV contours

本文介绍如何使用QPainterPath结合OpenCV的findContours功能,在Qt环境中绘制图像的轮廓线。通过调整ROI区域,可以精确显示所需部分的轮廓,并通过按钮控制实现交互式调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QPainterPath可以画出各种各样的图形,以下就是画OpenCV的findcontours的轮廓线。

左上角显示区域所有contours的数量。

先用findContours找到轮廓线,之后就可以用moveTo一点一点画出来。代码如下:

"""
有趣的事情
没有结束
2020/4/6 15:53
"""
from PyQt5.QtWidgets import (QApplication, QGraphicsItem, QGraphicsScene, QGraphicsView,
                             QPushButton, QLabel, QDialog, QHBoxLayout, QVBoxLayout)
from PyQt5.QtGui import (QBrush, QPen, QPixmap, QPicture, QImage, QPainterPath)
from PyQt5.QtCore import (QPoint, QPointF, QLine, QLineF, QRect, QRectF, Qt)
import numpy as np
import cv2 as cv
import random


class Shape(QGraphicsItem):
    def __init__(self):
        super(Shape, self).__init__()
        self.path = QPainterPath()
        self.ROIx1 = 20
        self.ROIy1 = 30
        self.ROIx2 = 200
        self.ROIy2 = 300
        self.indexStr = "0"
        self.cvimage = cv.imread("d:/pic/lena.jpg", cv.IMREAD_GRAYSCALE)
        width, height = self.cvimage.shape[0:2]
        self.w = width
        self.h = height
        self.setContours()

    def updateCountour(self, x, y):
        if ((self.ROIx1 + x) < 10) | ((self.ROIy1 + y) < 10) | \
                ((self.ROIx2 + x) > self.h - 10) | ((self.ROIy2 + y) > self.w - 10):
            print("out!")
            return
        self.ROIx1 += x
        self.ROIy1 += y
        self.ROIx2 += x
        self.ROIy2 += y
        self.path = QPainterPath()
        self.prepareGeometryChange()
        self.setContours()

    def setContours(self):
        imgROI = self.cvimage[self.ROIx1:self.ROIx2, self.ROIy1:self.ROIy2]
        imgBlur = cv.blur(imgROI, (3, 3))
        ret, thresh = cv.threshold(imgBlur, 127, 255, 0)
        imgCanny = cv.Canny(thresh, 120, 120)
        contours, hierarchy = cv.findContours(imgCanny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

        if len(contours) < 1:
            exit(1)

        imgDrawEx = np.empty((self.w, self.h, 3), np.uint8)
        imgDrawEx[:] = 0
        imgDraw = imgDrawEx[self.ROIx1:self.ROIx2, self.ROIy1:self.ROIy2]

        count = 0
        index = []
        for cnt in contours:
            if cv.arcLength(cnt, True) > 30:
                count += 1
                cv.drawContours(imgDraw, [cnt], -1,
                                (random.randint(100, 255), random.randint(100, 255), random.randint(100, 255)), 1)
                index.append(cnt)

        if len(index) < 1:
            exit(1)

        self.indexStr = str(count)

        contoursCount = len(index)

        for selectIndex in range(contoursCount):
            if len(index[selectIndex]) < 1:
                exit(1)

            self.path.moveTo(index[selectIndex][0][0][0]+self.ROIy1, index[selectIndex][0][0][1]+self.ROIx1)
            for i in index[selectIndex]:
                self.path.lineTo(i[0][0]+self.ROIy1, i[0][1]+self.ROIx1)

    def boundingRect(self):
        return QRectF(0, 0, self.w, self.h)

    def paint(self, painter, option, widget=None):
        image = QImage("d:/pic/lena.jpg")
        painter.drawImage(QPoint(0, 0), image)
        painter.setPen(Qt.NoPen)
        painter.setPen(QPen(Qt.green, 1))
        painter.drawPath(self.path)
        painter.setPen(Qt.NoPen)
        painter.setPen(QPen(Qt.black, 2))
        painter.drawText(QPointF(10, 10), "count: " + self.indexStr)


class Scene(QGraphicsScene):
    def __init__(self):
        super(Scene, self).__init__()


class View(QGraphicsView):
    def __init__(self):
        super(View, self).__init__()


class Form(QDialog):
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
        self.shape = Shape()
        self.scene = Scene()
        self.scene.addItem(self.shape)
        self.view = View()
        self.view.setScene(self.scene)
        self.button1 = QPushButton(self)
        self.button1.setText("X+")
        self.button2 = QPushButton(self)
        self.button2.setText("X-")
        self.button3 = QPushButton(self)
        self.button3.setText("Y+")
        self.button4 = QPushButton(self)
        self.button4.setText("Y-")
        self.button1.clicked.connect(self.clicked_btn1)
        self.button2.clicked.connect(self.clicked_btn2)
        self.button3.clicked.connect(self.clicked_btn3)
        self.button4.clicked.connect(self.clicked_btn4)
        self.buttonLayout = QHBoxLayout()
        self.buttonLayout.addWidget(self.button1)
        self.buttonLayout.addWidget(self.button2)
        self.buttonLayout.addWidget(self.button3)
        self.buttonLayout.addWidget(self.button4)
        self.layout = QVBoxLayout()
        self.layout.addLayout(self.buttonLayout)
        self.layout.addWidget(self.view)
        self.setLayout(self.layout)
        self.setWindowTitle("Contours")

    def clicked_btn1(self):
        self.shape.updateCountour(10, 0)

    def clicked_btn2(self):
        self.shape.updateCountour(-10, 0)

    def clicked_btn3(self):
        self.shape.updateCountour(0, 10)

    def clicked_btn4(self):
        self.shape.updateCountour(0, -10)


if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)

    form = Form()
    form.show()

    sys.exit(app.exec_())

通过X+,X-,Y+,Y-控制ROI区域,可以显示我们要的地方的轮廓线。

通过改变ROI可以见到如下效果:

多谢,美美。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值