Qt / C ++:高效绘图

时间:2012-09-28 13:10:57

标签: c++ qt graphics pixel qpainter

我设计了一个程序,基本上将几何形状切割成许多小三角形(在“左侧画布”中),对一堆三角形应用一些简单的数学变换,并在新的配置中重绘它们。请参阅下面的屏幕截图。

screen cap 1

为了绘制这些三角形,我使用QPainter::drawPolygon。右边的每个三角形对应左边的三角形,所以我知道我想用什么颜色来绘制它。

到目前为止,很好。即使我绘制了比这更多的三角形(当我使用更小的三角形来切割形状时),这足够快。

我在程序中添加了一个功能:我可以绘制从图片中提取的三角形而不是普通的三角形:请参阅下面的截屏。

enter image description here

问题是我这样做的方式太慢了。我是这样做的:

  1. 我浏览了所有三角形
  2. 对于每个三角形,我计算将要显示的每个像素的坐标。
  3. 对于这些像素中的每一个,我计算图片上相应像素的坐标(这是一个简单的数学运算),并检索该像素的颜色。
  4. 我使用QPainter::setPen(QColor)QPainter::drawPoint(QPoint)绘制像素。
  5. 我是Qt编程的新手,我对图形一无所知,所以这就是我能想到的。问题是它“不可接受”太慢(每个画布的paintEvent大约需要0.15s,而普通三角形则为0.01s。

    我跑了一个探查器试图了解发生了什么,我注意到在画布小部件的paintEvent中,

    1. 58%的时间花在QPainter::drawPoint
    2. 27%的时间花在QPainter::setPen
    3. 似乎QPainter::drawPoint过于复杂和缓慢:我只是想让它打印一个给定颜色的像素,就是这样。

      我可能找到了解决问题的方法:存储QImage(作为我的画布小部件的成员变量),它代表我希望我的画布显示的整个内容,并完全在我的{{{ 1}}逐个像素,然后在我的paintEvent末尾用paintEvent一次绘制它。我有一个提示,这会更快。但在我重新编写代码之前,我想知道这是否真的是我想要做的。

      我希望我没有让你做死!非常感谢您的见解。

5 个答案:

答案 0 :(得分:7)

OpenGL非常适合图像(纹理)坐标映射。您可能想要使用某种形式的OpenGL。 Qt对OpenGL有一定的帮助,可以帮助你。

答案 1 :(得分:4)

非OpenGl解决方案:

使用RGB缓冲区作为目标图像。像以前一样完成前3个步骤。 找到位置和像素颜色后,将其设置在此缓冲区上。然后你用

QImage::QImage ( uchar * data, int width, int height, Format format )

根据前一个缓冲区构建图像。它接近您提供的解决方案 并且比你现在拥有的要快得多。

答案 2 :(得分:3)

这样做的一种方法是使用继承自QGLWidget而不是QGraphicsScene / QGraphicsView组合的类。不幸的是,OpenGL的学习曲线开始有点陡峭。但是,它会非常快,因为它会直接发生在显卡上,而这种显卡只针对这种操作进行了优化 您将加载图片QGLWidget::bindTexture() 您将图像中的点与三角形网格相关联,并将它们全部发送到您的图形卡。在OpenGL的旧版本中(在我看来,它比新的API更容易使用),它看起来像这样:

glEnable(GL_TEXTURE_2D);

glBegin(GL_TRIANGLES);
for (int ii=0;ii<triangle.size();++ii) {
  for (int jj=0;jj<3;++jj) {
    glTexCoord2d(triangle[ii].tex[jj][0],triangle[ii].tex[jj][1]);
    glVertex2d(triangle[ii].point[jj[0],triangle[ii].point[jj][1]);
  }
}
glEnd();

其中triangle是您将三角形顶点和关联映射保存到图像中的一些数据结构。显卡将为您处理像素插值。

答案 3 :(得分:1)

除OpenGL之外的另一个选择是使用OpenCL,这对您来说可能更容易。您只需将输入/输出位图的内存映射到图形卡,在C中编写一个处理一个三角形的小内核,然后为每个三角形排队内核执行。这将比CPU上的单个核心快100倍。

这里有一个OpenCL主机api的Qt包装器:

http://doc.qt.digia.com/opencl-snapshot/index.html

答案 4 :(得分:0)

另一种方法是利用已在栅格绘制引擎中有效实现的剪切和变换。只要两个三角形之间的变换可以使用3x3增强变换矩阵表示,您只需要在目标画家上设置它,然后在目标上绘制整个源图像。它将被剪切并变换以填充目标三角形。如果分析显示其优势,您也可以仅绘制源三角形的边界矩形而不是整个图像。

这可以并行化,以便您可以像处理CPU核心那样并行处理多个三角形。