我设计了一个程序,基本上将几何形状切割成许多小三角形(在“左侧画布”中),对一堆三角形应用一些简单的数学变换,并在新的配置中重绘它们。请参阅下面的屏幕截图。
为了绘制这些三角形,我使用QPainter::drawPolygon
。右边的每个三角形对应左边的三角形,所以我知道我想用什么颜色来绘制它。
到目前为止,很好。即使我绘制了比这更多的三角形(当我使用更小的三角形来切割形状时),这足够快。
我在程序中添加了一个功能:我可以绘制从图片中提取的三角形而不是普通的三角形:请参阅下面的截屏。
问题是我这样做的方式太慢了。我是这样做的:
QPainter::setPen(QColor)
和QPainter::drawPoint(QPoint)
绘制像素。我是Qt编程的新手,我对图形一无所知,所以这就是我能想到的。问题是它“不可接受”太慢(每个画布的paintEvent
大约需要0.15s,而普通三角形则为0.01s。
我跑了一个探查器试图了解发生了什么,我注意到在画布小部件的paintEvent
中,
QPainter::drawPoint
QPainter::setPen
似乎QPainter::drawPoint
过于复杂和缓慢:我只是想让它打印一个给定颜色的像素,就是这样。
我可能找到了解决问题的方法:存储QImage
(作为我的画布小部件的成员变量),它代表我希望我的画布显示的整个内容,并完全在我的{{{ 1}}逐个像素,然后在我的paintEvent
末尾用paintEvent
一次绘制它。我有一个提示,这会更快。但在我重新编写代码之前,我想知道这是否真的是我想要做的。
我希望我没有让你做死!非常感谢您的见解。
答案 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包装器:
答案 4 :(得分:0)
另一种方法是利用已在栅格绘制引擎中有效实现的剪切和变换。只要两个三角形之间的变换可以使用3x3增强变换矩阵表示,您只需要在目标画家上设置它,然后在目标上绘制整个源图像。它将被剪切并变换以填充目标三角形。如果分析显示其优势,您也可以仅绘制源三角形的边界矩形而不是整个图像。
这可以并行化,以便您可以像处理CPU核心那样并行处理多个三角形。