在PyQt5中实施洪水填充

时间:2018-09-22 19:15:49

标签: python python-3.x user-interface pyqt5 paint

我正在尝试实现相当于Paint的功能,为此,我需要进行填充。谁能告诉我如何使用PyQt5找出像素的颜色,并使用宽度搜索来找到相似的像素。然后将所有这些像素更改为新的颜色。刚好在这个时候是getpixel和putpixel。我想知道PyQt5是否这样做。如果有,那么我要求显示一些实现此示例。

P.s。您可以不用寻找像素,而只需展示如何拍摄和更换像素即可。

P.s.s。如果出现问题,我为我的英语致歉с:

1 个答案:

答案 0 :(得分:2)

我有an implementation of a Paint program here,其中包含洪水填充的示例。

不幸的是,它比您想象的要复杂一些。您可以按照以下步骤从Qt中的QImage读取像素:

QImage.pixel(x, y)       # returns a QRgb object
QImage.pixelColor(x, y)  # returns a QColor object

基本算法

使用QImage.pixel(x,y)的基本林火填充算法如下所示。首先,将像素图转换为QImage(如有必要)。

    image = self.pixmap().toImage()
    w, h = image.width(), image.height()
    x, y = e.x(), e.y()

    # Get our target color from origin.
    target_color = image.pixel(x,y)

然后我们定义一个函数,该函数针对给定位置查看所有周围位置(如果尚未查看),并测试它是 hit 还是 miss 。如果成功,我们将存储该像素以备后用。

    def get_cardinal_points(have_seen, center_pos):
        points = []
        cx, cy = center_pos
        for x, y in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
            xx, yy = cx + x, cy + y
            if (xx >= 0 and xx < w and
                yy >= 0 and yy < h and
                (xx, yy) not in have_seen):

                points.append((xx, yy))
                have_seen.add((xx, yy))

        return points

要执行填充,我们创建一个QPainter以写入原始像素图。然后,从最初的x,y开始进行迭代,检查基数点,并且-如果我们有匹配项-将这些新平方推入队列。我们会随时填充所有匹配点。

    # Now perform the search and fill.
    p = QPainter(self.pixmap())
    p.setPen(QPen(self.active_color))

    have_seen = set()
    queue = [(x, y)]

    while queue:
        x, y = queue.pop()
        if image.pixel(x, y) == target_color:
            p.drawPoint(QPoint(x, y))
            queue.extend(get_cardinal_points(have_seen, (x, y)))

    self.update()

性能

QImage.pixel()可能会很慢,因此直接在QImage上进行读/写操作对于大图像来说实际上是不可行的。此后,将需要花费几秒钟的时间来填充该区域。

我使用的解决方案是将要填充的区域转换为bytes。每个像素有4个字节(RGBA)。这为我们提供了一个与之交互更快的数据结构。

    image = self.pixmap().toImage() # Convert to image if you have a QPixmap
    w, h = image.width(), image.height()
    s = image.bits().asstring(w * h * 4)

接下来,我们需要找到当前位置的3字节(RGB)值。通过我们的数据结构,我们创建了一个自定义函数来检索我们的命中/未命中字节。

    # Lookup the 3-byte value at a given location.
    def get_pixel(x, y):
        i = (x + (y * w)) * 4
        return s[i:i+3]

    x, y = e.x(), e.y()
    target_color = get_pixel(x, y)

搜索输入中所有点并在找到匹配项后将其写出到QPixmap的实际循环。

    # Now perform the search and fill.
    p = QPainter(self.pixmap())
    p.setPen(QPen(self.active_color))

    have_seen = set()
    queue = [(x, y)]

    while queue:
        x, y = queue.pop()
        if get_pixel(x, y) == target_color:
            p.drawPoint(QPoint(x, y))
            queue.extend(get_cardinal_points(have_seen, (x, y)))

    self.update()