黑白處理後圖片
原始圖片:
黑白處理後圖片:
部分處理代碼:
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#