毕业2年了,一直使用的qt做桌面程序,很少接触图像算法类的东西,最近由于项目的原因,不得不了解下图像处理,不过也是一些简单的图像处理,仅此作为记录,并希望能帮助初学qt图像处理的朋友。
首先我推荐一篇文章,高斯模糊算法的实现和优化这篇文章也是我理解图片模糊的开始,我个人觉得讲的相当清楚明了。因此如果对原理或者名词不理解的同学可以进去一看究竟。下面我说下我自己在项目运用过程中的一心心得,就包括对图片处理的一些操作,做一记录。
如果对Qt的图像储存相关类不了解,可以看QPixmap/QImage/QPicture中的讲解,比较准确的描述了qt设计这几个类的目的,其中QImage类可以对图像进行镜像转换、QPixmap可以进行矢量拉伸等。不过这些都是qt自带的一些操作,但是还有一些特殊处理需要我们自己实现,接下来我就说下图片模糊处理和图片圆角处理
一、图片模糊处理
图片模糊处理说白了就是需要寻找一套模糊算法来生成模糊滤镜,然后对图像上的每一个像素进行处理,问题的关键在于模糊算法的实现,本篇开始推荐的文章中高斯模糊其实就是使用高斯函数生成模糊滤镜的过程,并对图片进行处理。既然知道了原理,那么其实图片模糊也就可以用很多方式来做了,毕竟替换高斯函数的方法有很多。文章最后有我自己整理的一个小demo,可以供大家参考。
下面我先贴上几种模糊函数下的实现效果,为什么要实现这样的效果呢,呵呵。。因为mac上的qq在换头像时背景色会自动切换,背景色应该就是通过模糊算法自动生成。
图1 高斯函数模糊
图2 直线函数模糊
图3 算术平均值模糊
这3种模糊都是使用了Blur1D方法进行滤镜处理,通过测试Blur1D方法比Blur2D方法快接近10倍。这个方法的优化,在本文推荐的第一篇文章中就有详细说明,如图4所示
图4 高斯优化说明
具体细节处理请看原文中描述。在这里我只贴出使用高斯一维函数处理的滤镜,和使用滤镜对照片上每一个像素进行处理的代码,代码如下:
1 //高斯模糊算法 一维(O(2*x*y*2r))形式的高斯函数 比二维(O(x*y*(2r)^2))效率高 对应Blur1D滤镜算法 2 void Gauss(filter_t& kernel, long radius) 3 { 4 kernel.set(radius, Diamet(radius)); 5 6 static const double SQRT2PI = sqrt(2.0 * PI); 7 8 double sigma = (double)radius / 3.0; 9 double sigma2 = 2.0 * sigma * sigma; 10 double sigmap = sigma * SQRT2PI; 11 12 for (long n = 0, i = -kernel.radius(); i <= kernel.radius(); ++i, ++n) 13 kernel[n] = exp(-(double)(i * i) / sigma2) / sigmap; 14 }
下面的代码是对应高斯一维处理函数的图片像素点处理方法:
1 void Blur1D(bitmap_t& bitmap, filter_t& kernel) 2 { 3 Normalization(kernel); 4 5 buffer_t buff(bitmap); 6 7 for (long inx = 0, y = 0; y < bitmap.h(); ++y) 8 { 9 for (long x = 0; x < bitmap.w(); ++x, ++inx) 10 { 11 for (long n = 0, i = -kernel.radius(); i <= kernel.radius(); ++i, ++n) 12 { 13 long i_k = Edge(i, x, bitmap.w()); 14 long inx_k = inx + i_k; 15 buff[inx].r += bitmap[inx_k].r * kernel[n]; 16 buff[inx].g += bitmap[inx_k].g * kernel[n]; 17 buff[inx].b += bitmap[inx_k].b * kernel[n]; 18 } 19 } 20 } 21 22 for (long inx = 0, x = 0; x < bitmap.w(); ++x) 23 { 24 for (long y = 0; y < bitmap.h(); ++y) 25 { 26 inx = y * bitmap.w() + x; 27 double r = 0.0, g = 0.0, b = 0.0; 28 for (long n = 0, i = -kernel.radius(); i <= kernel.radius(); ++i, ++n) 29 { 30 long i_k = Edge(i, y, bitmap.h()); 31 long inx_k = inx + i_k * bitmap.w(); 32 r += buff[inx_k].r * kernel[n]; 33 g += buff[inx_k].g * kernel[n]; 34 b += buff[inx_k].b * kernel[n]; 35 } 36 bitmap[inx].r = Clamp<bitmap_t::channel_t>(r); 37 bitmap[inx].g = Clamp<bitmap_t::channel_t>(g); 38 bitmap[inx].b = Clamp<bitmap_t::channel_t>(b); 39 } 40 } 41 }
理解了上边的代码后,只需要下面几行代码,就可以生成模糊后的图片,其中resultImage是输出型参数,模糊后的图片存放在其中。
1 filter::bitmap_t bmp; 2 bmp.set((filter::bitmap_t::pixel_t*)resultImage.bits(), 3 resultImage.width(), resultImage.height()); 4 5 filter::Filter(pair[4], bmp, radius);
初次之外demo中还提到了一个检测算法时间复杂度的方法,通过调用该方法可以检测每个图片处理过程的时间长短。
1 #define CHECK_TIME(text, ...) 2 { 3 clock_t t1 = std::clock(); 4 { __VA_ARGS__; } 5 clock_t t2 = std::clock(); 6 qDebug() << #__VA_ARGS__ << text << "->" << (long)((double)(t2 - t1) / (double)(CLOCKS_PER_SEC) * 1000.0); 7 }
二、图片圆角处理
上边讲述了图片的模糊处理,其实说白了也就是对图像的每一个像素进行指定的滤镜操作,最终形成 一张新的图片。接下来我们要讲述的是根据一张矩形图来生成一张圆角矩形图,方式有2种我将分别介绍,个人根据自己的情况使用。
1、纯代码处理
纯代码处理,顾名思义也就是不需要外来的资源帮忙,其实原理也就是这样,通过给原来的图片设置掩码图像来生成圆角,也即我们需要自己从内存中绘制一张掩码图像,周围是透明的,里面是一个不透明的圆角矩形。效果如图5所示,实现代码如下:
1 QPixmap PixmapToRound(const QPixmap & img, int radius) 2 { 3 if (img.isNull()) 4 { 5 return QPixmap(); 6 } 7 8 QSize size(img.size()); 9 QBitmap mask(size); 10 QPainter painter(&mask); 11 painter.setRenderHint(QPainter::Antialiasing); 12 painter.setRenderHint(QPainter::SmoothPixmapTransform); 13 painter.fillRect(mask.rect(), Qt::white); 14 painter.setBrush(QColor(0, 0, 0)); 15 painter.drawRoundedRect(mask.rect(), radius, radius); 16 17 QPixmap image = img;// .scaled(size); 18 image.setMask(mask); 19 return image; 20 }
图5 圆角预览
2、蒙版实现
所谓蒙版实现其实原理和方式1类似,只是上图上的掩码图片需要设计师类提供,这样的设计就需要设计师设计出多套蒙版,效果和图5一样,diamante如下:
1 QPixmap PixmapToRound(const QPixmap & img, const QPixmap & mengban, QSize size) 2 { 3 if (img.isNull()) 4 { 5 return QPixmap(); 6 } 7 QImage resultImage(size, QImage::Format_ARGB32_Premultiplied); 8 QPixmap mask(mengban.scaled(size)); //蒙层图片 9 10 QPainter painter(&resultImage); 11 painter.setRenderHints(QPainter::SmoothPixmapTransform); 12 painter.setCompositionMode(QPainter::CompositionMode_Source); 13 painter.fillRect(resultImage.rect(), Qt::transparent); 14 painter.setCompositionMode(QPainter::CompositionMode_SourceOver); 15 painter.drawPixmap(0, 0, mask); 16 painter.setCompositionMode(QPainter::CompositionMode_SourceOut); 17 painter.drawPixmap(0, 0, img.scaled(size)); 18 painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); 19 painter.end(); 20 21 return QPixmap::fromImage(resultImage); 22 }
demo下载链接:http://download.csdn.net/detail/qq_30392343/9591008