图片的黑白处理(二值化)

本文介绍了灰度图像二值化的概念及其在数字图像处理中的重要性,展示了如何使用不同算法(如平均值法、最大值法、加权平均值法)进行二值化处理,并提供了C#代码示例,包括图像数据处理函数和阀值求取方法,强调了动态调节阀值以优化图像处理效果的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

原始圖片:
 

 

黑白處理后圖片:

部分处理代码:

Code:
  1. ……   
  2.   Dim ts2 As IThresholder = New GlobalMeanThreshold(inbmp)   
  3.         Dim tsBMP As New Bitmap(PictureBox1.Width, PictureBox1.Height)   
  4.         ts2.RenderToBitmap(tsBMP)   
  5.         PictureBox6.Image = tsBMP   
  6.         PictureBox6.Height = PictureBox1.Height   
  7.         PictureBox6.Width = PictureBox1.Width   
  8.         PictureBox6.Left = 0   
  9.         PictureBox6.Top = 0   
  10. ……   

理论知识:
灰度图像的二值化处理就是讲图像上的点的灰度置为0或255,也就是讲整个图像呈现出明显的黑白效果。即将256个亮度等级的灰度图像通过适当的阀值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理中,二值图像占有非常重要的地位,特别是在实用的图像处理中,以二值图像处理实现而构成的系统是很多的,要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像,这样子有利于再对图像做进一步处理时,图像的集合性质只与像素值为0或255的点的位置有关,不再涉及像素的多级值,使处理变得简单,而且数据的处理和压缩量小。为了得到理想的二值图像,一般采用封闭、连通的边界定义不交叠的区域。所有灰度大于或等于阀值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。如果某特定物体在内部有均匀一致的灰度值,并且其处在一个具有其他等级灰度值的均匀背景下,使用阀值法就可以得到比较的分割效果。如果物体同背景的差别表现不在灰度值上(比如纹理不同),可以将这个差别特征转换为灰度的差别,然后利用阀值选取技术来分割该图像。动态调节阀值实现图像的二值化可动态观察其分割图像的具体结果。

灰度图像的二值化没有固定的算法,根据图像区域中目标物体的不同而有不同的二值化算法.目前最主要的方法有:最大值法,平均值法,加权平均值法
如下边代码:
 

Code:
  1. Private Function SetBitMapToBlackAndWhite(bmp As Bitmap) As Bitmap    
  2.     Try    
  3.         Dim height As Integer = bmp.Height    
  4.         Dim Width As Integer = bmp.Width    
  5.         Dim newBitMap As New Bitmap(Width, height)    
  6.         Dim pixel As Color    
  7.         For x As Integer = 0 To Width - 1    
  8.             For y As Integer = 0 To height - 1    
  9.                 pixel = bmp.GetPixel(x, y)    
  10.                 Dim r As Integer    
  11.                 Dim g As Integer    
  12.                 Dim b As Integer    
  13.                 Dim Result As Integer    
  14.                 Result = 0    
  15.                 r = pixel.R    
  16.                 g = pixel.G    
  17.                 b = pixel.B    
  18.                 Dim iType As Integer = 2    
  19.                 Select Case iType    
  20.                     Case 0    
  21.                         '平均值法    
  22.                         Result = (r + g + b) / 3    
  23.                         Exit Select    
  24.                     Case 1    
  25.                         '最大值法    
  26.                         If (r > g) Then    
  27.                             Result = r    
  28.                         Else    
  29.                             Result = g    
  30.                         End If    
  31.                            
  32.                         If (Result > b) Then    
  33.                             Result = Result    
  34.                         Else    
  35.                             Result = b    
  36.                         End If    
  37.                            
  38.                         Exit Select    
  39.                     Case 2    
  40.                         '加权平均值    
  41.                         Result = CInt(0.7) * r + CInt(0.2) * g + CInt(0.1) * b    
  42.                         Exit Select    
  43.                 End Select    
  44.                 newBitMap.SetPixel(x, y, Color.FromArgb(Result, Result, Result))    
  45.             Next    
  46.         Next    
  47.         Return newBitMap    
  48.     Catch ex As Exception    
  49.         Return Nothing    
  50.     End Try    
  51. End Function    

该函数实现的简单的图像2值化。
实际使用中最简单的二值化算法就是根据每个像素的灰度值做舍入处理,比如二值化阀值可以设置为0-255的中值127,但是这种的二值化没有根基图像的整体灰度值所在范围做考虑,所以效果很差.
网上流传较广的是根据图像的直方图求取阀值:可以到网上搜索,我就不重复了
介绍我的方法:
图像数据处理函数:由于需要对图像进行指针操作,故使用C#编写源码
 

