EmguCV Image Process: Counting the Pixels with Histograms
參考OpenCV 2 Computer Vision Application Programming Cookbook第四章
介紹內容如下:
Computing the image histogram
Applying look-up tables to modify image appearance
Equalizing the image histogram
Equalizing the image histogram
Backprojecting a histogram to detect specific image content
Using the mean shift algorithm to find an object
上一篇介紹了histogram,通常中文翻譯成直方圖
可以發現直方圖是透過每個pixel的intensity value來呈現一張影像
所以分析一張影像中pixel的分佈對於修改或是改善影像是很有用的資訊
這裡介紹如何用一個簡單的mapping function
透過一個look-up table來修改影像中一些pixels的值
一個look-up table是一個簡單的一對一或是多對一的函式
其中定義了如何將pixels的值轉換成新的值
若是以灰階的影像來說
一個一維的陣列,包含256個entries
在table的第i個entry則傳出相對應灰階值的新值
newIntensity = Lookup[oldIntensity];像這樣的對應方式
在EmguCV中並無實作出Lookup table的方法
但可透過CvInvoke來呼叫
使用Matrix<Byte>的型別來表示look-up table
用法如下:
Image<Gray, Byte> ApplyLookUp(Image<Gray, Byte> image, Matrix<Byte> lookupTable) { //the output image Image<Gray,byte> result = image.CopyBlank(); //apply lookup table CvInvoke.cvLUT(image, result, lookupTable); return result; }用法非常簡單!!
這裡要注意就是傳入的result要先建立成跟來源影像同大小的影像才行
然後把來源影像、目的影像跟look-up table傳入cvLUT這個方法就可以了!
這裡來試試一個inverse的效果
//Load input image Image<Gray, Byte> image = new Image<Gray, Byte>(@"image.jpg"); //Create an image inversion table Matrix<Byte> lookupTable = new Matrix<Byte>(new Size(1, 256)); for (int i = 0; i < 256; i++) { lookupTable[i, 0] = (Byte)(255 - i); } Image<Gray, Byte> result = ApplyLookUp(image, lookupTable);建立一個inversion look-up table
table的值,透過一個for迴圈塞入反向的值(255-i)
就可以取得inverse後的影像
結果影像,看起來是不是很詭異~XD
這時候就可以跟上一篇介紹的直方圖整合來做一些影像處理
這邊示範如何加強影像的對比
首先取得原始影像的直方圖
透過直方圖可以很輕鬆發現影像所有pixels的值的分佈位於0~255那些區間
可以找出那些區間是沒有pixels存在的(可能沒有全白(255)或是全黑(0)的pixel)
這時候將直方圖做延伸(stretch),就能夠擴大影像的對比度
講白一點,就是讓影像深色的部分更深,淺色的部分更淺,就會增加對比!!
(黑的更黑~白得更白!!)
前提是我們必須知道直方圖裡頭最小的值(min)和最大的值(max)落在哪裡
然後將最小的值擴展到真正的最小值0
最大的值擴展到真正最大值255
簡單的公式如下: 255.0 * ((i - min) / (max - min) + 0.5);
那就來看程式怎麼寫:
Image<Gray, Byte> Stretch(Image<Gray, Byte> image, int minValue) { //Compute histogram first DenseHistogram histogram = GetHistogram(image); float[] hist = new float[256]; histogram.MatND.ManagedArray.CopyTo(hist, 0); //find left extremity of the histogram int min = 0; for (; min < hist.Length; min++) { if (hist[min] > minValue) break; } //find right extremity of the histogram int max = hist.Length - 1; for (; max >= 0; max--) { if (hist[max] > minValue) break; } //Create lookup table Matrix<Byte> lookupTable = new Matrix<Byte>(new Size(1, 256)); for (int i = 0; i < 256; i++) { //stretch between minLocation and maxLocation if (i < min) lookupTable[i, 0] = 0; else if (i > max) lookupTable[i, 0] = 255; else lookupTable[i, 0]= (Byte)(255.0 * (i - min) / (max - min) + 0.5); } //Apply lookup table return ApplyLookUp(image, lookupTable); }由傳入的引數minValue來決定左右邊界的閥值
這邊minValue設定成0的話
影像中若是剛好有一個黑(0)點、一個白點(255)
這張影像就不會受到處理
所以可以帶入一個較大的值來取得較好的結果
//Ignore starting and ending bins with less than 100 pixels Image<Gray, Byte> result = Stretch(image,100);若是設定成100,就會忽略掉左邊、右邊小於100個pixels的位置
由於我們原始提供的影像的對比度相當完美
分佈均勻、0~255皆有值分佈,所以跑出來的結果如下:
原本對比就很高,再去做stretch也還是一樣!!
所以這邊再提供一張降低對比的影像來做測試:
可以發現影像變得比較黯淡
這時候一樣再透過stretch來處理
有沒有發現,好像又變成原始那張影像一樣了!!
但是其實仔細看還是會發現有些地方不一樣
尤其是樹林的部分
原本的樹林在影像中屬於比較暗的部分
若是在一開始提供的影像
就已經在暗部失去細節的話
就算透過影像處理,拉高對比,也還是救不回來!!!
Equalizing the image histogram
也就是說,一個品質好的影像
應該在所有的intensity中(0~255)平均的分佈
上面的stretch的方法
並不會改變每一個bin中的pixels數量
而在許多的影像處理中
都會提到的histogram equalization
就是用上述的概念來實作的
這個方法會重新把pixels更平均的分佈在各個bin中
在EmguCV能夠很輕易的實作這個方法:
image._EqualizeHist();就這麼一行!
這裡一樣讀入經過降低對比的影像
結果如下:
就是讓pixels更平均的分佈在每個bin中
這樣的結果雖然並不算完美
但這在許多影像處理中都會用的到喔!!
下一篇將介紹簡單的影像偵測!!
沒有留言:
張貼留言