當前位置:編程學習大全網 - 源碼下載 - VB.NET圖片的黑白處理法(二值化)

VB.NET圖片的黑白處理法(二值化)

原始圖片

黑白處理後圖片

原始圖片:

黑白處理後圖片:

部分處理代碼:

code

Dim ts2 As IThresholder = New GlobalMeanThreshold(inbmp)

Dim tsBMP As New Bitmap(PictureBox1.Width, PictureBox1.Height)

ts2.RenderToBitmap(tsBMP)

PictureBox6.Image = tsBMP

PictureBox6.Height = PictureBox1.Height

PictureBox6.Width = PictureBox1.Width

PictureBox6.Left = 0

PictureBox6.Top = 0

理論知識:

灰度圖像的二值化處理就是講圖像上的點的灰度置為0或255,也就是講整個圖像呈現出明顯的黑白效果。即將256個亮度等級的灰度圖像通過適當的閥值選取而獲得仍然可以反映圖像整體和局部特征的二值化圖像。在數字圖像處理中,二值圖像占有非常重要的地位,特別是在實用的圖像處理中,以二值圖像處理實現而構成的系統是很多的,要進行二值圖像的處理與分析,首先要把灰度圖像二值化,得到二值化圖像,這樣子有利於再對圖像做進壹步處理時,圖像的集合性質只與像素值為0或255的點的位置有關,不再涉及像素的多級值,使處理變得簡單,而且數據的處理和壓縮量小。為了得到理想的二值圖像,壹般采用封閉、連通的邊界定義不交疊的區域。所有灰度大於或等於閥值的像素被判定為屬於特定物體,其灰度值為255表示,否則這些像素點被排除在物體區域以外,灰度值為0,表示背景或者例外的物體區域。如果某特定物體在內部有均勻壹致的灰度值,並且其處在壹個具有其他等級灰度值的均勻背景下,使用閥值法就可以得到比較的分割效果。如果物體同背景的差別表現不在灰度值上(比如紋理不同),可以將這個差別特征轉換為灰度的差別,然後利用閥值選取技術來分割該圖像。動態調節閥值實現圖像的二值化可動態觀察其分割圖像的具體結果。

灰度圖像的二值化沒有固定的算法,根據圖像區域中目標物體的不同而有不同的二值化算法.目前最主要的方法有:最大值法,平均值法,加權平均值法

如下邊代碼:

Private Function SetBitMapToBlackAndWhite(bmp As Bitmap) As Bitmap

Try

Dim height As Integer = bmp.Height

Dim Width As Integer = bmp.Width

Dim newBitMap As New Bitmap(Width, height)

Dim pixel As Color

For x As Integer = 0 To Width - 1

For y As Integer = 0 To height - 1

pixel = bmp.GetPixel(x, y)

Dim r As Integer

Dim g As Integer

Dim b As Integer

Dim Result As Integer

Result = 0

r = pixel.R

g = pixel.G

b = pixel.B

Dim iType As Integer = 2

Select Case iType

Case 0

'平均值法

Result = (r + g + b) / 3

Exit Select

Case 1

'最大值法

If (r

g) Then

Result = r

Else

Result = g

End If

If (Result

b) Then

Result = Result

Else

Result = b

End If

Exit Select

Case 2

'加權平均值

#p#副標題#e#

Result = CInt(0.7) * r + CInt(0.2) * g + CInt(0.1) * b

Exit Select

End Select

newBitMap.SetPixel(x, y, Color.FromArgb(Result, Result, Result))

Next

Next

Return newBitMap

Catch ex As Exception

Return Nothing

End Try

End Function

該函數實現的簡單的圖像2值化。

實際使用中最簡單的二值化算法就是根據每個像素的灰度值做舍入處理,比如二值化閥值可以設置為0-255的中值127,但是這種的二值化沒有根基圖像的整體灰度值所在範圍做考慮,所以效果很差.

網上流傳較廣的是根據圖像的直方圖求取閥值:可以到網上搜索,我就不重復了

介紹我的方法:

public override unsafe void DoThresholding()