Code:
  1. public override unsafe void DoThresholding()   
  2.         {   
  3.   
  4.             System.Drawing.Imaging.BitmapData indata = InBMP.LockBits(new Rectangle(0, 0, InBMP.Width, InBMP.Height),   
  5.                 System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);   
  6.             byte* ptr = (byte*)indata.Scan0.ToPointer();   
  7.   
  8.   
  9.             Histogram his = new Histogram(indata, ptr, 0, 0, InBMP.Width, InBMP.Height);   
  10.             int mean = Math.Max((int)his.Mean, 0) * 3;   
  11. //图像阀值   
  12.             int stride = indata.Stride;   
  13.             for (int x = this.Width - 1; x >= 0; x--)   
  14.             {   
  15.                 for (int y = this.Height - 1; y >= 0; y--)   
  16.                 {   
  17.                     int average = (ptr[(y * stride) + (x * 3)] +   
  18.                     ptr[(y * stride) + (x * 3) + 1] +   
  19.                     ptr[(y * stride) + (x * 3) + 2]);   
  20.                     //byte average = (byte)((ptr[(y * indata.Stride) + (x * 3) + 2]));                           
  21.                     if (average > mean)   
  22.                         Data[x, y] = 255;   
  23.                     else  
  24.                         Data[x, y] = 0;   
  25.                 }   
  26.             }   
  27.             InBMP.UnlockBits(indata);   
  28.         }   
  29.     }   

 图像阀值的求取:

Code:
  1. byte[] HistogramData;   
  2.   
  3.         unsafe public Histogram(System.Drawing.Imaging.BitmapData indata, byte* ptr,   
  4.             int left, int top, int width, int height)   
  5.         {   
  6.             HistogramData = new byte[256];   
  7.             for (int i = 0; i < 256; i++)   
  8.                 HistogramData[i] = 0;   
  9.             int right = Math.Min(left + width, indata.Width);   
  10.             int bottom = Math.Min(top + height, indata.Height);   
  11.             int stride = indata.Stride;   
  12.             for (int x = left; x < right; x++)   
  13.             {   
  14.                 for (int y = top; y < bottom; y++)   
  15.                 {   
  16.                     HistogramData[ptr[(y * stride) + (x * 3)]] += 1;   
  17.                     HistogramData[ptr[(y * stride) + (x * 3) + 1]] += 1;   
  18.                     HistogramData[ptr[(y * stride) + (x * 3) + 2]] += 1;   
  19.                 }   
  20.             }   
  21.             CalculateMean();   
  22.             CalculateMinMax();   
  23.         }   
  24.   
  25.         unsafe public Histogram(byte* ptr, int stride, int imgWidth, int imgHeight,   
  26.             int left, int top, int width, int height)   
  27.         {   
  28.             HistogramData = new byte[256];   
  29.             int right = Math.Min(left + width, imgWidth);   
  30.             int bottom = Math.Min(top + height, imgHeight);   
  31.             for (int x = left; x < right; x++)   
  32.             {   
  33.                 for (int y = top; y < bottom; y++)   
  34.                 {   
  35.                     byte average = (byte)((ptr[(y * stride) + (x * 3)] +   
  36.                          ptr[(y * stride) + (x * 3) + 1] +   
  37.                          ptr[(y * stride) + (x * 3) + 2]) / 3);   
  38.                     HistogramData[average] += 1;   
  39.                 }   
  40.             }   
  41.             CalculateMean();   
  42.             CalculateVariance();   
  43.         }   
  44.   
  45.         public byte Mean;   
  46.   
  47.         private int Sum;   
  48.         private int WeightedSum;   
  49.   
  50.         private void CalculateMean()   
  51.         {   
  52.             int sum = 0;   
  53.             int weightedSum = 0;   
  54.             for (int i = 0; i < 256; i++)   
  55.             {   
  56.                 sum += HistogramData[i];   
  57.                 weightedSum += HistogramData[i] * i;   
  58.             }   
  59.             Sum = sum;   
  60.             WeightedSum = weightedSum;   
  61.   
  62.             if (sum > 0)   
  63.                 Mean = (byte)(weightedSum / sum);   
  64.             else  
  65.                 Mean = 0;   
  66.         }   
  67.   

生成黑白图像
 

Code:
  1. public unsafe void RenderToBitmap(Bitmap bmp)   
  2.         {   
  3.             if (Data == null)   
  4.                 DoThresholding();   
  5.             System.Drawing.Imaging.BitmapData outdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),   
  6.                 System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);   
  7.             byte* ptr = (byte*)outdata.Scan0.ToPointer();   
  8.             for (int x = bmp.Width - 1; x >= 0; x--)   
  9.             {   
  10.                 for (int y = bmp.Height - 1; y >= 0; y--)   
  11.                 {   
  12.                     if (this.Data[x, y] > 0)   
  13.                     {   
  14.                         ptr[(y * outdata.Stride) + (x * 3)] = this.Data[x, y];   
  15.                         ptr[(y * outdata.Stride) + (x * 3) + 1] = this.Data[x, y];   
  16.                         ptr[(y * outdata.Stride) + (x * 3) + 2] = this.Data[x, y];   
  17.                     }   
  18.                     else  
  19.                     {   
  20.                         ptr[(y * outdata.Stride) + (x * 3)] = 0;   
  21.                         ptr[(y * outdata.Stride) + (x * 3) + 1] = 0;   
  22.                         ptr[(y * outdata.Stride) + (x * 3) + 2] = 0;   
  23.                     }   
  24.                 }   
  25.             }   
  26.             bmp.UnlockBits(outdata);   
  27.         }   

考虑到图像处理速度问题,所有图像都锁定在内存中进行操作。这样比直接操作速度快了几倍。

附件为Threshold控件,引用到工程里面即可,   Threshold.rar

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值