当前位置: 移动技术网 > IT编程>开发语言>c# > c#文档图片自动纠偏

c#文档图片自动纠偏

2019年07月18日  | 移动技术网IT编程  | 我要评论

复制代码 代码如下:

public class deskew
    {
        // representation of a line in the image. 
        private class hougline
        {
            // count of points in the line.
            public int count;
            // index in matrix.
            public int index;
            // the line is represented as all x,y that solve y*cos(alpha)-x*sin(alpha)=d
            public double alpha;
        }


        // the bitmap
        public bitmap _internalbmp;

        // the range of angles to search for lines
        const double alpha_start = -20;
        const double alpha_step = 0.2;
        const int steps = 40 * 5;
        const double step = 1;

        // precalculation of sin and cos.
        double[] _sina;
        double[] _cosa;

        // range of d
        double _min;


        int _count;
        // count of points that fit in a line.
        int[] _hmatrix;

        // calculate the skew angle of the image cbmp.
        public double getskewangle()
        {
            // hough transformation
            calc();

            // top 20 of the detected lines in the image.
            hougline[] hl = gettop(20);

            // average angle of the lines
            double sum = 0;
            int count = 0;
            for (int i = 0; i <= 19; i++)
            {
                sum += hl[i].alpha;
                count += 1;
            }
            return sum / count;
        }

        // calculate the count lines in the image with most points.
        private hougline[] gettop(int count)
        {
            hougline[] hl = new hougline[count];

            for (int i = 0; i <= count - 1; i++)
            {
                hl[i] = new hougline();
            }
            for (int i = 0; i <= _hmatrix.length - 1; i++)
            {
                if (_hmatrix[i] > hl[count - 1].count)
                {
                    hl[count - 1].count = _hmatrix[i];
                    hl[count - 1].index = i;
                    int j = count - 1;
                    while (j > 0 && hl[j].count > hl[j - 1].count)
                    {
                        hougline tmp = hl[j];
                        hl[j] = hl[j - 1];
                        hl[j - 1] = tmp;
                        j -= 1;
                    }
                }
            }

            for (int i = 0; i <= count - 1; i++)
            {
                int dindex = hl[i].index / steps;
                int alphaindex = hl[i].index - dindex * steps;
                hl[i].alpha = getalpha(alphaindex);
                //hl[i].d = dindex + _min;
            }

            return hl;
        }


        // hough transforamtion:
        private void calc()
        {
            int hmin = _internalbmp.height / 4;
            int hmax = _internalbmp.height * 3 / 4;

            init();
            for (int y = hmin; y <= hmax; y++)
            {
                for (int x = 1; x <= _internalbmp.width - 2; x++)
                {
                    // only lower edges are considered.
                    if (isblack(x, y))
                    {
                        if (!isblack(x, y + 1))
                        {
                            calc(x, y);
                        }
                    }
                }
            }
        }

        // calculate all lines through the point (x,y).
        private void calc(int x, int y)
        {
            int alpha;

            for (alpha = 0; alpha <= steps - 1; alpha++)
            {
                double d = y * _cosa[alpha] - x * _sina[alpha];
                int calculatedindex = (int)calcdindex(d);
                int index = calculatedindex * steps + alpha;
                try
                {
                    _hmatrix[index] += 1;
                }
                catch (exception ex)
                {
                    system.diagnostics.debug.writeline(ex.tostring());
                }
            }
        }
        private double calcdindex(double d)
        {
            return convert.toint32(d - _min);
        }
        private bool isblack(int x, int y)
        {
            color c = _internalbmp.getpixel(x, y);
            double luminance = (c.r * 0.299) + (c.g * 0.587) + (c.b * 0.114);
            return luminance < 140;
        }

        private void init()
        {
            // precalculation of sin and cos.
            _cosa = new double[steps];
            _sina = new double[steps];

            for (int i = 0; i < steps; i++)
            {
                double angle = getalpha(i) * math.pi / 180.0;
                _sina[i] = math.sin(angle);
                _cosa[i] = math.cos(angle);
            }

            // range of d:           
            _min = -_internalbmp.width;
            _count = (int)(2 * (_internalbmp.width + _internalbmp.height) / step);
            _hmatrix = new int[_count * steps];

        }

        private static double getalpha(int index)
        {
            return alpha_start + index * alpha_step;
        }
    }

