二值化是一個相當複雜的理論問題,如果不給出具體的應用要求是無法做的.
最簡單的:
for(......)
if(PixelY[i,j]>T)
PixelY[i,j] = 255;
else
PixelY[i,j] = 0;
如果考慮具體問題,二值化演算法不下100種.
/***************************************************************************
* 函數名稱
* OSTUThreshold()
* 參數
* LPSTR lpDIBBits - 指向源DIB映像指標
* LONG lWidth - 源映像寬度(像素數)
* LONG lHeight - 源映像高度(像素數)
* 傳回值
* BOOL - 運算成功 返回TRUE , 否則 返回FALSE。
* 說明
* 該函數採用大津法進行閾值分割 二值化
***************************************************************************/
BOOL WINAPI OSTUThreshold(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
// 指向源映像像素指標
LPSTR lpSrc;
// 指向緩衝映像指標
LPSTR lpDst;
// 指向緩衝映像像素指標
LPSTR lpNewDIBBits;
HLOCAL hNewDIBBits;
// 迴圈變數
int i, j, t;
// 用於計算兩個地區的中間變數
long lP1, lS1, lP2, lS2;
// 像素值
unsigned char pixel;
// 灰階長條圖數組
long lHistogram[256];
// 閾值, 最大灰階值和最小灰階值, 兩個地區的平均灰階值
unsigned char iThreshold, iNewThreshold, iMaxGrayValue, iMinGrayValue, iMean1GrayValue, iMean2GrayValue;
// 前景點數占映像比例, 背景點數占映像比例
double w0,w1;
// 方差
double G, tempG;
// 映像每行占位元組數
LONG lLineBytes;
// 暫時分配記憶體, 以儲存新映像
hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);
if (hNewDIBBits == NULL)
{
//分配記憶體失敗
return FALSE;
}
// 鎖定記憶體
lpNewDIBBits = (char *) LocalLock(hNewDIBBits);
// 初始化新分配的記憶體, 設定初始值為255
lpDst = (char *) lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight);
lLineBytes = WIDTHBYTES(lWidth * 8);
for(i= 0; i < 256; i++)
{
lHistogram[i] = 0;
}
// 獲得灰階長條圖,灰階最大值和灰階最小值
iMaxGrayValue = 0;
iMinGrayValue = 255;
for(i = 0; i < lWidth; i++)
{
for(j = 0; j < lHeight; j++)
{
lpSrc = (char *) lpDIBBits + lLineBytes * j + i;
pixel = (unsigned char) *lpSrc;
lHistogram[pixel]++;
// 修改最大灰階值和最小灰階值
if (iMinGrayValue > pixel)
{
iMinGrayValue = pixel;
}
if (iMaxGrayValue < pixel)
{
iMaxGrayValue = pixel;
}
}
}
// 遍曆t, 選取最佳閾值
for(t = iMinGrayValue; t < iMaxGrayValue ; t++)
{
iNewThreshold = t;
lP1 = 0;
lS1 = 0;
lP2 = 0;
lS2 = 0;
// 求前景,背景兩個地區的平均灰階值, 點數所佔比例
for(i = iMinGrayValue; i <= iNewThreshold; i++)
{
lP1 += lHistogram[i] * i;
lS1 += lHistogram[i];
}
iMean1GrayValue = (unsigned char) (lP1/lS1);
w0 = (double) (lS1) / (lWidth * lHeight);
for(i = iNewThreshold + 1; i <= iMaxGrayValue; i++)
{
lP2 += lHistogram[i] * i;
lS2 += lHistogram[i];
}
iMean2GrayValue = (unsigned char) (lP2/lS2);
w1 = 1 - w0;
// 計算類間方差
G = (double) w0 * w1
* (iMean1GrayValue - iMean2GrayValue) * (iMean1GrayValue - iMean2GrayValue);
if (G > tempG)
{
tempG = G;
iThreshold = iNewThreshold;
}
}
// 根據閾值將映像二值化
for(i = 0; i < lWidth; i++)
{
for(j = 0; j < lHeight; j++)
{
lpSrc = (char *) lpDIBBits + lLineBytes * j + i;
lpDst = (char *) lpNewDIBBits + lLineBytes * j + i;
pixel = (unsigned char) *lpSrc;
if (pixel <= iThreshold)
{
*lpDst = (unsigned char)0;
}
else
{
*lpDst = (unsigned char) 255;
}
}
}
// 複製映像
memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);
// 釋放記憶體
LocalUnlock(hNewDIBBits);
LocalFree(hNewDIBBits);
// 返回
return TRUE;
}
/*************************************************************************
*
* 函數名稱:
* ThresholdDIB()
*
* 參數:
* LPSTR lpDIBBits - 指向源DIB映像指標
* LONG lWidth - 源映像寬度(象素數)
* LONG lHeight - 源映像高度(象素數)
*
* 傳回值:
* BOOL - 運算成功返回TRUE,否則返回FALSE。
*
* 說明:
* 該函數用 迭代法 對映像進行閾值分割運算。
*
************************************************************************/
BOOL WINAPI ThresholdDIB(LPSTR lpDIBBits,LONG lWidth, LONG lHeight)
{
// 指向源映像的指標
LPSTR lpSrc;
// 指向緩衝映像的指標
LPSTR lpDst;
// 指向緩衝DIB映像的指標
LPSTR lpNewDIBBits;
HLOCAL hNewDIBBits;
//迴圈變數
long i;
long j;
//像素值
unsigned char pixel;
//長條圖數組
long lHistogram[256];
//閾值,最大灰階值與最小灰階值,兩個地區的平均灰階值
unsigned char iThreshold,iNewThreshold,iMaxGrayValue,iMinGrayValue,iMean1GrayValue,iMean2GrayValue;
//用於計算地區灰階平均值的中間變數
long lP1,lP2,lS1,lS2;
//迭代次數
int iIterationTimes;
// 映像每行的位元組數
LONG lLineBytes;
// 暫時分配記憶體,以儲存新映像
hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);
if (hNewDIBBits == NULL)
{
// 分配記憶體失敗
return FALSE;
}
// 鎖定記憶體
lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
// 初始化新分配的記憶體,設定初始值為255
lpDst = (char *)lpNewDIBBits;
memset(lpDst, (BYTE)255, lWidth * lHeight);
// 計算映像每行的位元組數
lLineBytes = WIDTHBYTES(lWidth * 8);
for (i = 0; i < 256;i++)
{
lHistogram[i]=0;
}
//獲得長條圖
iMaxGrayValue = 0;
iMinGrayValue = 255;
for (i = 0;i < lWidth ;i++)
{
for(j = 0;j < lHeight ;j++)
{
// 指向源映像倒數第j行,第i個象素的指標
lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
pixel = (unsigned char)*lpSrc;
lHistogram[pixel]++;
//修改最大,最小灰階值
if(iMinGrayValue > pixel)
{
iMinGrayValue = pixel;
}
if(iMaxGrayValue < pixel)
{
iMaxGrayValue = pixel;
}
}
}
//迭代求最佳閾值
iNewThreshold = (iMinGrayValue + iMaxGrayValue)/2;
iThreshold = 0;
for(iIterationTimes = 0; iThreshold != iNewThreshold && iIterationTimes < 100;iIterationTimes ++)
{
iThreshold = iNewThreshold;
lP1 =0;
lP2 =0;
lS1 = 0;
lS2 = 0;
//求兩個地區的灰階平均值
for (i = iMinGrayValue;i < iThreshold;i++)
{
lP1 += lHistogram[i]*i;
lS1 += lHistogram[i];
}
iMean1GrayValue = (unsigned char)(lP1 / lS1);
for (i = iThreshold+1;i < iMaxGrayValue;i++)
{
lP2 += lHistogram[i]*i;
lS2 += lHistogram[i];
}
iMean2GrayValue = (unsigned char)(lP2 / lS2);
iNewThreshold = (iMean1GrayValue + iMean2GrayValue)/2;
}
//根據閾值將映像二值化
for (i = 0;i < lWidth ;i++)
{
for(j = 0;j < lHeight ;j++)
{
// 指向源映像倒數第j行,第i個象素的指標
lpSrc = (char *)lpDIBBits + lLineBytes * j + i;
// 指向靶心圖表像倒數第j行,第i個象素的指標
lpDst = (char *)lpNewDIBBits + lLineBytes * j + i;
pixel = (unsigned char)*lpSrc;
if(pixel <= iThreshold)
{
*lpDst = (unsigned char)0;
}
else
{
*lpDst = (unsigned char)255;
}
}
}
// 複製映像
memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);
// 釋放記憶體
LocalUnlock(hNewDIBBits);
LocalFree(hNewDIBBits);
// 返回
return TRUE;
}
///////////////////////////////////////////////////////////////
映像的二值化原理和實現 1、 映像的二值化的基本原理映像的二值化處理就是講映像上的
點的灰階置為
0
或255,也就是講整個映像呈現出明顯的黑白效果。即將256個亮度等級的灰階映像通過適當的閥值選取而獲得仍然可以反映映像整體和局部特徵的二值化映像。在數位影像處理中,二值映像佔有非常重要的地位,特別是在實用的影像處理中,以二值影像處理實現而構成的系統是很多的,要進行二值映像的處理與分析,首先要把灰階映像二值化,得到二值化映像,這樣子有利於再對映像做進一步處理時,映像的集合性質只與像素值為0或255的點的位置有關,不再涉及像素的多級值,使處理變得簡單,而且資料的處理和壓縮量小。為了得到理想的二值映像,一般採用封閉、連通的邊界定義不交疊的地區。
所有灰階大於或等於閥值的像素被判定為屬於特定物體,其灰階值為
255
表示,否則這些像素點被排除在物體地區以外,灰階值為0
,表示背景或者例外的物體地區。如果某特定物體在內部有均勻一致的灰階值,並且其處在一個具有其他等級灰階值的均勻背景下,使用閥值法就可以得到比較的分割效果。如果物體同背景的差別表現不在灰階值上(比如紋理不同),可以將這個差別特徵轉換為灰階的差別,然後利用閥值選取技術來分割該映像。動態調節閥值實現映像的二值化可動態觀察其分割映像的具體結果。2、 映像的二值化的程式實現通過Delphi刻度控制項調整閥值,實現動態控制,程式如下:procedure TForm1.Button1Click(Sender: TObject);var p:PByteArray; Gray,x,y:integer;begin TestBMP:=TBitmap.Create; changedbmp:=tbitmap.Create; testbmp.Assign(image1.Picture); for y:=0 to testbmp.Height-1 do begin p:=testbmp.ScanLine[y]; for x:=0 to testbmp.Width-1 do begin
//
首先將映像灰階化 gray:=round(p[x*3+2]*0.3+p[x*3+1]*0.59+p[x*3]*0.11); if gray> TrackBar1.Position then
//
按閥值進行二值化 begin p[x*3]:=255; p[x*3+1]:=255; p[x*3+2]:=255; end else begin p[x*3]:=0;p[x*3+1]:=0;p[x*3+2]:=0; end; end; end; ChangedBmp.Assign(TestBMP); PaintBox1.Canvas.CopyMode:=srccopy; PaintBox1.Canvas.Draw(0,0,ChangedBmp); end;3、 處理的效果
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=886749