Qt中有两个最常用的类,一个是QPixmap,一个是QImage,当然还有QBitmap,QPicture之类的。关于QPixmap和QImage,官方的解释是这样的,
Qt provides four classes for handling image data: QImage, QPixmap, QBitmap and QPicture. QImage is designed and optimized for I/O, and for direct pixel access and manipulation, while QPixmap is designed and optimized for showing images on screen. QBitmap is only a convenience class that inherits QPixmap, ensuring a depth of 1. Finally, the QPicture class is a paint device that records and replays QPainter commands. Because QImage is a QPaintDevice subclass, QPainter can be used to draw directly onto images. When using QPainter on a QImage, the painting can be performed in another thread than the current GUI thread.
大概是说QPixmap主要用于显示,而QImage则是图像的物理存储信息。
如果我们要对QImage进行像素级的图片读写,通常要用到setpixel之类的函数,但每读一个像素,需要调用函数级堆栈,如果要对整张图像进行算法上的变换,效率是完全不能接受的。
所以,我们必须要对raw data(内存数据块)直接操作。下面是一段测试代码,这里我只测试了Grayscale8,ARGB32和Mono格式,RGB24等大家可以自己去尝试,如下,
gImgViewer = new QGraphicsView();
gScene = new QGraphicsScene();
gScene->setSceneRect(0, 0, 800, 600);
gImgViewer->setScene(gScene);
// 在mainwindow.cpp中,构建好QGraphicsScene和QGraphicsView之后,添加下面这一段代码即可
// 测试,使用不同格式时注意修改步长
QImage::Format fmt = QImage::Format_ARGB32; //:Format_Grayscale8; //QImage::Format_Mono;
QImage *image = new QImage(800, 600, fmt);
int step = image->bytesPerLine(); //image->width();
int wd = image->width();
int ht = image->height();
//image->data_ptr()==QImageData
uchar* ptr = image->bits();
uchar* ptr_var = ptr;
uchar **pptr = new uchar*[ht];
for (int y = 0; y < image->height(); y++) {
ptr_var += step;
pptr[y] = ptr_var; //&(((uchar*)ptr_var)[0]);
}
if(QImage::Format_Mono == fmt){
assert(step*8 == wd); // NOTE: for mono, each pix has 1 bit
}else if(QImage::Format_Grayscale8 == fmt){
assert(step == wd); // NOTE: for mono, each pix has 1 bit
for(int x=200; xaddPixmap(QPixmap::fromImage(*image));
delete [] pptr;
这里最关键的是在获取到内存的地址image->bits()之后,通过指针的形式pptr把1维数据变成2维数据(当然也可用scanline()函数),然后直接以2维数据的形式对数据进行存储与读取。本例源码的grayscale8显示结果 如下,
随便找一张800*600的图片,然后使用源码中的ARGB32覆盖在图片上面,可以看到当alpha设置为100时的中间部分透明度较高,效果如下,
图中的四周灰色是没有初始化的内存,中间白色就是我们源码中逐个像素填充的颜色色(255)。
值得说明的是,
(1)直接使用源码中的代码貌似存在内存泄露,当pixmap接收QImage的时候,会自己在内存中保存一份copy,此时指针形式创建的内存并没有释放,测试如下源码,会发现scene->clear这句只释放了一半内存,另一半是由new创建的,并没有释放。使用时不用的内存区需要自己去删除。
for (int i = 0; i < 50; i++) {
QImage* image = new QImage(8000, 6000, fmt);
scene->addPixmap(QPixmap::fromImage(*image));
}
scene->clear();
(2)源码中对数据进行了维度变换。对数据进行维度变换有好几种办法,这里只选了最常用的一种,更多具体可参考
C++ 中多维数组之间的快速转换(以1维2维数组的相互转换为例说明)_高精度计算机视觉的博客-CSDN博客在图像处理中,大规格的数组之间的转换是家常便饭。c++中多维数组在本质上就是一个地址问题,普通情况下,可以通过类似如下方法进行暴力转换int arr[50];int main(){unsigned i, j;for (i = 0; i < 50; i++) {arr[i] = 2 * i;}int bruteArray[7][7];for (i =...https://blog.csdn.net/tanmx219/article/details/93874224
最后,如何获取QGraphicsPixmapItem中的QImage?
我们看一下下面这段测试代码,把前面的白色变成 红色,透明度依旧保持为100,
QPixmap pmp = pix_item->pixmap();
QImage image_t = pmp.toImage();
fmt = image_t.format();
if(QImage::Format_ARGB32_Premultiplied == fmt){
*image = image_t.convertToFormat(QImage::Format_ARGB32);
wd = image->width();
ht = image->height();
step = image->bytesPerLine();
assert(step == wd * 4); // NOTE: for mono, each pix has 1 bit
ptr = image->bits();
ptr_var = ptr;
for (int y = 0; y < image->height(); y++) {
ptr_var += step;
pptr[y] = ptr_var; //&(((uchar*)ptr_var)[0]);
}
for(int x=200*4; x
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?