簡體   English   中英

在PyQt5中實施洪水填充

[英]Implementing flood fill in PyQt5

我正在嘗試實現相當於Paint的功能,為此,我需要進行填充。 誰能告訴我如何使用PyQt5找出像素的顏色,並使用寬度搜索來找到相似的像素。 然后將所有這些像素更改為新的顏色。 剛好在這個時候是getpixel和putpixel。 我想知道PyQt5是否這樣做。 如果有,那么我要求顯示一些實現此示例。

Ps您可以不用尋找像素,而只需顯示如何拍攝和更換像素。

附言:如果出現問題,我為我的英語致歉。

在這里有一個Paint程序的實現,其中包括泛洪填充的示例。

不幸的是,它比您想象的要復雜一些。 您可以按照以下步驟從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)

然后,我們定義一個函數,該函數針對給定位置查看所有周圍位置(如果尚未查看過),並測試它是命中還是未命中 如果成功,我們將存儲該像素以備后用。

    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其寫出到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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM