我试图用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)