自己写的调用方法

复制代码 代码如下:

public static void deskewimage(string filename, byte binarizethreshold)
        {
            //打开图像
            bitmap bmp = openimage(filename);

            deskew deskew = new deskew();
            bitmap tempbmp = cropimage(bmp, bmp.width / 4, bmp.height / 4, bmp.width / 2, bmp.height / 2);
            deskew._internalbmp = binarizeimage(tempbmp, binarizethreshold);
            double angle = deskew.getskewangle();
            bmp = rotateimage(bmp, (float)(-angle));

            //保存图像(需要再还原图片原本的位深度)
            saveimage(bmp, filename);
        }

        /// <summary>
        /// 图像剪切
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="startx"></param>
        /// <param name="starty"></param>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <returns></returns>
        private static bitmap cropimage(bitmap bmp, int startx, int starty, int w, int h)
        {
            try
            {
                bitmap bmpout = new bitmap(w, h, pixelformat.format32bppargb);

                graphics g = graphics.fromimage(bmpout);
                g.drawimage(bmp, new rectangle(0, 0, w, h), new rectangle(startx, starty, w, h), graphicsunit.pixel);
                g.dispose();

                return bmpout;
            }
            catch
            {
                return null;
            }
        }


        /// <summary>
        /// 图像二值化
        /// </summary>
        /// <param name="b"></param>
        /// <param name="threshold">阈值</param>
        private static bitmap binarizeimage(bitmap b, byte threshold)
        {
            int width = b.width;
            int height = b.height;
            bitmapdata data = b.lockbits(new rectangle(0, 0, width, height), imagelockmode.readwrite, pixelformat.format32bpprgb);
            unsafe
            {
                byte* p = (byte*)data.scan0;
                int offset = data.stride - width * 4;
                byte r, g, b, gray;
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        r = p[2];
                        g = p[1];
                        b = p[0];
                        gray = (byte)((r * 19595 + g * 38469 + b * 7472) >> 16);
                        if (gray >= threshold)
                        {
                            p[0] = p[1] = p[2] = 255;
                        }
                        else
                        {
                            p[0] = p[1] = p[2] = 0;
                        }
                        p += 4;
                    }
                    p += offset;
                }
                b.unlockbits(data);
                return b;
            }
        }

        /// <summary>
        /// 图像旋转
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="angle">角度</param>
        /// <returns></returns>
        private static bitmap rotateimage(bitmap bmp, float angle)
        {
            pixelformat pixelformat = bmp.pixelformat;
            pixelformat pixelformatold = pixelformat;
            if (bmp.palette.entries.count() > 0)
            {
                pixelformat = pixelformat.format24bpprgb;
            }

            bitmap tmpbitmap = new bitmap(bmp.width, bmp.height, pixelformat);
            tmpbitmap.setresolution(bmp.horizontalresolution, bmp.verticalresolution);
            graphics g = graphics.fromimage(tmpbitmap);
            try
            {
                g.fillrectangle(brushes.white, 0, 0, bmp.width, bmp.height);
                g.rotatetransform(angle);
                g.drawimage(bmp, 0, 0);
            }
            catch
            {
            }
            finally
            {
                g.dispose();
            }

            if (pixelformatold == pixelformat.format8bppindexed) tmpbitmap = copyto8bpp(tmpbitmap);
            else if (pixelformatold == pixelformat.format1bppindexed) tmpbitmap = copyto1bpp(tmpbitmap);

            return tmpbitmap;
        }

在最后进行图片选择时,位深度为1、4、8的索引图片是没办法直接用graphics进行旋转操作的,需要图像的pixelformat再做旋转。
现在只实现位深度为1和8的索引图片还原。

复制代码 代码如下:

