C# 自动按比例裁剪去除图片色边(一般是黑边或者白边)

        最近遇到了这种问题,图片两边有黑色的多余部分,就想要去掉它,去抄了几个方法,都用不了,想改又无从下手(我太垃圾了),只能自己去写一个 ,用的死方法,不考虑性能。

        实现思路:遍历整张图片所有像素点颜色,找到最左的色边的位置和最右的色边的位置,上下色边同理。

                          根据这两个位置对图片进行裁剪。完成!

                          下面是实现代码:

        由于我的图片黑边中也有不需要的像素,所以加了个检测比例。

        /// <summary>
        /// 自动去除图片左右色边
        /// </summary>
        /// <param name="filename">文件路径</param>
        /// <param name="color">要去除的色边颜色</param>
        /// <param name="yscale1">开始位置比例,上至下,从哪个比例开始(0.25就代表从图片25%处开始检测)</param>
        /// <param name="yscale2">结束位置比例,上至下,到哪个位置结束(0.5就代表检测到50%为止)</param>
        /// <returns></returns>
        public static Bitmap AutoCutColorEdge2(string filename, Color color, double yscale1, double yscale2)
        {
            Bitmap bmp = new Bitmap(filename);
            Color c = new Color();
            int max_Left = bmp.Width / 2, min_Right = bmp.Width / 2;
            for (int y = Convert.ToInt32(bmp.Height * yscale1); y < bmp.Height * yscale2; y++)//b.Height  
            {
                for (int x = bmp.Width / 2; x >= 0; x--)//找到最靠左的非黑边位置
                {
                    c = bmp.GetPixel(x, y); //获取该像素点的颜色
                    if (c.R >= color.R + 5 && c.G >= color.G + 5 && c.B >= color.B + 5)//非黑边位置
                    {
                        if (max_Left > x)
                        {
                            max_Left = x;
                        }
                    }
                }
                for (int x = bmp.Width / 2; x < bmp.Width; x++)//找到最靠右的非黑边位置
                {
                    c = bmp.GetPixel(x, y); //获取该像素点的颜色
                    if (c.R >= color.R + 5 && c.G >= color.G + 5 && c.B >= color.B + 5)//非黑边位置
                    {
                        if (min_Right < x)
                        {
                            min_Right = x;
                        }
                    }
                }
            }
            //最左邊黑邊:903,最右邊黑邊:1475
            //Console.WriteLine($"最左邊黑邊:{max_Left},最右邊黑邊:{min_Right}");
            //创建一个画框:宽(右黑边起始位置-左黑边最终位置=去除黑边之后的宽度),高(整个图片 的图框)
            Bitmap huakuang = new Bitmap(min_Right - max_Left, bmp.Height);//2162 - 239 =1923
            //创建一个画布:宽高和画框一致
            Graphics huabu = Graphics.FromImage(huakuang);
            //清空画布(透明)
            huabu.Clear(System.Drawing.Color.Transparent);
            //画布上所要画的位置和大小
            RectangleF huabu_rec = new RectangleF(0, 0, min_Right - max_Left, bmp.Height);
            //图片所要裁剪矩形的大小和位置:
            //x=intLeft(从左黑边最终位置开始),y=0
            //width=intRight - intLeft(右黑边起始位置-左黑边最终位置=去除黑边之后的宽度),height=整个图片的高
            RectangleF img_rec = new RectangleF(max_Left, 0, min_Right - max_Left, bmp.Height);
            //在画布上的指定位置大小(huabu_rec)画上图片(bmp)的指定部分(img_rec)
            huabu.DrawImage(bmp, huabu_rec, img_rec, GraphicsUnit.Pixel);
            bmp.Dispose();
            huabu.Dispose();
            return huakuang;
        }
        /// <summary>
        /// 自动去除图片上下色边
        /// </summary>
        /// <param name="filename">文件路径</param>
        /// <param name="color">要去除的色边颜色</param>
        /// <param name="xscale1">开始位置比例,上至下,从哪个比例开始(0.25就代表从图片25%处开始检测)</param>
        /// <param name="xscale2">结束位置比例,上至下,到哪个位置结束(0.5就代表检测到50%为止)</param>
        /// <returns></returns>
        public static Bitmap AutoCutColorEdge3(string filename, Color color, double xscale1, double xscale2)
        {
            Bitmap bmp = new Bitmap(filename);
            Color c = new Color();
            int min_Top = bmp.Height / 2, max_Bottom = bmp.Height / 2;
            for (int x = Convert.ToInt32(bmp.Width * xscale1); x < bmp.Width * xscale2; x++)//b.Height  
            {
                for (int y = bmp.Height / 2; y >= 0; y--)//找到最靠左的非黑边位置
                {
                    c = bmp.GetPixel(x, y); //获取该像素点的颜色
                    if (c.R >= color.R + 5 && c.G >= color.G + 5 && c.B >= color.B + 5)//非黑边位置
                    {
                        if (min_Top > y)
                        {
                            min_Top = y;
                        }
                    }
                }
                for (int y = bmp.Height / 2; y < bmp.Height; y++)//找到最靠右的非黑边位置
                {
                    c = bmp.GetPixel(x, y); //获取该像素点的颜色
                    if (c.R >= color.R + 5 && c.G >= color.G + 5 && c.B >= color.B + 5)//非黑边位置
                    {
                        if (max_Bottom < y)
                        {
                            max_Bottom = y;
                        }

                    }
                }
            }
            //最上邊黑邊:140,最下邊黑邊:986
            //Console.WriteLine($"最上邊黑邊:{min_Top},最下邊黑邊:{max_Bottom}");
            //创建一个画框:宽
            Bitmap huakuang = new Bitmap(bmp.Width, max_Bottom - min_Top);//986 - 140 =846
            //创建一个画布:宽高和画框一致
            Graphics huabu = Graphics.FromImage(huakuang);
            //清空画布(透明)
            huabu.Clear(System.Drawing.Color.Transparent);
            //画布上所要画的位置和大小
            RectangleF huabu_rec = new RectangleF(0, 0, bmp.Width, max_Bottom - min_Top);
            //图片所要裁剪矩形的大小和位置:
            RectangleF img_rec = new RectangleF(0, min_Top, bmp.Width, max_Bottom - min_Top);
            //在画布上的指定位置大小(huabu_rec)画上图片(bmp)的指定部分(img_rec)
            huabu.DrawImage(bmp, huabu_rec, img_rec, GraphicsUnit.Pixel);
            bmp.Dispose();
            huabu.Dispose();
            return huakuang;
        }
        /// <summary>
        /// 自动去除图片上下色边
        /// </summary>
        /// <param name="bmp">图片</param>
        /// <param name="color">要去除的色边颜色</param>
        /// <param name="xscale1">开始位置比例,上至下,从哪个比例开始(0.25就代表从图片25%处开始检测)</param>
        /// <param name="xscale2">结束位置比例,上至下,到哪个位置结束(0.5就代表检测到50%为止)</param>
        /// <returns></returns>
        public static Bitmap AutoCutColorEdge4(Bitmap bmp, Color color, double xscale1, double xscale2)
        {
            Color c = new Color();
            int min_Top = bmp.Height / 2, max_Bottom = bmp.Height / 2;
            for (int x = Convert.ToInt32(bmp.Width * xscale1); x < bmp.Width * xscale2; x++)//b.Height  
            {
                for (int y = bmp.Height / 2; y >= 0; y--)//找到最靠左的非黑边位置
                {
                    c = bmp.GetPixel(x, y); //获取该像素点的颜色
                    if (c.R >= color.R + 5 && c.G >= color.G + 5 && c.B >= color.B + 5)//非黑边位置
                    {
                        if (min_Top > y)
                        {
                            min_Top = y;
                        }
                    }
                }
                for (int y = bmp.Height / 2; y < bmp.Height; y++)//找到最靠右的非黑边位置
                {
                    c = bmp.GetPixel(x, y); //获取该像素点的颜色
                    if (c.R >= color.R + 5 && c.G >= color.G + 5 && c.B >= color.B + 5)//非黑边位置
                    {
                        if (max_Bottom < y)
                        {
                            max_Bottom = y;
                        }

                    }
                }
            }
            //最上邊黑邊:140,最下邊黑邊:986
            //Console.WriteLine($"最上邊黑邊:{min_Top},最下邊黑邊:{max_Bottom}");
            //创建一个画框:宽
            Bitmap huakuang = new Bitmap(bmp.Width, max_Bottom - min_Top);//986 - 140 =846
            //创建一个画布:宽高和画框一致
            Graphics huabu = Graphics.FromImage(huakuang);
            //清空画布(透明)
            huabu.Clear(System.Drawing.Color.Transparent);
            //画布上所要画的位置和大小
            RectangleF huabu_rec = new RectangleF(0, 0, bmp.Width, max_Bottom - min_Top);
            //图片所要裁剪矩形的大小和位置:
            RectangleF img_rec = new RectangleF(0, min_Top, bmp.Width, max_Bottom - min_Top);
            //在画布上的指定位置大小(huabu_rec)画上图片(bmp)的指定部分(img_rec)
            huabu.DrawImage(bmp, huabu_rec, img_rec, GraphicsUnit.Pixel);
            bmp.Dispose();
            huabu.Dispose();
            return huakuang;
        }

