Python 绘制一个太大的图像,无法放入图像中

Python 绘制一个太大的图像,无法放入图像中,python,c++,qt,Python,C++,Qt,我需要显示一个图表,可以是非常大的,例如,图像分辨率可以是100000 x 1000。但是,我似乎被QImage限制为32768 x 32768 我无法在每次paintEvent直接重新绘制图表,因此我需要将其存储到一个QImage中(它可能是一个不会改变任何内容的QPixmap)。但是,它不适合 我的第一个想法是: 创建QImage的列表 在各种QImage 使用良好的QImages重新绘制 第一点和最后一点都很容易做到。但第二点更为复杂。我很有信心我的方法会奏效,但它需要重载基本的绘制方

我需要显示一个图表,可以是非常大的,例如,图像分辨率可以是100000 x 1000。但是,我似乎被QImage限制为32768 x 32768

我无法在每次
paintEvent
直接重新绘制图表,因此我需要将其存储到一个QImage中(它可能是一个不会改变任何内容的QPixmap)。但是,它不适合

我的第一个想法是:

  • 创建
    QImage的列表
  • 在各种
    QImage
  • 使用良好的
    QImage
    s重新绘制
第一点和最后一点都很容易做到。但第二点更为复杂。我很有信心我的方法会奏效,但它需要重载基本的绘制方法(绘制矩形、圆形等),以便能够在多个图像上绘制


因此,在进一步讨论之前,我想知道其他选项。

您可能不希望一次显示多个
QImage
数据。很少有屏幕宽或高超过32k像素

因此,您需要一个抽象类型,该类型在请求读取时生成
QImage
s,偏移量和可能不同的缩放因子

下一个问题是修改这个抽象类型。一个易于使用,但性能不是最高的版本包括允许用户将blit
QImage
s导入您的内部存储(无论是什么)

用户仍然需要“平铺”他们的努力,但可以以方便他们的方式平铺他们的努力

更高性能的版本公开了一些我们尚未提到的底层实现

大型图像的传统实现是平铺图像。您有一个相互邻接的图像分片网格。当有人要求从您的图像中添加一个blit时,您会生成一个临时的
QImage
,并在其上添加适当的平铺。当有人向您发送短消息时,您会找出合适的分幅,并在部分分幅上编写部分源代码
QImage

更高性能的接口公开了这些分幅

一个低级界面让外界知道你的瓷砖在哪里,并让他们询问。这是一个糟糕的界面

更好的接口公开了一个子图块迭代器。它们请求一个区域,然后返回一对描述该区域的迭代器。迭代器中的数据由一个图块和该图块中的一个区域以及该区域在“完整图像”中的位置组成,或者由一个子图块对象(具有线条跨距、线条长度等)和子图块对象的位置组成

另一个好的界面是
foreach
风格的界面。同样,big image类的用户传入他们想要处理的区域,但也传入回调。该回调类似于迭代器取消引用的上述任一结果

与迭代器方法相比,这种方法有两大优势。首先,您可以在大型图像类中实现并行图像处理算法。其次,编写它要比使用自己的迭代器容易得多


一旦你有了这些,绘图就相对容易了。确定正在绘制的区域(请大方)。迭代生成的分幅。在每个平铺上,在将平铺的偏移应用于图形后进行绘制。

您可以使用Qt图形视图框架。为其创建
QGraphicsView
qgraphicscene
。使用
qgraphicscene::addPixmap
(返回从
QGraphicsItem
派生的
QGraphicsPixmapItem
)添加项目,并使用
QGraphicsItem::setPos
调整其位置
QGraphicsView
将有效地绘制场景,并在必要时处理滚动和缩放。

您是否意识到100000 x 1000 RGBA图像是400 MB?浪费所有的记忆是没有意义的。真的,没有

只需在
paintEvent
中每次一个请求都进行绘制。聪明一点,这样你只画需要展示的东西。我认为应该关注优化绘制过程和数据结构,以便能够有效地绘制


在小范围(缩小)下,通过近似/抽取/插值数据,使其看起来相同,可以获得大量数据,但不会浪费时间多次绘制同一像素。

QImage
是一个对齐的连续4字节/像素行缓冲区。对于(a)不会一次全部显示,(B)通常显示为“缩小”,以及(C)非常大的图像,这样的数据结构设计得不好。400 MB的连续RAM不是任何库都需要的。这就是为什么
QImage
不起作用的原因。一个平铺图像,其中每个平铺都是一个
QImage
,甚至还有一个用于缩小的mip贴图类型的东西,应该可以工作——我不知道这是否是您所描述的。这就是我所描述的。感谢您的解释,但我不明白如何实际实现后一种方法。我是说,我在用QPainter方法写文本。如果文本在两个不同的瓷砖上怎么办?@Maxime,视情况而定。
qPaint::drawText
是否允许您以负坐标传递?如果是这样的话,计算(或猜测)哪些图块与文本重叠。将全局坐标转换为平铺局部坐标。在与文本重叠的每个平铺上绘制文本(可能为负偏移)。如上所述,tile暴露版本更难使用:我将首先实现“blit a QImage”和“get a QImage”接口,并担心在工作完成后暴露tile。