標籤:qt 影像處理
有時,我們要在只能顯示黑白兩種顏色的顯示裝置上顯示一副灰階映像。這時就要採用所謂的抖動法(Dithering)來類比出灰階效果來。
比如下面這幅圖:
如果只是做個簡單的二值化處理,得到的結果是這樣的(以 128 為閾值)
雖然還能看出這個映像的內容,但是效果並不好。
一種直觀的想法就是在做二值化時引入隨機數,對於所有值為 x 的像素,以 x/256 為機率將這些像素點點亮。下面的代碼就可以實現這個功能。
QImage RandomDithering(QImage &image){ int width = image.width(); int height = image.height(); QImage ret = image.copy(); for(int i = 0; i < height; i ++) { uchar * p = ret.scanLine(i); for(int j = 0; j < width; j ++) { int x = rand() % 256; p[j] = ( x <= p[j] ? 255 : 0 ); } } return ret;}
實際實驗一下,這樣做的效果並不太好。
原因嘛,就是引入了太多的雜訊。其實我們可以抖動的不這麼厲害。下面的代碼就可以控制抖動的大小。
QImage RandomDithering(QImage &image, int dither){ int width = image.width(); int height = image.height(); QImage ret = image.copy(); for(int i = 0; i < height; i ++) { uchar * p = ret.scanLine(i); for(int j = 0; j < width; j ++) { int x = rand() % (2 * dither) - dither; p[j] = (p[j] + x >= 128 ? 255 : 0); } } return ret;}
這個代碼,當 dither 值為 128 時就和上面隨機抖動代碼的結果相同了。如果 dither 值為 0, 那就退化成了簡單的二值化。
當 dither = 50 時,是下面的效果:
dither = 10 時:
可以看出,通過調整 dither ,可以達到不錯的效果。
除了這種隨機抖動法,還有些確定性抖動處理方法,其中最常用的應該算是 Floyd–Steinberg dithering。
這種演算法的介紹可以參考: https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering
下面我也給個我寫的一個實現。
QImage FloydSteinbergDithering(QImage &image){ int width = image.width(); int height = image.height(); QImage ret = image.copy(); for(int i = 0; i < height - 1; i ++) { uchar * p = ret.scanLine(i); uchar *pNext = ret.scanLine(i + 1); for(int j = 0; j < width - 1; j ++) { int diff; if( p[j] > 128 ) { diff = p[j] - 255; p[j] = 255; } else { diff = p[j]; p[j] = 0; } pNext[j] = qBound(0, pNext[j] + diff * 3 / 16, 255); p[j + 1] = qBound(0, p[j + 1] + diff * 3 / 16, 255); pNext[j + 1] = qBound(0, pNext[j + 1] + diff * 1 / 4, 255); } p[width - 1] = (p[width - 1] >= 128 ? 255 : 0); } uchar * p = ret.scanLine(height - 1); for(int j = 0; j < width; j ++) { p[j] = (p[j] >= 128 ? 255 : 0); } return ret;}
用這個演算法得到的映像是這樣的:
效果很不錯,這也是大家都喜歡用它的原因。
當然 Floyd–Steinberg dithering 的參數可以有不同的設定,得到的結果也不同。感興趣的同學可以自己做做實驗。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
抖動法顯示灰階映像(Qt 實現)