这是调用:

            Bitmap bmp = AutoCutColorEdge(@"文件路径", Color.Black, 0.7, 0.9);
            bmp.Save(@"保存路径" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg");

原理:先记录第一行左边最靠右的色边位置,在去验证非色边是否处于该记录点的左边,处于则更新记录。(PS:从中间开始检测左边,检测图片的第一行像素,拿到左边最靠右的色边,然后接下来的循环是一样的,如果比这个更靠右的则记录,如果遇到了非色边,则判断它是否处于记录点的左边,是则更新记录点并且不在检测左边最靠右的。)

效果原图1:

          

 我的检测比例是0.7~0.9所以会变成这样:

        

如果检测比例是0~1的话:

        

检测到中间的时候最左的色边位置就变成了0。

效果原图2(这个最下面有一条蓝色线):

        

 检测比例:0.7~1,可以发现不是想要的效果

        

检测比例:0.7~0.9,这才是想要的效果

       

完整演示:

        

检测比例:0.2~0.3,差不多是这个程度               

      

调用代码:先去除左右色边,再去除上下色边

                Bitmap bmp = ImageHelper.AutoCutColorEdge2(@"文件路径", Color.Black, 0.2, 0.3);//先去除左右色边
                bmp = ImageHelper.AutoCutColorEdge4(bmp, Color.Black, 0.2, 0.3);//再去除上下色边
                string filename = @"保存路径" + DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".jpg";
                bmp.Save(filename);
                bmp.Dispose();

 效果如下:这就是想要的效果

        

 如果想要保留:则需要修改比例,左右色边0.7-0.9,上下0.5-0.6

                Bitmap bmp = ImageHelper.AutoCutColorEdge2(@"文件路径", Color.Black, 0.7, 0.9);
                bmp = ImageHelper.AutoCutColorEdge4(bmp, Color.Black, 0.5, 0.6);
                string filename = @"保存路径" + DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".jpg";
                bmp.Save(filename);
                bmp.Dispose();

 效果如下:非常的nice~

        

猜你喜欢

转载自blog.csdn.net/qq_51502150/article/details/127316000