遗忘海岸

江湖程序员 -Feiph(LM战士)

导航

黑白二值图像周长测量--C#实现

假设是单像素线白色用1(对应RGB(255,0,0))表示,背景用0(对应RBG(0,0,0))表示。

考虑3种类型的边界 水平方向  0->1  1->0   类似垂直方向也是0->1  1->0

如果是单像素,如果水平检测时 发现 0->1 或1->0变动,那么都将 mapX[i,j] 设置成1,注意是白色像素对应的位置

类似的处理也针对垂直方向mapY[i,j]

如果以个mapY[i,j] 与mapX[i,j] 同时标记成了1,那么意味着这个像素是斜方向,那么按sqrt(2)来记录。

 

注意一:以直角三角型为例,构成边的线段粗细大于1个像素,那么求出的结果是翻倍的,因为边界出现了2次。

注意二:以直角三角型为例,如果直角三角型内部是填充成白色的(前景色1),那么求出的结果是一样的,因为边界只出现一次。

 

完整代码如下,需要传入二值图片。

     /// <summary>
        /// 二值图片前景是白背景是黑
        /// 测试白像素的边长
        /// 正负 pi/4   ,3pi/4 计1.414
        /// 其余按1计
        /// </summary>
        /// <param name="bm"></param>
        public static double? SegmentLen(Bitmap bm)
        {

            var map = new byte[bm.Width, bm.Height];
            var mapX = new byte[bm.Width, bm.Height];
            var mapY = new byte[bm.Width, bm.Height];

            for (int i = 0; i < bm.Width; i++)
            {
                for (int j = 0; j < bm.Height; j++)
                {
                    var c = bm.GetPixel(i, j);
                    if (c.R == 255)
                    {
                        map[i, j] = 1;
       
                    }
                    else
                    {
                        map[i, j] = 0;

                    }
                    mapX[i, j] = 0;
                    mapY[i, j] = 0;
                }
            }
            //水平边界检测
            for (int i = 1; i < bm.Width - 1; i++)
            {

                for (int j = 1; j < bm.Height - 1; j++)
                {
                    if (map[i, j] == 1 && map[i, j - 1] == 0) mapX[i, j] = 1;
                    if (map[i, j] == 0 && map[i, j - 1] == 1) mapX[i, j - 1] = 1;

                }
            }
            //垂直边界检测
            for (int i = 1; i < bm.Width - 1; i++)
            {

                for (int j = 1; j < bm.Height - 1; j++)
                {
                    if (map[i, j] == 1 && map[i - 1, j] == 0) mapY[i, j] = 1;
                    if (map[i, j] == 0 && map[i - 1, j] == 1) mapY[i - 1, j] = 1;

                }
            }
            var len = 0.0d;
            for (int i = 0; i < bm.Width; i++)
            {

                for (int j = 0; j < bm.Height; j++)
                {

                    if (mapY[i, j] == 1 && mapX[i, j] == 1)
                    {
                        len +=  1.414;
                    }
                    else if (mapX[i, j] == 1 || mapY[i, j] == 1)
                    {
                        len += 1;
                    }
                }
            }
            return len;

        }
View Code

 类似的调用代码

var filename = @"C:\t2\z4_3.jpg";
pictureBox1.ImageLocation = filename;
var tImg = new Bitmap(filename);

tImg = GenBinaryImgByThreshold(tImg, 80);
tImg = BorderCheck.FullScanBoundrExtract(tImg);
var len = BorderCheck.SegmentLen(tImg);
Console.WriteLine(len);
ShowImg(tImg);

        public Bitmap GenBinaryImgByThreshold(Bitmap bm, int threshold)
        {
            Color white = Color.FromArgb(255, 255, 255);
            Color black = Color.FromArgb(0, 0, 0);
            Color c = new Color();
            int r;
            Bitmap box1 = new Bitmap(bm.Width, bm.Height);
            for (int i = 0; i < bm.Width; i++)
            {
                for (int j = 0; j < bm.Height; j++)
                {
                    c = bm.GetPixel(i, j);
                    r = (c.R + c.G + c.B) / 3 ;
                    if (r > threshold)
                    {
                        box1.SetPixel(i, j, black);
                    }
                    else
                    {
                        box1.SetPixel(i, j, white);
                    }
                }
            }
          return box1;
        }
View Code

 上文涉及到的边界抽取函数:

        /// <summary>
        /// 黑白图片全图检测边界抽取
        /// </summary>
        public static Bitmap FullScanBoundrExtract(Bitmap bm)
        {
            var box1 = new Bitmap(bm);//输入使用bm.Width,bm.Height,保留的点是透明的。
            var b = Color.FromArgb(255,0, 0, 0);
            var w = Color.FromArgb(255,255, 255, 255);
            var map = new Int16[bm.Width, bm.Height];
            var map2 = new Int16[bm.Width, bm.Height];
            for (int i = 0; i < bm.Width; i++)
            {

                for (int j = 0; j < bm.Height; j++)
                {
                    var c = bm.GetPixel(i, j);
                    if (c.R == 255)
                    {
                        map[i, j] = 1;
                    }
                    else
                    {
                        map[i, j] = 0;
                        box1.SetPixel(i, j, b);
                    }
                    //map2[i, j] = 0;
                }
            }

            for (int i = 1; i < bm.Width - 1; i++)
            {

                for (int j = 1; j < bm.Height - 1; j++)
                {
                    if (map[i, j] == 1 && map[i, j - 1] == 0) map2[i, j] = 1;
                    if (map[i, j] == 0 && map[i, j - 1] == 1) map2[i, j - 1] = 1;

                }
            }
            for (int i = 1; i < bm.Width - 1; i++)
            {

                for (int j = 1; j < bm.Height - 1; j++)
                {
                    if (map[i, j] == 1 && map[i - 1, j] == 0) map2[i, j] = 1;
                    if (map[i, j] == 0 && map[i - 1, j] == 1) map2[i - 1, j] = 1;

                }
            }
            for (int i = 0; i < bm.Width; i++)
            {

                for (int j = 0; j < bm.Height; j++)
                {
                    if (map2[i, j] == 0)
                    {

                        box1.SetPixel(i, j, b);
                    }
                }
            }
            return box1;
        }
View Code

 

posted on 2018-07-26 10:28  遗忘海岸  阅读(801)  评论(0编辑  收藏  举报