youngyang_sjtu的博客
转
QImage像素级操作
2018年03月20日 14:31:04
阅读数:754
转自http://blog.csdn.net/silangquan/article/details/41008183
这篇文章主要阐述了如何使用Qt在像素级别上对图像进行操作,并实现了一些图像效果,这些效果主要有:灰度,模糊,锐化,添加相框,金属质感,改变图像饱和度,亮度还有白平衡。
scanLine 返回某一行数据,转换为QRgb指针可进行直接有效的像素存取操作。
介绍
文章中,我们将讨论在Qt中修改图像的一些技术和算法,在这之前,你必须知道在Qt中操作图像的一些方法。
.在Qt中有两种表示图像的类,Qt:QImage和QPixmap,还有QBitmap来存储单色的图像,比如遮罩,QPicture在存储QPainter的一些操作指令。
当我们想要在屏幕上绘制图像的时候,最快的方法就是使用QPixmap,不过坏处就是无法访问和修改像素;
QImage在IO操作中有很快的速度,并且给出了访问像素的接口,这篇文章中我们就使用这个类。
.如果你是要处理大的图片,比如摄像头拍摄的照片,这种情况最好是将原图缩小之后作为预览图显示在屏幕上,除非我们允许用户缩放图像。有两种加载并缩放图像的方法。
。将图像加载进QImage或者QPixmap,然后调整大小:
[cpp] view plain copy
- QImage image("sample.png");
- image = image.scaled(width, height);
使用QImageReader来读取和缩放图片,然后再加载进QImage中。QImageReader无法将一张图片加载进QPixmap中去,但是可以使用静态方法 QPixmap::fromImage(QImage img)从QImage中加载进QPixmap。这个方法非常快,并且不需要加载大图的内存开销:
[cpp] view plain copy
- QImageReader imgReader("sample.png");
- imgReader.setScaledSize(QSize(width, height));
- QImage * image;
- imgReader.read(image);
。每一张图片都是由像素点组成,每一个像素都有三个通道:红,绿,蓝,还有一个alpha通道来保存透明度(JPEG格式的图片不支持透明)。每个通道的值是0-255,三个通道都是0的话,表示黑色,都是255表示白色。这篇文章中我们用RGB来表示一种颜色,也就是三个通道的值。
。相比于一个像素一个像素地读取,uchar * QImage::scanLine(int i)可以一次读取整行的像素值,会更加高效,下面的例子就是按行读取的例子,也是我们将要讲的第一个例子,转灰度图。
[cpp] view plain copy
- QImage * MainWindow::greyScale(QImage * origin){
- QImage * newImage = new QImage(origin->width(), origin->height(), QImage::Format_ARGB32);
- QRgb * line;
- for(int y = 0; y<newImage->height(); y++){
- QRgb * line = (QRgb *)origin->scanLine(y);
- for(int x = 0; x<newImage->width(); x++){
- int average = (qRed(line[x]) + qGreen(line[x]) + qRed(line[x]))/3;
- newImage->setPixel(x,y, qRgb(average, average, average));
- }
- }
- return newImage;
- }
灰度
我们要学习的第一个技术就是将彩色图转换成灰度图,我们首先要明白的一点就是,其实标准的灰度图就是每个像素点的三个通道的值一样或者近似,我们的策略就是将每个像素的每个通道的值都调成一样,取R,G,B值为三者的算数平均数就可以了,比如原色是RGB(169,204,69), 那么最终的RGB就是(169+204+69)/3 = 147.
[cpp] view plain copy
- QImage * MainWindow::greyScale(QImage * origin){
- QImage * newImage = new QImage(origin->width(), origin->height(), QImage::Format_ARGB32);
- QColor oldColor;
- for(int x = 0; x<newImage->width(); x++){
- for(int y = 0; y<newImage->height(); y++){
- oldColor = QColor(origin->pixel(x,y));
- int average = (oldColor.red()+oldColor.green()+oldColor.blue())/3;
- newImage->setPixel(x,y,qRgb(average,average,average));
- }
- }
- return newImage;
- }
原始图
灰度图
亮度调节
就如之前我们提到的,白色用RGB(255,255,255)表示,黑色用RGB(0,0,0)表示,所以如果我们需要提高图片的亮度(颜色接近白色),我们需要同时增加三个通道的数值,反之就是变暗。
在这里我们添加了一个函数参数来决定要提高多少亮度,如果参数是负数的话就是减少亮度了。在每个通道都加上delta值之后,需要做的就是让它不要低于0且不要高于255.
原图
加亮图 Delta = 30
暖色调
当我们说一一幅暖色调的图片的时候通常是因为这张图色调偏黄。我们没有黄色的通道,但是红色和绿色混合起来就是黄色,所以我们增加这两个通道值,然后蓝色通道值不变就好了。
我们使用一个delta参数来决定增加红色和绿色通道的值。一张暖色的图片能够给人一种复古效果,如果是有沙子的图片,图片将会更加生动。
[cpp] view plain copy
- QImage * MainWindow::warm(int delta, QImage * origin){
- QImage *newImage = new QImage(origin->width(), origin->height(), QImage::Format_ARGB32);
- QColor oldColor;
- int r,g,b;
- for(int x=0; x<newImage->width(); x++){
- for(int y=0; y<newImage->height(); y++){
- oldColor = QColor(origin->pixel(x,y));
- r = oldColor.red() + delta;
- g = oldColor.green() + delta;
- b = oldColor.blue();
- //we check if the new values are between 0 and 255
- r = qBound(0, r, 255);
- g = qBound(0, g, 255);
- newImage->setPixel(x,y, qRgb(r,g,b));
- }
- }
- return newImage;
- }
原图
暖色图 Delta = 30
冷色调
如果说暖色调的图片偏黄色,那么冷色调的图片应该就是偏蓝色了。在这个方法里面我们只增加蓝色通道的值,红色和绿色的值不变。
冷色调的图片可以联想到未来,死亡或者,冷。
[cpp] view plain copy
- QImage * MainWindow::cool(int delta, QImage * origin){
- QImage *newImage = new QImage(origin->width(), origin->height(), QImage::Format_ARGB32);
- QColor oldColor;
- int r,g,b;
- for(int x=0; x<newImage->width(); x++){
- for(int y=0; y<newImage->height(); y++){
- oldColor = QColor(origin->pixel(x,y));
- r = oldColor.red();
- g = oldColor.green();
- b = oldColor.blue()+delta;
- //we check if the new value is between 0 and 255
- b = qBound(0, b, 255);
- newImage->setPixel(x,y, qRgb(r,g,b));
- }
- }
- return newImage;
- }
原图
冷色调图 Delta = 30
饱和度
我们已经说了,颜色由三个通道组成:红,绿,蓝,尽管如此,RGB不是唯一一个表示色彩的方式,在这里,我们使用HSL格式表示色彩 - hue(色相), saturation(饱和度), lightness(明度)。
饱和的图像拥有更加生动的颜色,通常会比较好看,但是有一点要记住:不要滥用饱和度,因为很容易出现失真。
[cpp] view plain copy
- QImage * MainWindow::saturation(int delta, QImage * origin){
- QImage * newImage = new QImage(origin->width(), origin->height(), QImage::Format_ARGB32);
- QColor oldColor;
- QColor newColor;
- int h,s,l;
- for(int x=0; x<newImage->width(); x++){
- for(int y=0; y<newImage->height(); y++){
- oldColor = QColor(origin->pixel(x,y));
- newColor = oldColor.toHsl();
- h = newColor.hue();
- s = newColor.saturation()+delta;
- l = newColor.lightness();
- //we check if the new value is between 0 and 255
- s = qBound(0, s, 255);
- newColor.setHsl(h, s, l);
- newImage->setPixel(x, y, qRgb(newColor.red(), newColor.green(), newColor.blue()));
- }
- }
- return newImage;
- }
原图
饱和的图片 Delta=30
模糊
这个效果相对于之前的有一点点复杂。我们会用到一个卷积滤波器,根据当前像素的颜色和相邻像素的颜色来获得一个新的颜色。同时还有一个kernel的矩阵来决定计算中相邻像素的影响程度。
原像素会在矩阵的中心,因此我们会使用基数行的行和列。我们不会修改边缘的像素点,因为那些点没有我们需要的相邻像素点,虽然我们也可以只使用有效的像素点。
举了例子,让我们来看看如何计算像素的RGB值。下面的三个举证代表着当前像素和邻接像素的RGB值,最中间的是当前像素。
R = 20 102 99
150 200 77
170 210 105
G = 22 33 40
17 21 33
8 15 24
B = 88 70 55
90 72 59
85 69 50
Kenel = 0 2 0
2 5 2
0 2 0
使用滤波器进行计算:
r = ( (102*2) + (150*2) + (200*5) + (77*2) + (210*2) ) / (2+2+5+2+2) = 159
g = ( (33*2) + ( 17*2) + (21*5) + (33*2) + (15*2) ) / (2+2+5+2+2) = 23
b = ( (70*2) + (90*2) + (72*5) + (59*2) + (69*2) ) / (2+2+5+2+2) = 72
由原始的RGB(200, 21, 72)得到了RGB(159, 23, 72). 发现最大的变化是红色的通道,因为红色通道的值差距最大。
在修改肖像照片的时候通常会使用到模糊的技术,它能后掩盖住皮肤的瑕疵。
[cpp] view plain copy
- QImage * MainWindow::blur(QImage * origin){
- QImage * newImage = new QImage(*origin);
- int kernel [5][5]= {{0,0,1,0,0},
- {0,1,3,1,0},
- {1,3,7,3,1},
- {0,1,3,1,0},
- {0,0,1,0,0}};
- int kernelSize = 5;
- int sumKernel = 27;
- int r,g,b;
- QColor color;
- for(int x=kernelSize/2; x<newImage->width()-(kernelSize/2); x++){
- for(int y=kernelSize/2; y<newImage->height()-(kernelSize/2); y++){
- r = 0;
- g = 0;
- b = 0;
- for(int i = -kernelSize/2; i<= kernelSize/2; i++){
- for(int j = -kernelSize/2; j<= kernelSize/2; j++){
- color = QColor(origin->pixel(x+i, y+j));
- r += color.red()*kernel[kernelSize/2+i][kernelSize/2+j];
- g += color.green()*kernel[kernelSize/2+i][kernelSize/2+j];
- b += color.blue()*kernel[kernelSize/2+i][kernelSize/2+j];
- }
- }
- r = qBound(0, r/sumKernel, 255);
- g = qBound(0, g/sumKernel, 255);
- b = qBound(0, b/sumKernel, 255);
- newImage->setPixel(x,y, qRgb(r,g,b));
- }
- }
- return newImage;
- }
原图
模糊图
锐化
像模糊中一样,锐化一张图片也会使用一个卷积滤波器,但是kernel矩阵是不一样的,相邻像素对应的值是负的。
锐化能够处理模糊的照片,能够提升细节。
[cpp] view plain copy
- QImage * MainWindow::sharpen(QImage * origin){
- QImage * newImage = new QImage(* origin);
- int kernel [3][3]= {{0,-1,0},
- {-1,5,-1},
- {0,-1,0}};
- int kernelSize = 3;
- int sumKernel = 1;
- int r,g,b;
- QColor color;
- for(int x=kernelSize/2; x<newImage->width()-(kernelSize/2); x++){
- for(int y=kernelSize/2; y<newImage->height()-(kernelSize/2); y++){
- r = 0;
- g = 0;
- b = 0;
- for(int i = -kernelSize/2; i<= kernelSize/2; i++){
- for(int j = -kernelSize/2; j<= kernelSize/2; j++){
- color = QColor(origin->pixel(x+i, y+j));
- r += color.red()*kernel[kernelSize/2+i][kernelSize/2+j];
- g += color.green()*kernel[kernelSize/2+i][kernelSize/2+j];
- b += color.blue()*kernel[kernelSize/2+i][kernelSize/2+j];
- }
- }
- r = qBound(0, r/sumKernel, 255);
- g = qBound(0, g/sumKernel, 255);
- b = qBound(0, b/sumKernel, 255);
- newImage->setPixel(x,y, qRgb(r,g,b));
- }
- }
- return newImage;
- }
原图
锐化图
添加相框
绘制一个相框是非常见到那的,我们只需要把相框在原图上面绘制就可以了。这里假设我们已经有一个和图片一样大小的相框了,不一样的话要resize到一样大。
[cpp] view plain copy
- QImage * MainWindow::drawFrame(QImage * origin){
- QImage * newImage = new QImage(* origin);
- QPainter painter;
- painter.begin(newImage);
- painter.drawImage(0,0, QImage(":images/frame.png"));
- painter.end();
- return newImage;
- }
原图
相框
添加相框之后
金属效果
这个例子中我们会结合几种技术来获得一种效果。下面是处理的步骤:
1.调整图像的亮度,获得一个较暗的图片。
2.将图像转成灰度。
3.将灰度图绘制在金属的纹理上,透明度50%。
[cpp] view plain copy
- QImage * MainWindow::metal(QImage * origin){
- QImage * newImage = new QImage(":images/metal.png");
- QImage * darkImage = brightness(-100, origin);
- QImage * greyImage = greyScale(darkImage);
- QPainter painter;
- painter.begin(newImage);
- painter.setOpacity(0.5);
- painter.drawImage(0, 0, * greyImage);
- painter.end();
- delete greyImage;
- delete darkImage;
- return newImage;
- }
原图
金属纹理
最终效果
模糊的边框
最后再来学习一个融合的效果,这次我们想要做的是模糊图片外延的部分,让视线的焦点聚集在图片的中间。
我们将会使用一张遮罩图片,来决定需要模糊的部分,具体的操作步骤如下:
1.从原图获取一张完全模糊的图片。
2.使用QPainter的一种融合模式,通过遮罩图片截取出一个模糊的相框。点这里可以学习到更多的QPainter的融合模式。
3.在原图上绘制出模糊的边框。
[cpp] view plain copy
- QImage * MainWindow::blurFrame(QImage * origin){
- QImage * newImage = new QImage(* origin);
- QImage * blurredImage = blur(newImage);
- QImage * mask = new QImage(":images/mask.png");
- QPainter painter;
- //Using the composition mode SourceAtop we get a blurred frame stored in QImage mask
- painter.begin(mask);
- painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
- painter.drawImage(0, 0, * blurredImage);
- painter.end();
- //With our new frame we simply draw it over the original image
- painter.begin(newImage);
- painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
- painter.drawImage(0, 0, * mask);
- painter.end();
- delete mask;
- delete blurredImage;
- return newImage;
- }
原图
遮罩
模糊的边框
最终效果
手机Demo
你可以下载这个手机Demo的源码,里面包含了文章中的源码,在这个应用中,包含了3张462*260的图片。测试应用的时候,你只要选择其中一张并应用下面的效果就可以了。
总结
这篇文章应该可以成为你图像处理的入门,但是一切皆有可能。你可以修改这些方法,整合这些方法,使用其他的技术等等。想象力才是你唯一的限制。
个人分类: image processing
相关热词: qimage画布 qimage拷贝 qimage类型 qimage颜色 qimage转换
2018年Python全栈平均薪资是多少?
转型学Python如何从8K提升至20K月薪,多数高薪Python全栈需要掌握Django框架、网络爬虫Scrapy框架、Xpath、PhantomJS、BeautifulSoup、Redis存储和Docker容器技术、自动化运维、数据挖掘与机器学习…………
想对作者说点什么? 我来说一句
2219
5560
因为想利用QT的gui在arm上显示的缘故,因此开始接触了QT。最近,用QT在弄一个显示图片的小程序。程序如下: #include #include "mainwindow.h" ...
6-7
这篇文章主要阐述了如何使用Qt在像素级别上对图像进行操作,并实现了一些图像效果,这些效果主要有:灰度,模糊,锐化,添加相框,金属质感,改变图像饱和度,亮度还有白平衡。...
8-1
8850
QImage::QImage() 构造一个空的QImage对象,此时返回的对象,如果调用isNULL 返回值为真 QImage::QImage(const QSize & size, Fo...
5-29
6-6
Qt中QImage类封装了对于一般图像像素级的操作,图像显示则使用QPixmap。本文说说对...访问: 32万+ 积分: 4298 排名: 9140 勋章: 持之以恒 授予每个自然...
1286
本文以常见的二维BMP图像为例,对比OpenCV, QT, ITK库对图像像素级的操作。
9087
对比OpenCV, QT, ITK库对图像像素级的操作 - CSDN博客
6-3
5-22
1.3万
支持的图像格式: BMP ,GIF , JPG , JPEG, PNG, PBM, PGM, PPM, XBM, XPM //使用给定的大小和格式构造图像 QImage(const ...
6-26
Qt可显示基本的图像类型,利用QImage、QPxmap类可以实现图像的显示,并且利用类中的方法可以实现图像的基本操作(缩放、旋转)。 1. Qt可显示的图像类型 参考Qt的帮助...
6-6
Qt 中获取字体的像素高度和宽度 最近在用Qt做文字的滚屏效果,要计算字体的像素...访问: 2万+ 积分: 549 排名: 9万+ 勋章: 持之以恒 授予每个自然...
117
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupU...
2018年05月08日 6KB 下载
6-6
这里主要介绍了在Qt中使图片像素变小,编程的时候,一般都是要添加图片的,但是图片有很大,对于编程人员来说,编程那是小事,要实现快速化缩小图片,就是头疼的事儿了...
6343
1885
如何将内存图像数据封装成QImage 当采用Qt开发相机数据采集软件时,势必会遇到采集内存图像并进行处理(如缩放、旋转)操作。如果能够将内存图像数据封装成QImage,则可以利用QI...
QPixmap、QBitmap、QImage 與 QPicture
2.2万
在處理影像資料上,Qt提供了QPixmap、QBitmap、QImage與QPicture等類別。 一. 几种类的简介 QPixmap繼承了QPaintDevice,您可用以建立QPaint e...
3286
6620
QT的图像类有QImage,QPixmap,QBitmap,QPicture。 CMyWidget类头文件: #ifndef CMYWIDGET_H #define CMYWIDGET_H ...
2964
简单认识图像融合,包括概念、特点、应用、基本原则以及像素级融合、特征级融合、决策级融合...
2.8万
204
77
之前还做过GIGE相机的raw格式转换为OpenCV格式,一开始觉得很不好下手,但其实图像都会遵循标准的,,不要慌,仔细看文档,看清楚是什么格式后就能发现转换的办法 代码如下[cpp] v...
231
453
1231
2899
3340
4773
直接上代码: cv::Mat QImageToMat(QImage image) { cv::Mat mat; switch (image.format()) { case QImage::...
1451
http://tracey2076.blog.51cto.com/1623739/539690 嗯,这个QImage的问题研究好久了,有段时间没用,忘了,已经被两次问到了,突然有点解释不清楚,我...
1483
Qimage等均是以左上角为原点(0,0),向右向下分别延伸x与y的正半轴的。
OpenCV 学习(像素操作 Manipuating the Pixels)
3938
76
613
图像的数据是以字节为单位保存的,每一行的字节数必须是4的整数倍,不足的补0。 (因为我们使用的是32操作系统,因此数据是按照32位对齐的,所以每行的字节数必须是4的整数倍也就是说每行的数据位必须...
如何正确地在手机上显示图片——QImage与QPixmap完全解析
1180
引言 用Qt程序在手机上显示一幅图片对编程人员来说是再基础不过的一件事情了。那么先让大家看两段代码: //dangerous should not be used, cannot d...
1283
2.7万
4174
mainwindow.cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new ...
OpenCV的cv::Mat转换为Qt的QImage是歪斜失真
74
1 OpenCV的cv::Mat转换为Qt的QImage是歪斜失真 2 Qt中用QLabel显示OpenCV中Mat图像数据出现扭曲现象的解决 void CenterWindow::dis...
566
QT三大绘图类:Qpixmap/QImage/Qpicture
2775
743
转自:http://blog.csdn.net/zyh821351004/article/details/46646735
543
4610
1.8万
转载自http://www.civilnet.cn/bbs/browse.php?topicno=4691 用Qt程序在手机上显示一幅图片对编程人员来说是再基...
Qt可显示基本的图像类型,利用QImage、QPxmap类可以实现图像的显示,并且利用类中的方法可以实现图像的基本操作(缩放、旋转)。
4882
427
8-3 使用QImage进行高质量绘制(High-Quality Rendering with QImage)
1.4万
651
837
2011年07月01日 283KB 下载
2359
3778
2016-05-09 赵凯 深度学习大讲堂 点击上方“公众号”可订阅哦!深度学习大讲堂致力于推送人工智能,深度学习方面的最新技术,产品以及活动。 卷积神经网络(CNN):图像级语义理解的利器 ...
2949
QImage与QPixmap加载图片 效果 . 分类: QT开发 qtQtQT PixmapTest::PixmapTest(QWidget *parent) : QDial...
使用QImage进行高质量绘制(High-Quality Rendering with QImage)
1527
4193
没有更多推荐了,返回首页
个人资料
粉丝
2
喜欢
2
评论
0
等级:
访问:
925
积分:
33
排名:
199万+
最新文章
个人分类
归档
热门文章
- QImage像素级操作
阅读量:742
- PCA在图像压缩和图像识别的区别
阅读量:153
- 基石
阅读量:18
联系我们
请扫描二维码联系客服
400-660-0108
QQ客服 客服论坛
©2018 CSDN版权所有 京ICP证09002463号
百度提供支持
登录