如何在PyQt中使用QImage直接写入像素数据?

时间:2019-06-24 21:19:00

标签: python pyqt

我试图用PyQt5编写一个程序,该程序可以充斥QImage。问题是它有点慢,对于800x600的图像要花整整2秒钟的时间。 Qt文档建议使用bits()或scanLine()方法直接访问像素数据,这比使用pixel()和setPixel()方法要快。虽然可以使用这些方法读取像素数据,但无法像C ++示例中那样直接分配像素数据。

def flood_fill(self, x, y, old_color, new_color):
    if old_color == new_color:
        return
    w = self.image.width()
    h = self.image.height()
    s = self.image.bits().asstring(self.image.byteCount())

    def get_pixel(x, y):
        i = (x + y * w) * 4
        return s[i:i+3]

    old_color = get_pixel(x, y)
    painted = set()
    stack = set()
    stack.add((x, y))
    while stack:
        x, y = stack.pop()
        x1 = x
        while x1 >= 0 and get_pixel(x1, y) == old_color:
            x1 -= 1
        x1 += 1
        span_above = span_below = False
        while x1 < w and get_pixel(x1, y) == old_color:
            self.image.setPixelColor(x1, y, new_color)
            painted.add((x1, y))
            if not span_above and y > 0 and get_pixel(x1, y - 1) == old_color:
                if (x1, y - 1) not in painted:
                    stack.add((x1, y - 1))
                span_above = True
            elif span_above and y > 0 and get_pixel(x1, y - 1) != old_color:
                span_above = False
            if not span_below and y < h - 1 and get_pixel(x1, y + 1) == old_color:
                if (x1, y + 1) not in painted:
                    stack.add((x1, y + 1))
                span_below = True
            elif span_below and y < h - 1 and get_pixel(x1, y + 1) != old_color:
                span_below = False
            x1 += 1

我认为我也许能够代替s中的那些字节,而不用调用setPixelColor(),然后将其加载到新的QImage中。但是它会创建一个完全透明的图像,甚至更慢。

def flood_fill(self, x, y, old_color, new_color):
    . . .
    self.image.setPixelColor(x+1, y, new_color)
    s = self.image.bits().asstring(w * h * 4)

    def get_pixel(x, y):
        i = (x + y * w) * 4
        return s[i:i+3]

    def set_pixel(x, y, new_color, s):
        i = (x + y * w) * 4
        return s[:i] + new_color + s[i+3:]

    old_color = get_pixel(x, y)
    new_color = get_pixel(x+1, y)
    . . .
    while stack:
        . . .
        while x1 < w and get_pixel(x1, y) == old_color:
            s = set_pixel(x1, y, new_color, s)
            painted.add((x1, y))
            . . .
    new_img = QImage()
    new_img.loadFromData(s)
    self.image = new_img

我的目标实际上是提高速度。我相信我没有正确进行像素写入,但是我不确定为什么这种方式要慢得多。 This是我使用泛洪填充算法的地方,我不确定在这一方面是否还有其他需要改进的地方。我尝试使用PIL方法,但是它也很慢:

def flood_fill(self, x, y, old_color, new_color):
    buffer = QBuffer()
    buffer.open(QBuffer.ReadWrite)
    self.image.save(buffer, 'png')
    im = Image.open(io.BytesIO(buffer.data()))
    ImageDraw.floodfill(im, (x, y), new_color.getRgb())
    self.image = ImageQt.ImageQt(im)

0 个答案:

没有答案