亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

c#文檔圖片自動糾偏

2020-01-24 02:44:47
字體:
來源:轉載
供稿:網友

復制代碼 代碼如下:

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;
        }

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲天堂精品在线| 成人黄色免费网站在线观看| 日韩人体视频一二区| 国产美女精品免费电影| 丁香五六月婷婷久久激情| 日韩免费在线视频| 欧美老少做受xxxx高潮| 国产亚洲欧洲黄色| 成人福利网站在线观看11| 亚洲午夜av久久乱码| 欧美大全免费观看电视剧大泉洋| 国产欧美精品在线| 久久在线视频在线| 日韩男女性生活视频| 日韩高清欧美高清| 欧美大学生性色视频| 亚洲免费人成在线视频观看| 亚洲欧美成人精品| 日韩欧美黄色动漫| 国产精品h片在线播放| 国产欧美久久久久久| 亚洲网在线观看| 欧美精品一区二区免费| 日韩电影免费在线观看中文字幕| 精品人伦一区二区三区蜜桃免费| 日韩美女福利视频| 亚洲国产私拍精品国模在线观看| xxxx性欧美| 91国产高清在线| 国产精品久久久久77777| 日韩精品免费电影| 色诱女教师一区二区三区| 日韩免费在线电影| 91久久在线观看| 热re91久久精品国99热蜜臀| 91久久综合亚洲鲁鲁五月天| 国产一区二区av| 亚洲国产99精品国自产| 欧美性生交xxxxx久久久| 国产成人av网址| 中文字幕免费精品一区高清| 亚洲黄色www| 亚洲精品色婷婷福利天堂| 国产成人avxxxxx在线看| 日韩精品中文字幕视频在线| 亚洲精品小视频| 国产精品自拍网| 91精品国产高清久久久久久| 日韩av在线天堂网| 欧美一级视频一区二区| 91在线国产电影| 一区二区三区天堂av| 亚洲精品大尺度| 97国产在线视频| 高清欧美电影在线| 国产午夜精品免费一区二区三区| 77777少妇光屁股久久一区| 欧洲s码亚洲m码精品一区| 这里只有精品视频| 韩日欧美一区二区| 亚洲区一区二区| 欧美中文字幕在线| 欧美电影免费在线观看| 亚洲区在线播放| 精品福利樱桃av导航| 91精品国产99久久久久久| 日本不卡视频在线播放| 另类视频在线观看| 欧美高清在线观看| 亚洲男人天堂网站| 亚洲综合日韩中文字幕v在线| 国产精品天天狠天天看| 久久久久中文字幕2018| 欧美日韩裸体免费视频| 国产精品视频自在线| 国产在线a不卡| 久久精品国产99国产精品澳门| 久久国产精品99国产精| 国产成人av在线播放| 亚洲精品视频播放| 精品调教chinesegay| 色爱av美腿丝袜综合粉嫩av| 欧美午夜精品久久久久久人妖| 亚洲偷熟乱区亚洲香蕉av| 日韩免费观看视频| 亚洲视频在线看| 国产亚洲成av人片在线观看桃| 在线播放日韩精品| 亚洲精品福利在线观看| 尤物精品国产第一福利三区| 欧洲午夜精品久久久| 亚洲成人精品视频| 亚洲最大福利视频网站| 亚洲第一偷拍网| 欧美一级片久久久久久久| 欧美三级免费观看| 精品五月天久久| 精品日本美女福利在线观看| 亚洲自拍偷拍一区| 国外成人免费在线播放| 欧美人在线观看| 久久久中文字幕| 日本精品久久久久久久| 国产欧美在线视频| 亚洲一区二区福利| 久久久99免费视频| 国产精品中文字幕在线| 欧美尺度大的性做爰视频| 九九精品在线播放| 亚洲的天堂在线中文字幕| 久久久国产精品亚洲一区| 精品国产1区2区| 色天天综合狠狠色| 欧美做受高潮电影o| 国产精品久久二区| 中文字幕亚洲欧美一区二区三区| 精品福利免费观看| 国产精品网站视频| 亚洲欧美一区二区三区情侣bbw| 亚洲男人的天堂网站| 欧美日韩在线视频一区二区| 成人性生交大片免费观看嘿嘿视频| 2019日本中文字幕| 91精品在线观看视频| 欧美—级a级欧美特级ar全黄| 日本一欧美一欧美一亚洲视频| 亚洲深夜福利视频| 国产精品18久久久久久首页狼| 日韩电影网在线| 亚洲理论在线a中文字幕| 中文字幕一精品亚洲无线一区| 亚洲国产欧美一区二区三区久久| 91精品国产乱码久久久久久蜜臀| 亚洲丁香久久久| 国产精品va在线播放我和闺蜜| 高清视频欧美一级| 亚洲香蕉伊综合在人在线视看| 永久免费毛片在线播放不卡| 午夜精品www| 欧美激情视频播放| 91精品视频播放| 欧美激情精品久久久久久久变态| 亚洲女在线观看| 国产黑人绿帽在线第一区| 久久精品国亚洲| 亚洲第一福利视频| 在线观看欧美日韩国产| 狠狠躁夜夜躁久久躁别揉| 欧美麻豆久久久久久中文| 韩国v欧美v日本v亚洲| 亚洲一区二区三区xxx视频| 成年人精品视频| 国产精品久久久久av免费| 在线视频欧美日韩精品| 精品国产电影一区| 在线观看日韩专区| 亚洲一区中文字幕| 亚洲欧美精品一区| 亚洲欧美综合区自拍另类| 精品国偷自产在线视频99| 国产成人在线亚洲欧美| 爽爽爽爽爽爽爽成人免费观看| 欧美激情欧美激情在线五月| 亚洲最新视频在线|