{

System.Drawing.Imaging.BitmapData indata = InBMP.LockBits(new Rectangle(0, 0, InBMP.Width, InBMP.Height),

System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

byte* ptr = (byte*)indata.Scan0.ToPointer();

Histogram his = new Histogram(indata, ptr, 0, 0, InBMP.Width, InBMP.Height);

int mean = Math.Max((int)his.Mean, 0) * 3;

//圖像閥值

int stride = indata.Stride;

for (int x = this.Width - 1; x = 0; x--)

{

for (int y = this.Height - 1; y = 0; y--)

{

int average = (ptr[(y * stride) + (x * 3)] +

ptr[(y * stride) + (x * 3) + 1] +

ptr[(y * stride) + (x * 3) + 2]);

//byte average = (byte)((ptr[(y * indata.Stride) + (x * 3) + 2]));

if (average

mean)

Data[x, y] = 255;

else

Data[x, y] = 0;

}

}

InBMP.UnlockBits(indata);

}

}

byte[] HistogramData;

unsafe public Histogram(System.Drawing.Imaging.BitmapData indata, byte* ptr,

int left, int top, int width, int height)

{

HistogramData = new byte[256];

for (int i = 0; i

256; i++)

HistogramData[i] = 0;

int right = Math.Min(left + width, indata.Width);

int bottom = Math.Min(top + height, indata.Height);

int stride = indata.Stride;

for (int x = left; x

right; x++)

{

for (int y = top; y

bottom; y++)

{

HistogramData[ptr[(y * stride) + (x * 3)]] += 1;

HistogramData[ptr[(y * stride) + (x * 3) + 1]] += 1;

HistogramData[ptr[(y * stride) + (x * 3) + 2]] += 1;

}

}

CalculateMean();

CalculateMinMax();

}

unsafe public Histogram(byte* ptr, int stride, int imgWidth, int imgHeight,

int left, int top, int width, int height)

{

HistogramData = new byte[256];

int right = Math.Min(left + width, imgWidth);

int bottom = Math.Min(top + height, imgHeight);

for (int x = left; x

right; x++)

{

for (int y = top; y

bottom; y++)

{

byte average = (byte)((ptr[(y * stride) + (x * 3)] +

ptr[(y * stride) + (x * 3) + 1] +

ptr[(y * stride) + (x * 3) + 2]) / 3);

HistogramData[average] += 1;

}

}

CalculateMean();

CalculateVariance();

}

public byte Mean;

private int Sum;

private int WeightedSum;

private void CalculateMean()

{

int sum = 0;

int weightedSum = 0;

for (int i = 0; i

256; i++)

{

sum += HistogramData[i];

weightedSum += HistogramData[i] * i;

}

Sum = sum;

WeightedSum = weightedSum;

if (sum

0)

Mean = (byte)(weightedSum / sum);

else

Mean = 0;

}

生成黑白圖像

public unsafe void RenderToBitmap(Bitmap bmp)

{

if (Data == null)

DoThresholding();

System.Drawing.Imaging.BitmapData outdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),

System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

byte* ptr = (byte*)outdata.Scan0.ToPointer();

for (int x = bmp.Width - 1; x = 0; x--)

{

for (int y = bmp.Height - 1; y = 0; y--)

{

if (this.Data[x, y]

0)

{

ptr[(y * outdata.Stride) + (x * 3)] = this.Data[x, y];

ptr[(y * outdata.Stride) + (x * 3) + 1] = this.Data[x, y];

ptr[(y * outdata.Stride) + (x * 3) + 2] = this.Data[x, y];

}

else

{

ptr[(y * outdata.Stride) + (x * 3)] = 0;

ptr[(y * outdata.Stride) + (x * 3) + 1] = 0;

ptr[(y * outdata.Stride) + (x * 3) + 2] = 0;

}

}

}

bmp.UnlockBits(outdata);

}

考慮到圖像處理速度問題,所有圖像都鎖定在內存中進行操作。這樣比直接操作速度快了幾倍。

#p#副標題#e#

  • 上一篇:java裏同步是什麽意思
  • 下一篇:程序設計題目四 倉庫產品管理系統
  • copyright 2024編程學習大全網