您的位置:首页 > 编程语言 > Qt开发

一种使用Qt快速绘图的思路

2014-10-27 18:16 232 查看
Qt具有强大的绘图功能,相信熟悉Qt的人都有这个体会,再加上一个基于Qt的绘图库,使得绘制各种图形都更加方便,比如qwt,应该是接触的比较多的。Qt本身的Graphic Model/View,在一些方面更加方便。在此,我想说一下下面这种样式图的画法思路。



来分析下图,不同像素颜色不同(或者相同)。一般不同像素都有实际意义,或者对应有实际的计算方法,可以取到某个坐标位置的图的颜色(一般取到的是某中强度值,然后根据这个强度值去查颜色表,本篇以后提到坐标对应的值都表示为强度)。并且,一般来说,二维图形都会支持缩放。这样会带来一个问题,不同缩放比例下需要计算对应的实际坐标(我们称之为世界坐标)是不同的。这样就需要一个世界坐标和像素坐标的转换,我们不在此讨论坐标转换的实现问题。假设这种转换关系我们已经知道了,我们现在只关注如何绘制的问题。

先来看下Qt中有哪些可以用的工具。熟悉Qt的人都知道,双缓冲的速度要快。而双缓冲的实现就是依赖于在内存中构建一个QImage(或者QPixmap等)对象,对它进行绘制,然后显示这个对象。我们就这么做,首先构建一个QImage。QImage的大小如何确定?可以取当前视口的设备坐标范围,也就是像素坐标范围。大小有了,就该填充值了。看下QImage的方法:

uchar *	scanLine ( int i )
可以取到一行的像素,数组赋值的速度要快的多,我们就采用此法。

归纳下思路:取适口范围-->转换成世界坐标-->取(强度)值-->数组赋值。

为了加快速度,还可以用Qt的QtConcurrent来分多线程填充像素。

QFuture<T> QtConcurrent::run ( Function function, ... )

Runs function in a separate thread. The thread is taken from the global QThreadPool. Note that the function may not run immediately; the function will only be run when a thread is available.

这种按照像素填充的方式适用的地方还是挺多的。

再考虑一下,如果转换的代价很大(比如很耗时),可以对数据采样后取色填充,比如,现在数据源变化了,改为从一个图中取值,可以不再逐个像素填充,我们就可以分块来填充,兼顾质量和速度。

补充点代码片段:

#include "testimage.h"
#include <QPainter>
#include <QImage>
#include <QtConcurrentMap>
#include <QVector>

TestImage::TestImage(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
}

TestImage::~TestImage()
{

}
namespace
{
class TmpClass
{
public:
TmpClass(QImage* image)
:m_image(image), m_len(image->bytesPerLine()){}
QImage* m_image;
int m_len;
void operator()(uchar* data)
{
//uchar* data = m_image->scanLine(index);
int cnt = m_len / 4;//m_image->bytesPerLine() / 4;
for (int i = 0; i < cnt; ++i)
{
data[i * 4] = qrand() % 255;
data[i * 4 + 1] = qrand() % 255;
data[i * 4 + 2] = qrand() % 255;
data[i * 4 + 3] = 0xff;
}
}
};
}
void renderImage( int index )
{

}

void TestImage::paintEvent( QPaintEvent *event )
{
QPainter painter(this);
painter.save();

int w = this->width();
int h = this->height();
QImage image(w, h, QImage::Format_ARGB32);
QVector<uchar*> vec(h);
int sz = image.bytesPerLine();
for (int i = 0; i < vec.size(); i++)
{
uchar* data = image.scanLine(i);
vec[i] = data;
}
QFuture<void> results = QtConcurrent::map(vec, TmpClass(&image));
results.waitForFinished();
painter.drawImage(0, 0, image);
painter.restore();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Qt 绘图 QtConCurrent