在《Qt Quick 之 QML 与 C++ 混合编程详解》一文中我们讲解了 QML 与 C++ 混合编程的方方面面的内容,这次我们通过一个图像处理应用,再来看一下 QML 与 C++ 混合编程的威力,同时也为诸君揭开美图秀秀、魔拍之类的相片美化应用的底层原理。
项目的创建过程请参考《Qt Quick 之 Hello World 图文详解》,项目名称为 imageProcessor ,创建完成后需要添加两个文件: imageProcessor.h 和 imageProcessor.cpp 。
本文是作者 Qt Quick 系列文章中的一篇,其它文章在这里:
- Qt Quick 简介
- QML 语言基础
- Qt Quick 之 Hello World 图文详解
- Qt Quick 简单教程
- Qt Quick 事件处理之信号与槽
- Qt Quick事件处理之鼠标、键盘、定时器
- Qt Quick 事件处理之捏拉缩放与旋转
- Qt Quick 组件与对象动态创建详解
- Qt Quick 布局介绍
- Qt Quick 之 QML 与 C++ 混合编程详解
实例效果
先看一下示例的实际运行效果,然后我们再来展开。
图 1 是在电脑上打开一个图片后的初始效果:
图 1 初始效果
图 2 是应用柔化特效后的效果:
图 2 柔化特效
图 3 是应用灰度特效后的截图:
图 3 灰度特效
图 4 是浮雕特效:
图 4 浮雕特效
图 5 是黑白特效:
图 5 黑白特效
图 6 是应用底片特效后的截图:
图 6 底片特效
如果你注意到我博客的头像……嗯,木错,它就是我使用本文实例的底片特效做出来的。
图 7 是应用锐化特效后的截图:
图 7 锐化特效
特效展示完毕,那么它们是怎么实现的呢?这就要说到图像处理算法了。
图像处理算法
imageProcessor 实例提供了"柔化"、"灰度"、"浮雕"、"黑白"、"底片"、"锐化"六种图像效果。算法的实现在 imageProcessor.h / imageProcessor.cpp 两个文件中,我们先简介每种效果对应的算法,然后看代码实现。
柔化
柔化又称模糊,图像模糊算法有很多种,我们最常见的就是均值模糊,即取一定半径内的像素值之平均值作为当前点的新的像素值。
为了提高计算速度,我们取 3 为半径,就是针对每一个像素,将周围 8 个点加上自身的 RGB 值的平均值作为像素新的颜色值置。代码如下:
static void _soften(QString sourceFile, QString destFile){ QImage image(sourceFile); if(image.isNull()) { qDebug() << "load " << sourceFile << " failed! "; return; } int width = image.width(); int height = image.height(); int r, g, b; QRgb color; int xLimit = width - 1; int yLimit = height - 1; for(int i = 1; i < xLimit; i++) { for(int j = 1; j < yLimit; j++) { r = 0; g = 0; b = 0; for(int m = 0; m < 9; m++) { int s = 0; int p = 0; switch(m) { case 0: s = i - 1; p = j - 1; break; case 1: s = i; p = j - 1; break; case 2: s = i + 1; p = j - 1; break; case 3: s = i + 1; p = j; break; case 4: s = i + 1; p = j + 1; break; case 5: s = i; p = j + 1; break; case 6: s = i - 1; p = j + 1; break; case 7: s = i - 1; p = j; break; case 8: s = i; p = j; } color = image.pixel(s, p); r += qRed(color); g += qGreen(color); b += qBlue(color); } r = (int) (r / 9.0); g = (int) (g / 9.0); b = (int) (b / 9.0); r = qMin(255, qMax(0, r)); g = qMin(255, qMax(0, g)); b = qMin(255, qMax(0, b)); image.setPixel(i, j, qRgb(r, g, b)); } } image.save(destFile);}
这样处理的效果不是特别明显,采用高斯模糊算法可以获取更好的效果。
灰度
把图像变灰,大概有这么三种方法:
- 最大值法,即 R = G = B = max(R , G , B),这种方法处理过的图片亮度偏高
- 平均值法,即 R = G = B = (R + G + B) / 3 ,这种方法处理过的图片比较柔和
- 加权平均值法,即 R = G = B = R*Wr + G*Wg + B*Wb ,因为人眼对不同颜色的敏感度不一样,三种颜色权重也不一样,一般来说绿色最高,红色次之,蓝色最低。这种方法最合理的取值,红、绿、蓝的权重依次是 0.299 、0.587 、 0.114 。为了避免浮点运算,可以用移位替代。
Qt 框架有一个 qGray() 函数,采取加权平均值法计算灰度。 qGray(