记录一个优秀的图像二值化代码

#region 二值化02

        public Bitmap binaryzation(Bitmap srcBitmap, Bitmap dstBitmap)
        {
            int threshold = 0;
            Byte[,] BinaryArray = ToBinaryArray(srcBitmap, out threshold);
            dstBitmap = BinaryArrayToBinaryBitmap(BinaryArray);
            return dstBitmap;
        }

        /// <summary>
        /// 全局阈值图像二值化
        /// </summary>
        /// <param name="bmp">原始图像</param>
        /// <param name="method">二值化方法</param>
        /// <param name="threshold">输出:全局阈值</param>
        /// <returns>二值化后的图像数组</returns>
        public static Byte[,] ToBinaryArray(Bitmap bmp, out int threshold)
        {   // 位图转换为灰度数组
            Byte[,] GrayArray = ToGrayArray(bmp);

            // 计算全局阈值
            threshold = OtsuThreshold(GrayArray);

            // 根据阈值进行二值化
            int PixelHeight = bmp.Height;
            int PixelWidth = bmp.Width;
            Byte[,] BinaryArray = new Byte[PixelHeight, PixelWidth];
            for (int i = 0; i < PixelHeight; i++)
            {
                for (int j = 0; j < PixelWidth; j++)
                {
                    BinaryArray[i, j] = Convert.ToByte((GrayArray[i, j] > threshold) ? 255 : 0);
                }
            }

            return BinaryArray;
        }

        /// <summary>
        /// 大津法计算阈值
        /// </summary>
        /// <param name="grayArray">灰度数组</param>
        /// <returns>二值化阈值</returns>
        public static int OtsuThreshold(Byte[,] grayArray)
        {   // 建立统计直方图
            int[] Histogram = new int[256];
            Array.Clear(Histogram, 0, 256);     // 初始化
            foreach (Byte b in grayArray)
            {
                Histogram[b]++;                 // 统计直方图
            }

            // 总的质量矩和图像点数
            int SumC = grayArray.Length;    // 总的图像点数
            Double SumU = 0;                  // 双精度避免方差运算中数据溢出
            for (int i = 1; i < 256; i++)
            {
                SumU += i * Histogram[i];     // 总的质量矩
            }

            // 灰度区间
            int MinGrayLevel = Array.FindIndex(Histogram, NonZero);       // 最小灰度值
            int MaxGrayLevel = Array.FindLastIndex(Histogram, NonZero);   // 最大灰度值

            // 计算最大类间方差
            int Threshold = MinGrayLevel;
            Double MaxVariance = 0.0;       // 初始最大方差
            Double U0 = 0;                  // 初始目标质量矩
            int C0 = 0;                   // 初始目标点数
            for (int i = MinGrayLevel; i < MaxGrayLevel; i++)
            {
                if (Histogram[i] == 0) continue;

                // 目标的质量矩和点数
                U0 += i * Histogram[i];
                C0 += Histogram[i];

                // 计算目标和背景的类间方差
                Double Diference = U0 * SumC - SumU * C0;
                Double Variance = Diference * Diference / C0 / (SumC - C0); // 方差
                if (Variance > MaxVariance)
                {
                    MaxVariance = Variance;
                    Threshold = i;
                }
            }

            // 返回类间方差最大阈值
            return Threshold;
        }

        /// <summary>
        /// 检测非零值
        /// </summary>
        /// <param name="value">要检测的数值</param>
        /// <returns>
        ///     true:非零
        ///     false:零
        /// </returns>
        private static Boolean NonZero(int value)
        {
            return (value != 0) ? true : false;
        }

        /// <summary>
        /// 将位图转换为灰度数组(256级灰度)
        /// </summary>
        /// <param name="bmp">原始位图</param>
        /// <returns>灰度数组</returns>
        public static Byte[,] ToGrayArray(Bitmap bmp)
        {
            int PixelHeight = bmp.Height; // 图像高度
            int PixelWidth = bmp.Width;   // 图像宽度
            int Stride = ((PixelWidth * 3 + 3) >> 2) << 2;    // 跨距宽度
            Byte[] Pixels = new Byte[PixelHeight * Stride];

            // 锁定位图到系统内存
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, PixelWidth, PixelHeight), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            Marshal.Copy(bmpData.Scan0, Pixels, 0, Pixels.Length);  // 从非托管内存拷贝数据到托管内存
            bmp.UnlockBits(bmpData);    // 从系统内存解锁位图

            // 将像素数据转换为灰度数组
            Byte[,] GrayArray = new Byte[PixelHeight, PixelWidth];
            for (int i = 0; i < PixelHeight; i++)
            {
                int Index = i * Stride;
                for (int j = 0; j < PixelWidth; j++)
                {
                    GrayArray[i, j] = Convert.ToByte((Pixels[Index + 2] * 19595 + Pixels[Index + 1] * 38469 + Pixels[Index] * 7471 + 32768) >> 16);
                    Index += 3;
                }
            }

            return GrayArray;
        }

        /// <summary>
        /// 将二值化数组转换为二值化图像
        /// </summary>
        /// <param name="binaryArray">二值化数组</param>
        /// <returns>二值化图像</returns>
        public static Bitmap BinaryArrayToBinaryBitmap(Byte[,] binaryArray)
        {   // 将二值化数组转换为二值化数据
            int PixelHeight = binaryArray.GetLength(0);
            int PixelWidth = binaryArray.GetLength(1);
            int Stride = ((PixelWidth + 31) >> 5) << 2;
            //int Stride = PixelWidth/8+(4- (PixelWidth / 8)%4);
            Byte[] Pixels = new Byte[PixelHeight * Stride];
            for (int i = 0; i < PixelHeight; i++)
            {
                int Base = i * Stride;
                for (int j = 0; j < PixelWidth; j++)
                {
                    if (binaryArray[i, j] != 0)
                    {
                        Pixels[Base + (j >> 3)] |= Convert.ToByte(0x80 >> (j & 0x7));
                    }
                }
            }

            // 创建黑白图像
            Bitmap BinaryBmp = new Bitmap(PixelWidth, PixelHeight, PixelFormat.Format1bppIndexed);

            // 设置调色表
            ColorPalette cp = BinaryBmp.Palette;
            cp.Entries[0] = Color.Black;    // 黑色
            cp.Entries[1] = Color.White;    // 白色
            BinaryBmp.Palette = cp;

            // 设置位图图像特性
            BitmapData BinaryBmpData = BinaryBmp.LockBits(new Rectangle(0, 0, PixelWidth, PixelHeight), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
            Marshal.Copy(Pixels, 0, BinaryBmpData.Scan0, Pixels.Length);
            BinaryBmp.UnlockBits(BinaryBmpData);

            return BinaryBmp;
        }

        #endregion
     其中将二值化数组转换为二值化图像的算法很有意思
      求跨距宽度这一步怎么也想不通为什么
            int Stride = ((PixelWidth + 31) >> 5) << 2;          下面这个是一般的写法,很容易懂  参考https://www.cnblogs.com/dearzhoubi/p/8655326.html
            //int Stride = PixelWidth/8+(4- (PixelWidth / 8)%4);
         
          Pixels[Base + (j >> 3)] |= Convert.ToByte(0x80 >> (j & 0x7));                        ****j&0x7实际上就是对j进行对8取余                        ****0x7二进制就是0000 0111                        ****比如j=18,二进制j=0001 0010,j&0x7=0000 0010,j=18对8取余就是2,也就是说二值数组中j=18这个位置的数据在二值图像中的存储位置是2个字节后第三个字节的第2个位置                        ****也就是要把0x80向右移动2位,0x80二进制是1000 0000,右移2位是0010 0000,                        ****然后和当前正在填充的字节进行按位或|,就可以把这一位数据填充进去                        ****实在是不熟悉这种二进制的这种移位操作,很神奇。


原文地址:https://www.cnblogs.com/dearzhoubi/p/9854653.html

时间: 2024-11-05 14:37:01

记录一个优秀的图像二值化代码的相关文章

图像处理之积分图应用四(基于局部均值的图像二值化算法)

图像处理之积分图应用四(基于局部均值的图像二值化算法) 基本原理 均值法,选择的阈值是局部范围内像素的灰度均值(gray mean),该方法的一个变种是用常量C减去均值Mean,然后根据均值实现如下操作: pixel = (pixel > (mean - c)) ? object : background 其中默认情况下参数C取值为0.object表示前景像素,background表示背景像素. 实现步骤 1. 彩色图像转灰度图像 2. 获取灰度图像的像素数据,预计算积分图 3. 根据输入的参数

基于直方图的图像二值化算法实现

引言 图像二值化的目的是最大限度的将图象中感兴趣的部分保留下来,在很多情况下,也是进行图像分析.特征提取与模式识别之前的必要的图像预处理过程.在过去年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法,但如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果. 在分类方法中,基于直方图的全局二值算法都从不同的科学层次提出了各自的实施方案,并且这类方法都有着一些共同的特点:简单.算法容易实现和执行速度快. 算法代码 第一种方法Huang L.-K et al.参考代

一种超级快速的图像二值化技术

在计算机视觉中,对图像进行二值化恐怕是最常见的操作了.为了检测目标,可能需要对每一帧图像的每一个像素点进行运算.如果能提升二值化的速度,那么,你的算法的效率就会大大的提高.本文,将介绍一种超级快速的图像二值化技术. 要解决的问题: 如上图所示,需要把彩色图像中, (1) R通道介于(smoevalue1, somevalue2)(2) G通道介于(somevalue3, somevalue4)(3) B通道介于(somevalue5, somevalue6)当图像中某个像素点同时满足上面3个条件

图像基本变换---图像二值化(包含OSTU/迭代法/统计法/双峰法/P分位法/最大熵法)

OSTU法图像二值化 [算法说明] Ostu法又叫做最大类间方差法,是一种常用的图像分割算法.基本算法思想是根据初始阈值把图像分为两类,然后计算两类之间的方差,更新阈值,重新计算类间方差,当满足类间方差最大时的阈值,即为所求最佳阈值,具体过程如下: 1,初始化一阈值Th,将图像f(x,y)分为A,B两类: 2,分别计算A,B两类像素集合的均值ua和ub,公式如下: 其中,Na和Nb分别表示集合A,B中的像素个数. 3,计算A,B两类的类间方差,公式如下: 4,将Th从0到255循环,分别计算A,

C# 指针操作图像 二值化处理

/// <summary> /// 二值化图像 /// </summary> /// <param name="bmp"></param> /// <returns></returns> private static unsafe Bitmap Binaryzation(Bitmap bmp) { BitmapData dstData = bmp.LockBits(new Rectangle(0, 0, bmp.W

数学之路-python计算实战(8)-机器视觉-图像二值化

二值化 hreshold Applies a fixed-level threshold to each array element. C++: double threshold(InputArray src, OutputArray dst, double thresh, doublemaxval, int type) Python: cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dst C: double cvThresh

opencv2对读书笔记——图像二值化——thresholded函数

opencv中的图像二值化函数threshold函数 其结构 double cv::threshold( //二值化函数 const CvArr* src, //原始图像 CvArr* dst, //输出图像 double threshold, //阈值 double max_value, //最大值 int threshold_type//阈值类型 ); 实例代码 #include "cv.h" #include "highgui.h" int main() {

MATLAB:图像二值化、互补图(反运算)(im2bw,imcomplement函数)

图像二值化.反运算过程涉及到im2bw,imcomplement函数,反运算可以这么理解:原本黑的区域变为白的区域,白的区域变为黑的区域. 实现过程如下: close all; %关闭当前所有图形窗口,清空工作空间变量,清除工作空间所有变量 clear all; clc; J=imread('rice.png');% 读取灰度图像,赋值给J J1=im2bw(J);%将灰度图像转换成二值图像,赋值给J1 J2=imcomplement(J);%求灰度图像的补,即对图像进行求反运算,赋值给J2 J

Win8 Metro(C#)数字图像处理--2.56简单统计法图像二值化

原文:Win8 Metro(C#)数字图像处理--2.56简单统计法图像二值化  [函数名称] 简单统计法图像二值化 WriteableBitmap StatisticalThSegment(WriteableBitmap src) /// <summary> /// Statistical method of image segmention. /// </summary> /// <param name="src">The source im