Histogram Equalization
當透過 sensor 抓取影像, 我們可能會需要提高影像的品質, 使影像的細節或特徵更為凸顯. 其中一個方法是對影像亮度的分佈進行改變, 此類方法稱為 對比增強. 本文所要介紹的 Cumulative Histogram Equalization(直方圖等化) 法即是影像增強的技術之一.
直方圖等化使用機率分佈, 將原先的亮度分佈重新均勻的等化到新的亮度值. 原來在直方圖分佈中 比較窄化的影像, 例如 : 低對比度的影像, 透過直方圖等化的過程, 其亮度灰階的分佈變成均勻分散, 而成為高對比度的影像. 另外, 對於影像偏暗的部分提高亮度, 偏亮的部分則降低亮度, 使得細節呈現更為清晰.
Cumulative Histogram Equalization 的步驟如下
1. 建立影像的 histogram(PDF).
2. 計算影像的 cumulative distribution function(CDF).
3. 根據 CDF 以及 cumulative equalization 公式 計算灰階亮度的對應關係.
4. 根據對應關係計算出新的灰階亮度.
Histogram (PDF)
影像的 histogram 代表影像中灰階亮度的分佈狀況, 以機率來說稱為 Probability Density Function ; PDF, 如下是計算 PDF 的 pseudo code.
假設灰階範圍是 0~255:
Histogram
images_PDF(0:255) = 0; //clear PDF array
for i = 1 to colume_size
for j = 1 to row_size
level = array(j, i);
images_PDF(level) = images_PDF(level + 1) + 1;
end
end
colume_size以及 row_size 代表影像的列數以及行數, 假設灰階的數值範圍是 0~255, 則 images_PDF 共有 256 個數值, 每個數值代表影像中該灰階數量的統計. 若要將Histogram轉換為機率上的 Probability Density Function ; PDF, 其實需將每一個 Histogram 數值 normalize 到 0~1 之間.我們將normalize留到後面進行.
Cumulative Distribution Function ; CDF
我們要對影像進行 histogram
equalization 需要使用 CDF , CDF 的定義如下:
計算 CDF 的 pseudo code 如下:
Cumulative distribution
function (cdf)
cdf(0:255) = 0; // clear
CDF array
for i = 0 to 255
cdf(i) = cdf(i) + images_PDF(i);
end
以圖一為例, 其 PDF 統計圖形如圖二. CDF 統計圖型如圖三.
影像中每一個灰階值對應的 EH(i) 就是新的灰階值.
例如 灰階值 50 其新的灰階值是EH(50). 所以要對一張影像進行 CHE, 只要將影像上每一個 pixel 的灰階值當作 CEH 陣列的索引.
Cumulative histogram equalization 的程式代碼如下:
01 #include "StdAfx.h" 02 #include "CameraDS.h" 03 #include <cv.h> 04 #include <highgui.h> 05 06 07 #include <stdio.h> 08 09 #define CAP_WIDTH 320 // 640 // 176 10 #define CAP_HEIGHT 240 // 480 // 144 11 #define HISTOGRAM_BIN 256 12 13 int 14 main() 15 { 16 int HistogramBins = HISTOGRAM_BIN; 17 float HistogramRange1[ 2 ] = { 0, 255 }; 18 float *HistogramRange[ 1 ] = { &HistogramRange1[ 0 ] }; 19 int CDF[ HISTOGRAM_BIN+1 ]; 20 int LUT[ HISTOGRAM_BIN+1 ]; 21 22 IplImage* capimg; 23 IplImage* gray_capimg; 24 CvCapture *capture; 25 26 CvHistogram *Gray_Histogram; 27 IplImage *Gray_PDF; 28 IplImage *Gray_CDF; 29 IplImage *Gray_CHE; 30 31 IplImage *CHE_CDF; 32 IplImage *CHE_PDF; 33 CvHistogram *CHE_Histogram; 34 35 int loop = 1; 36 int file_idx = 0; 37 int key; 38 int DeviceCamCount; 39 40 char filename[256]; 41 char fileidx[10]; 42 43 int CamCount = 0; 44 int CamIndex[10]; 45 CCameraDS *pCamDS = NULL; 46 47 pCamDS = new CCameraDS(); 48 DeviceCamCount = pCamDS->CameraCount(); 49 if ( DeviceCamCount == 0 ) 50 { 51 printf( "No Camera detected....\n" ); 52 return(-1); 53 } 54 55 for (int i = 0, j = 0; i < DeviceCamCount; i++) 56 { 57 char szCamName[1024]; 58 59 int retval = pCamDS->CameraName(i, szCamName, sizeof(szCamName)); 60 61 if (retval >0) 62 { 63 printf("Camera #%d's Name is '%s'.\n", i, szCamName); 64 if ( !strcmp( szCamName, "USB µø°T¸Ë¸m" ) ) 65 { 66 CamIndex[ j++ ] = i; 67 CamCount++; 68 } 69 } 70 else 71 { 72 printf("Can not get Camera #%d's name.\n", i); 73 } 74 } 75 76 if ( pCamDS->OpenCamera(CamIndex[0],false,CAP_WIDTH,CAP_HEIGHT)==false) 77 { 78 printf("Camera do not support w=%d:h=%d\n",CAP_WIDTH,CAP_HEIGHT); 79 return (-1); 80 } 81 82 cvNamedWindow( "camera0", 1 ); 83 capimg=pCamDS->QueryFrame(); 84 gray_capimg = cvCreateImage( cvGetSize(capimg), 8, 1 ); 85 86 Gray_PDF = cvCreateImage( cvSize(256,300), 8, 3 ); 87 Gray_CDF = cvCreateImage( cvSize(256,300), 8, 3 ); 88 Gray_CHE = cvCreateImage( cvGetSize(capimg), 8, 1 ); 89 Gray_Histogram = cvCreateHist( 1, &HistogramBins, 90 CV_HIST_ARRAY, HistogramRange ); 91 92 int row, col; 93 while ( loop ) 94 { 95 capimg=pCamDS->QueryFrame(); 96 cvCvtColor(capimg ,gray_capimg, CV_RGB2GRAY); 97 98 cvCalcHist( &gray_capimg, Gray_Histogram ); 99 100 for ( row = 0; row < Gray_PDF->height ; row++ ) 101 { 102 for ( col = 0; col < Gray_PDF->width ; col++ ) 103 { 104 Gray_PDF->imageData[row*Gray_PDF->width*3+ col*3]=255; 105 Gray_PDF->imageData[row*Gray_PDF->width*3+ col*3+1]=128; 106 Gray_PDF->imageData[row*Gray_PDF->width*3+ col*3+2]=0; 107 } 108 } 109 110 for ( row = 0; row < Gray_CDF->height ; row++ ) 111 { 112 for ( col = 0; col < Gray_CDF->width ; col++ ) 113 { 114 Gray_CDF->imageData[row*Gray_CDF->width*3+ col*3]=0; 115 Gray_CDF->imageData[row*Gray_CDF->width*3+ col*3+1]=128; 116 Gray_CDF->imageData[row*Gray_CDF->width*3+ col*3+2]=0; 117 } 118 } 119 120 memset( CDF, 0, sizeof(CDF) ); 121 int sum = 0; 122 int PDFi; 123 float scale = 255.0 / (gray_capimg->width * gray_capimg->height ); 124 for ( int i=0 ; i<HistogramBins ; i++ ) 125 { 126 //printf("%.f \n",((CvMatND *) Histogram1->bins)->data.fl[i]); 127 PDFi = cvQueryHistValue_1D( Gray_Histogram, i ); 128 sum += PDFi; 129 CDF[ i ] = sum; 130 LUT[ i ] = cvRound(sum * scale); 131 cvLine( Gray_PDF,cvPoint(i,300), 132 cvPoint(i,300-(int)( PDFi/15)),CV_RGB(i,i,i) ); 133 cvLine( Gray_CDF,cvPoint(i,300), 134 cvPoint(i,300-(int)( CDF[i]/300)),CV_RGB(i,i,i) ); 135 } 136 137 int test; 138 for ( row = 0; row < gray_capimg->height ; row++ ) 139 { 140 for ( col = 0; col < gray_capimg->width ; col++ ) 141 { 142 int gray = 143 (unsigned char) 144 gray_capimg->imageData[row*gray_capimg->width+col]; 145 Gray_CHE->imageData[row*Gray_CHE->width+col]=LUT[gray]; 146 } 147 } 148 149 150 cvShowImage( "camera0", capimg ); 151 cvShowImage( "gray_camera0", gray_capimg ); 152 cvShowImage( "PDF", Gray_PDF ); 153 cvShowImage( "CDF", Gray_CDF ); 154 155 cvShowImage( "CHE", Gray_CHE ); 156 157 key = cvWaitKey( 5 ); 158 if ( key == 27 ) 159 { 160 loop = 0; 161 } 162 else if (key =='s' || key=='S' ) 163 { 164 sprintf( fileidx, "%03d", file_idx++ ); 165 strcpy( filename, "SAVE_IMG" ); 166 strcat( filename, fileidx ); 167 strcat( filename, ".bmp" ); 168 169 cvSaveImage( filename, capimg ); 170 printf("Image file %s saved.\n", filename); 171 } 172 } 173 174 if ( pCamDS ) 175 { 176 pCamDS->CloseCamera(); 177 delete pCamDS; 178 } 179 cvDestroyWindow( "camera0" ); 180 cvDestroyWindow( "gray_camera0" ); 181 182 if ( capimg ) 183 cvReleaseImage( &capimg ); 184 185 if ( gray_capimg ) 186 cvReleaseImage( &gray_capimg ); 187 188 if (Gray_PDF) 189 cvReleaseImage( &Gray_PDF ); 190 191 if (Gray_CDF) 192 cvReleaseImage( &Gray_CDF ); 193 194 if (Gray_CHE) 195 cvReleaseImage( &Gray_CHE ); 196 197 return(0); 198 }
實驗結果
對圖一的影像進行 CHE, 得到的結果如圖四, 圖五則是 CHE 後影像的 Histogram , 可以發現灰階值均勻分佈. 圖六是 CHE 後的影像的 CDF, 和圖三的 CDF 比較, 可以發現經過 CHE 後, CDF 會趨近於一直線, 直線上的鋸齒是因為CHE 後該灰階值出現的機率為 0.圖四 |
圖五 PDF |
圖六 CDF |
圖七 |
圖八 |
比較圖七和圖八, 圖七是圖八 CHE 後的結果, 對比增強後, 圖七左下角部分的衣服皺折比較明顯.
結論
CHE 雖然可以將影像的對比的提高,
但是 CHE 均勻地將灰階值重新分配的結果會將影像某些區域的對比度過於降低或是將某些區域對比度過於提高, 此外, 灰階值損失的現象可能會造成平均亮度的改變, 這些因素會使得 CHE 後的影像不夠自然.
基本的 CHE 使用的 histogram 來自於整個影像的全域資訊. 無法針對某個區域的特性進行處理. 針對全域 CHE 的缺點, 有區域 CHE (local CHE) 或是 自適性 CHE(Adaptive CHE)的提出. 這種 CHE 將影像切分為多個區域, 對個別區域做CHE, 如此避免了只參考全域資訊的缺點. 但也大幅增加了計算量.
Want to clarify, is it
回覆刪除CEH(i) ... + max_gray_level...
or
CEH(i) ... X max_gray_level...
according to
http://en.wikipedia.org/wiki/Histogram_equalization
it seems to be the latter.
Hi:
回覆刪除You are right, I have fixed this typo, thank you.
Richard Wang
elazığ
回覆刪除erzincan
bayburt
tunceli
sakarya
128
50D63
回覆刪除Bibox Güvenilir mi
Mexc Güvenilir mi
Keep Coin Hangi Borsada
Muş Evden Eve Nakliyat
Chat Gpt Coin Hangi Borsada
Çorum Lojistik
Kilis Şehir İçi Nakliyat
Bartın Evden Eve Nakliyat
Afyon Evden Eve Nakliyat
E4800
回覆刪除Ardahan Rastgele Görüntülü Sohbet Uygulamaları
ardahan en iyi rastgele görüntülü sohbet
kocaeli seslı sohbet sıtelerı
tekirdağ canli sohbet chat
canlı sohbet
Antep Random Görüntülü Sohbet
Ankara Bedava Sohbet
Hatay Bedava Sohbet Chat Odaları
aydın kadınlarla ücretsiz sohbet
4B78D26122
回覆刪除skype güvenilir şov