最近一直在用FPGA調圖像處理相關的算法,主要是集中在圖像增強和增晰方面。
現在來介紹一個復雜度不高,但確實也還比較好用的圖像增強算法-直方圖均衡。
直方圖均衡的作用,上面也說了,是圖像增強,那是增強什么呢?是增強圖像的對比度。
先來看下在Matlab中實現直方圖均衡的效果吧。
圖片比較隨意,直接對電腦桌面截了一張圖,大家應該能有一個直觀的感受,知道直方圖均衡的作用和效果了吧! ? ?
直方圖均衡在對一些低照度圖像增晰、去霧處理等應用場景,效果還是挺不錯的。
對于直方圖均衡的實現步驟,在網上一搜一大把,大部分講的都是用Matlab或者C語言的代碼實現。 ?
那我們也先來結合Matlab代碼來介紹一下直方圖均衡的實現步驟,之后再說說用FPGA是怎么做的。
?
% [ 第一步 ] 統計每個像素值出現次數 count = zeros(1, 256); for i = 1 : R for j = 1 : C count(1, fx(i, j) + 1) = count(1, fx(i, j) + 1) + 1; end end第一步,是對于一整幅圖像進行像素值統計,當然咱們這是對灰度圖像進行直方圖均衡,所以統計的像素值大小范圍是 0-255。 ?
這一步是統計 0-255 這 256 個像素點的值,在整幅圖像中出現的次數。
% [ 第二步 ] 統計每個像素值出現的概率, 得到概率直方圖 T = zeros(1, 256); T = double(T); count = double(count); for i = 1 : 256 ????T(1,?i)?=?count(1,?i)?/?(R?*?C);?%?R?和?C為圖像長和寬 end? 第二步,將像素點統計出來的出現次數除以圖像的總像素點,計算出各個灰度值出現的概率。
?
?
% [ 第三步 ] 求累計概率,得到累計直方圖 for i = 2 : 256 T(1, i) = T(1, i - 1) + T(1, i); end第三步,單看代碼,似乎不太好理解,這一步算的累計概率是怎么算的呢?
?
第 1 個結果,像素值為 0 的概率 + 像素值為 1 的概率; 第 2 個結果,像素值為 0 的概率 +像素值為 1 的概率 + 像素值為 2 的概率; 。。。 第 255 個結果,像素值為 0 的概率 +像素值為 1 的概率 + 像素值為 2 的概率 + ... + 像素值為 255 的概率。其實就是等于 1 。
其實這一步,總共會得出 256 個結果,還要算上像素值為 0 的概率,因為在第二步中已經算出來了單個像素點的概率,所以就沒有再次算了, for 循環里面寫的就是 2 - 256 了。
?
% [ 第四步 ] 完善映射函數 for i = 1 : 256 T(1, i) = T(1, i) * 255; end
?
第四步,是完善映射函數。
從原圖到直方圖均衡化之后的圖像,之間肯定存在一個函數 f(x),類似的 img_out = f(img_in)?。 ?
也就是從原圖進行直方圖均衡需要有一個函數表示他們之間的關系。
而這一步就是完善這個函數,其實就是對第三步得出的累計概率分布結果 * 255 。 ? ?
注意,這個映射函數其實是一個離散值,總共有 256 個值。
?
% [ 第五步 ] 完成每個像素點的映射 fy = double(fx); for i = 1 : R for j = 1 : C fy(i, j) = T(1, fy(i, j) + 1); end end
?
這是最后一步了,把原圖經過第四步的映射函數,得到直方圖均衡化之后的圖像結果。
這一步,給大家再解釋一下,其實就是把輸入圖像的像素值,作為映射函數這個一維數組相應元素的下標,去找到對應下標元素的值。并把這個值作為直方圖均衡化的結果輸出。
對于直方圖均衡的處理,從流程上來看,其實是很簡單的。 ?
當然對于有些書,會給你列出一堆的公式。作為一個畢業多年的老油條,對那些公式早就不敏感了。 ?
所以在文章里面,就直接開門見山的給大家說步驟了,這也算是對那些也像我這種對數學公式早已不感冒的朋友的一份愛惜吧!
對于原理部分,貼著 Matlab 代碼說完了,那就是再說說在FPGA里面的實現步驟吧。
用FPGA來實現直方圖均衡,我把上面的步驟稍微做了一點改變。 ?
第一步,依然統計0-255這256個像素點出現的次數。
第二步,沒有計算各個像素點出現的概率,而是統計各個像素點出現的累計次數。
也是得到 256 個結果: 第 1 個結果,像素點為0出現的次數; 第 2 個結果,像素點為 0 出現的次數 + 像素點為1出現的次數; 第 3 個結果,像素點為?0 出現的次數 + 像素點為1出現的次數 + 素點為2出現的次數;
依次類推。
第三步,將第二步的結果 *255*2,就是比剛剛在 Matlab 中,多乘上了 2 ,這樣做的目的,是因為在FPGA里面沒有進行小數運算,所以先乘上 2 ,?為后面的運算稍稍提高一下精度。
第四步,將第三步的結果除以整幅圖片的像素點個數。
第五步,完成直方圖均衡對輸入像素點值的映射。 ?
這里要注意,因為攝像頭那邊的數據是連續過來的,如果像 Matlab 那樣,先計算好當前圖像的映射函數,再把當前圖像作為輸入,給到映射函數再得出直方圖均衡的結果,這個時間是等不起的。 ?
所以這里我進行了一定的簡化,我是以前一幀圖像完善的映射函數作為當前幀圖像的映射函數。 ?
這種做法,其實是完全可行的,咱們攝像頭圖像的幀速率一般是 30fps ,也就是在 1 秒鐘里面可以有 30 幅圖像,只要攝像頭采集的畫面變化速度在一定范圍里面,咱們這樣做是完全 OK 的,而且我用的攝像頭是MT9V034,是全局曝光的。
是的,這就是我這幾天剛剛組裝好的 MT9V034 攝像頭,打樣了幾片PCB,裝上了 CS 大鏡頭,OV5640 瞬間 變身小弟,哈哈!!!感覺綠色的板子看著有點low,之后再換成黑色阻焊看看!??
對于圖像的增強效果還是很明顯的。
在調試直方圖均衡這個算法的時候,剛開始調的很郁悶。
完全搞不明白為啥,極其郁悶。
反復檢查了代碼,也跑了仿真,沒發現問題啊。?
難不成直方圖均衡后的效果就是這個鬼樣子。然后也在網上搜,看看有沒有用FPGA做直方圖均衡后的效果圖,來比較一下。
搜了半天,找到的全都是用Matlab 或者其他什么軟件語言做的效果圖,我要這些效果圖干啥,勞資這邊多的是!
之后又在知網下了好幾篇FPGA的直方圖均衡的論文,想看看論文里面有沒有效果圖,大多又是Matlab的效果圖,無語。。。
郁悶了一晚上,到第二天上午,把腦袋放空,重新歸零。回憶這種現象,想起來在之前調的一個圖像增強算法也出現了類似的效果。 ?
一時記不起來當時是怎么解決的,非常后悔,要是當時寫了一份調試記錄該多好。劃重點,寫調試記錄,是非常重要的!
想了很久,當時出現這種情況,似乎是VGA顯示的數據,對要顯示的數據源截位有問題。 ?
舉個例子,VGA要顯示灰度圖像的8個bit,但是你要給VGA顯示的圖像數據有16個bit,理應是把16bit的高8bit給VGA顯示,但是卻把[12:5]?這8個bit 給了VGA顯示。
但是這個問題,是在哪個地方出現了截位的問題呢?又想了很久,懷疑是除法器的IP Core。
除法器的dout_tdata,這個端口,包含了商的結果和小數部分,那商的結果也就是整數部分占多少bit,小數部分占多少bit?
在代碼里面,在對div_dout這個信號去把商的結果拿出來,在這個環節出現了截位的問題。果真,改了之后,結果馬上正常了。
審核編輯:劉清
評論
查看更多