18

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

屏幕盖 1

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

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

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

在此处输入图像描述

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

  1. 我穿过所有的三角形
  2. 对于每个三角形,我计算将要显示的每个像素的坐标。
  3. 对于这些像素中的每一个,我计算图片上相应像素的坐标(这是一个简单的数学运算),然后检索该像素的颜色。
  4. 我使用QPainter::setPen(QColor)andQPainter::drawPoint(QPoint)来绘制像素。

我是 Qt 编程的新手,我对图形一无所知,所以这就是我能想到的。问题是它“不可接受”太慢了(paintEvent每个画布的 0.15 秒,而普通三角形的 0.01 秒)。

我运行了一个分析器试图了解发生了什么,我注意到在画布小部件paintEvent

  1. 58%的时间花在QPainter::drawPoint
  2. 27% 的时间花在QPainter::setPen

这似乎QPainter::drawPoint太复杂和太慢了:我只想让它打印给定颜色的像素,就是这样。

我可能已经找到了解决我的问题的方法:存储一个QImage(作为我的画布小部件的成员变量),它代表我希望我的画布显示的全部内容,并在我paintEvent的逐像素中完全定义它,然后立即绘制它在我的paintEvent结尾QPainter::drawImage。我暗示这会快得多。但在我重新重写我的代码之前,我想知道这是否真的是我想要做的。

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

4

5 回答 5

7

OpenGL 很好地完成了图像(纹理)坐标映射。您可能想使用某种形式的 OpenGL。Qt 与 OpenGL 有一些绑定,可以帮助您。

于 2012-09-28T13:15:10.037 回答
4

非 OpenGL 解决方案:

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

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

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

于 2012-09-28T13:46:28.133 回答
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您制作的将三角形顶点和相关映射保存到图像中的一些数据结构在哪里。显卡将为您处理像素插值。

于 2012-09-28T13:31:16.860 回答
1

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

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

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

于 2012-09-28T14:13:00.837 回答
0

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

这可以并行化,以便您并行处理与 CPU 内核一样多的三角形。

于 2014-09-22T09:45:35.590 回答