private static bitmap copyto1bpp(bitmap b)
        {
            int w = b.width, h = b.height; rectangle r = new rectangle(0, 0, w, h);
            if (b.pixelformat != pixelformat.format32bpppargb)
            {
                bitmap temp = new bitmap(w, h, pixelformat.format32bpppargb);
                temp.setresolution(b.horizontalresolution, b.verticalresolution);
                graphics g = graphics.fromimage(temp);
                g.drawimage(b, r, 0, 0, w, h, graphicsunit.pixel);
                g.dispose();
                b = temp;
            }
            bitmapdata bdat = b.lockbits(r, imagelockmode.readonly, b.pixelformat);
            bitmap b0 = new bitmap(w, h, pixelformat.format1bppindexed);
            b0.setresolution(b.horizontalresolution, b.verticalresolution);
            bitmapdata b0dat = b0.lockbits(r, imagelockmode.readwrite, pixelformat.format1bppindexed);
            for (int y = 0; y < h; y++)
            {
                for (int x = 0; x < w; x++)
                {
                    int index = y * bdat.stride + (x * 4);
                    if (color.fromargb(marshal.readbyte(bdat.scan0, index + 2), marshal.readbyte(bdat.scan0, index + 1), marshal.readbyte(bdat.scan0, index)).getbrightness() > 0.5f)
                    {
                        int index0 = y * b0dat.stride + (x >> 3);
                        byte p = marshal.readbyte(b0dat.scan0, index0);
                        byte mask = (byte)(0x80 >> (x & 0x7));
                        marshal.writebyte(b0dat.scan0, index0, (byte)(p | mask));
                    }
                }
            }
            b0.unlockbits(b0dat);
            b.unlockbits(bdat);
            return b0;
        }

        private static bitmap copyto8bpp(bitmap bmp)
        {
            if (bmp == null) return null;

            rectangle rect = new rectangle(0, 0, bmp.width, bmp.height);
            bitmapdata bmpdata = bmp.lockbits(rect, imagelockmode.readonly, bmp.pixelformat);

            int width = bmpdata.width;
            int height = bmpdata.height;
            int stride = bmpdata.stride;
            int offset = stride - width * 3;
            intptr ptr = bmpdata.scan0;
            int scanbytes = stride * height;

            int posscan = 0, posdst = 0;
            byte[] rgbvalues = new byte[scanbytes];
            marshal.copy(ptr, rgbvalues, 0, scanbytes);
            byte[] grayvalues = new byte[width * height];

            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    double temp = rgbvalues[posscan++] * 0.11 +
                        rgbvalues[posscan++] * 0.59 +
                        rgbvalues[posscan++] * 0.3;
                    grayvalues[posdst++] = (byte)temp;
                }
                posscan += offset;
            }

            marshal.copy(rgbvalues, 0, ptr, scanbytes);
            bmp.unlockbits(bmpdata);

            bitmap bitmap = new bitmap(width, height, pixelformat.format8bppindexed);
            bitmap.setresolution(bmp.horizontalresolution, bmp.verticalresolution);
            bitmapdata bitmapdata = bitmap.lockbits(new rectangle(0, 0, width, height), imagelockmode.writeonly, pixelformat.format8bppindexed);

            int offset0 = bitmapdata.stride - bitmapdata.width;
            int scanbytes0 = bitmapdata.stride * bitmapdata.height;
            byte[] rawvalues = new byte[scanbytes0];

            int possrc = 0;
            posscan = 0;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    rawvalues[posscan++] = grayvalues[possrc++];
                }
                posscan += offset0;
            }

            marshal.copy(rawvalues, 0, bitmapdata.scan0, scanbytes0);
            bitmap.unlockbits(bitmapdata);

            colorpalette palette;
            using (bitmap bmp0 = new bitmap(1, 1, pixelformat.format8bppindexed))
            {
                palette = bmp0.palette;
            }
            for (int i = 0; i < 256; i++)
            {
                palette.entries[i] = color.fromargb(i, i, i);
            }
            bitmap.palette = palette;

            return bitmap;
        }

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网