欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

c#扫描图片去黑边(扫描仪去黑边)

程序员文章站 2024-02-23 16:38:40
自动去除图像扫描黑边复制代码 代码如下:///         ///...

自动去除图像扫描黑边

复制代码 代码如下:

/// <summary>
        /// 自动去除图像扫描黑边
        /// </summary>
        /// <param name="filename"></param>
        public static void autocutblackedge(string filename)
        {
            //打开图像
            bitmap bmp = openimage(filename);

            removeblackedge(bmp);
            //保存图像
            saveimage(bmp, filename);
        }

        private static byte[] rgbvalues; // 目标数组内存

        /// <summary>
        /// 图像去黑边
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        private static bitmap removeblackedge(bitmap bmp)
        {
            rectangle rect = new rectangle(0, 0, bmp.width, bmp.height);
            bitmapdata bmpdata = bmp.lockbits(rect, imagelockmode.readwrite, bmp.pixelformat);

            // 获取图像参数 
            int w = bmpdata.width;
            int h = bmpdata.height;
            int stride = bmpdata.stride;  // 扫描线的宽度
            double picbytesize = getpicbytesize(bmp.pixelformat);
            int bwidth = (int)math.ceiling(picbytesize * w); //显示宽度
            int offset = stride - bwidth;  // 显示宽度与扫描线宽度的间隙 
            intptr ptr = bmpdata.scan0;   // 获取bmpdata的内存起始位置 
            int scanbytes = stride * h;  // 用stride宽度,表示这是内存区域的大小

            // 分别设置两个位置指针,指向源数组和目标数组 
            int posscan = 0;
            rgbvalues = new byte[scanbytes];  // 为目标数组分配内存 
            marshal.copy(ptr, rgbvalues, 0, scanbytes);  // 将图像数据拷贝到rgbvalues中 

            bool ispass = true;
            int i = 0, j = 0;
            int cutw = (int)(bwidth * 0.02); //2%宽度(可修改)
            int cuth = (int)(h * 0.02);      //2%高度(可修改)
            int poslen = (int)(picbytesize * 8); //继续查找深度为8的倍数(可修改)
            //左边
            for (i = 0; i < h; i++)
            {
                for (j = 0; j < bwidth; j++)
                {
                    ispass = true;
                    if (rgbvalues[posscan] < 255) rgbvalues[posscan] = 255;

                    if (rgbvalues[posscan + 1] == 255)
                    {
                        for (int m = 1; m <= poslen; m++)
                        {
                            if (rgbvalues[posscan + m] < 255) ispass = false;
                        }
                    }
                    if (rgbvalues[posscan + 1] < 255 || bwidth / 2 < j) ispass = false;
                    reccheck(ref rgbvalues, posscan, h, stride, true);

                    posscan++;
                    if (j >= cutw && ispass) break;
                }
                // 跳过图像数据每行未用空间的字节,length = stride - width * byteperpixel 
                if (j == bwidth) posscan += offset;
                else posscan += (offset + bwidth - j - 1);
            }
            //右边
            posscan = scanbytes - 1;
            for (i = h - 1; i >= 0; i--)
            {
                posscan -= offset;
                for (j = bwidth - 1; j >= 0; j--)
                {
                    ispass = true;
                    if (rgbvalues[posscan] < 255) rgbvalues[posscan] = 255;

                    if (rgbvalues[posscan - 1] == 255)
                    {
                        for (int m = 1; m <= poslen; m++)
                        {
                            if (rgbvalues[posscan - m] < 255) ispass = false;
                        }
                    }
                    if (rgbvalues[posscan - 1] < 255 || bwidth / 2 > j) ispass = false;
                    reccheck(ref rgbvalues, posscan, h, stride, false);

                    posscan--;
                    if (cuth < (h - i))
                        if (j < (bwidth - cutw) && ispass) break;
                }
                // 跳过图像数据每行未用空间的字节,length = stride - width * byteperpixel
                if (j != -1) posscan -= j;
            }

            // 内存解锁 
            marshal.copy(rgbvalues, 0, ptr, scanbytes);
            bmp.unlockbits(bmpdata);  // 解锁内存区域 

            return bmp;
        }

        /// <summary>
        /// 上下去除黑边时,临近黑点去除
        /// </summary>
        /// <param name="rgbvalues"></param>
        /// <param name="posscan"></param>
        /// <param name="h"></param>
        /// <param name="stride"></param>
        /// <param name="islleft"></param>
        private static void reccheck(ref byte[] rgbvalues, int posscan, int h, int stride, bool islleft)
        {
            int scanbytes = h * stride;
            int cuth = (int)(h * 0.01); //临近最大1%高度(可修改)
            for (int i = 1; i <= cuth; i++)
            {
                int befrow = 0;
                if (islleft && (posscan - stride * i) > 0)
                {
                    befrow = posscan - stride * i;
                }
                else if (!islleft && (posscan + stride * i) < scanbytes)
                {
                    befrow = posscan + stride * i;
                }
                if (rgbvalues[befrow] < 255) rgbvalues[befrow] = 255;
                else break;
            }
        }