畢業2年了,一直使用的qt做桌面程序,很少接觸圖像算法類的東西,最近由於項目的原因,不得不了解下圖像處理,不過也是一些簡單的圖像處理,僅此作為記錄,並希望能幫助初學qt圖像處理的朋友。
首先我推薦一篇文章,高斯模糊算法的實現和優化 這篇文章也是我理解圖片模糊的開始,我個人覺得講的相當清楚明了。因此如果對原理或者名詞不理解的同學可以進去一看究竟。下面我說下我自己在項目運用過程中的一心心得,就包括對圖片處理的一些操作,做一記錄。
如果對Qt的圖像儲存相關類不了解,可以看QPixmap/QImage/QPicture 中的講解,比較准確的描述了qt設計這幾個類的目的,其中QImage類可以對圖像進行鏡像轉換、QPixmap可以進行矢量拉伸等。不過這些都是qt自帶的一些操作,但是還有一些特殊處理需要我們自己實現,接下來我就說下圖片模糊處理和圖片圓角處理
一、圖片模糊處理
圖片模糊處理說白了就是需要尋找一套模糊算法來生成模糊濾鏡,然后對圖像上的每一個像素進行處理,問題的關鍵在於模糊算法的實現,本篇開始推薦的文章中高斯模糊其實就是使用高斯函數生成模糊濾鏡的過程,並對圖片進行處理。既然知道了原理,那么其實圖片模糊也就可以用很多方式來做了,畢竟替換高斯函數的方法有很多。文章最后有我自己整理的一個小demo,可以供大家參考。
下面我先貼上幾種模糊函數下的實現效果,為什么要實現這樣的效果呢,呵呵。。因為mac上的qq在換頭像時背景色會自動切換,背景色應該就是通過模糊算法自動生成。
這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 }
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