c#文档图片自动纠偏

代码如下:

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

(0)

相关推荐

  • c#批量上传图片到服务器示例分享

    客户端代码: 复制代码 代码如下: /// <summary>/// 批量上传图片/// </summary>/// <param name="srcurl">服务器路径</param>/// <param name="imagesPath">图片文件夹路径</param>/// <param name="files">图片名称</param>publ

  • c#裁剪图片后使用zxing生成二维码示例分享

    复制代码 代码如下: /// <summary>/// 生成二维码/// </summary>/// <param name="fileName">生成二维码路径</param>/// <param name="url">生成的内容</param>/// <param name="width">二维码宽</param>/// <param nam

  • c#利用Grahics进行图片裁剪

    最开始用了 复制代码 代码如下: /// <summary>        /// 裁剪图片        /// </summary>        /// <param name="imagePath"/>        /// <param name="savePath">"c:\images\"</param>        private List<string>

  • C#保存上传来的图片示例代码

    复制代码 代码如下: [HttpPost] public string UploadImage() { //string ss = Request.Form["uploadFile"]; //return ss; HttpPostedFileBase uploadFile = Request.Files[0]; string fileName = uploadFile.FileName; int fileSize = uploadFile.ContentLength; string f

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

    自动去除图像扫描黑边 复制代码 代码如下: /// <summary>        /// 自动去除图像扫描黑边        /// </summary>        /// <param name="fileName"></param>        public static void AutoCutBlackEdge(string fileName)        {            //打开图像           

  • c#根据网址抓取网页截屏生成图片的示例

    复制代码 代码如下: using System.Drawing;using System.Drawing.Imaging;using System.IO;using System.Threading;using System.Windows.Forms; public class WebsiteToImage{private Bitmap m_Bitmap;private string m_Url;private string m_FileName = string.Empty; public

  • c#实现网页图片提取工具代码分享

    复制代码 代码如下: public Array MatchHtml(string html,string com)       {           List<string> urls = new List<string>();           html = html.ToLower();           //获取SRC标签中的URL           Regex regexSrc = new Regex("src=\"[^\"]*[(.j

  • C#正则表达式匹配HTML中的图片路径,图片地址代码

    一般来说一个 HTML 文档有很多标签,比如"<html>"."<body>"."<table>"等,想把文档中的 img 标签提取出来并不是一件容易的事.由于 img 标签样式变化多端,使提取的时候用程序寻找并不容易.于是想要寻找它们就必须写一个非常健全的正则表达式,不然有可能会找得不全,或者找出来的不是正确的 img 标签.我们可以从 HTML 标签的格式去想应该怎么建这个正则表达式.首先要想一下 img

  • C#图片按比例缩放的实现代码

    复制代码 代码如下: using System.Drawing;using System.Drawing.Drawing2D;using System.Drawing.Imaging; namespace Publics{    public class ImgHelper    {        public static void AdjustPhoto(int toWidth, int toHeight, string filePath, string fromFileName, stri

  • c#图片缩放图片剪切功能实现(等比缩放)

    所谓c#图片处理高级应,多数是基于.net framework类库完成 复制代码 代码如下: using system;using system.collections.generic;using system.text;using system.io;using system.drawing;using system.drawing.drawing2d;using system.drawing.imaging; namespace wujian.common{    /// <summary>

  • c#实现把汉字转为带田字格背景的jpg图片

    复制代码 代码如下: using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;using System.Drawing;using System.IO; namespace 文字图片生成程序{    static class Program    {        /// <summary>        ///

  • C# 判断两张图片是否一致的快速方法

    复制代码 代码如下: #region 判断图片是否一致 /// <summary> /// 判断图片是否一致 /// </summary> /// <param name="img">图片一</param> /// <param name="bmp">图片二</param> /// <returns>是否一致</returns> public bool IsSameImg

  • C# 将透明图片的非透明区域转换成Region的实例代码

    需要设置允许不安全代码.....项目->属性->生成->允许不安全代码 复制代码 代码如下: /// <summary>        /// 根据图片得到一个图片非透明部分的区域      /// </summary>        /// <param name="bckImage"></param>        /// <returns></returns>        private

  • c#高效比对大量图片的实例代码

    以前传统的比较方式是遍历图片中的每一个像素,然后进行比对.这样的比对在少量图片的比对上虽然效率低一点,但是也没有什么不好.但是在大量图片比对的时候,过长的反应时间和对服务器比较高的消耗肯定是不行的. 所以微软给我们提供了另外一种比对的方法,能够正确,高效的比对出两张图片的是否相同.这种方法的原理是:将图片保存到数据流中然后使用Convert.ToBase64String将数据流转换为字符串,那么我们只需要比对两张图片的字符串就ok了.代码如下: 复制代码 代码如下: public bool Ch

  • c#读取图像保存到数据库中(数据库保存图片)

    复制代码 代码如下: 注:MyTools.g_PhotoField为数据库表中的图象字段名称//将图片保存到数据库中    if(this.picPhoto.Image==null)    {     m_DataRow[MyTools.g_PhotoField]=DBNull.Value;    }    else    {     try      {      MemoryStream ms = new MemoryStream ();      picPhoto.Image.Save (

  • C#获取图片的后缀名解析

    要说,这也是一个很简单的功能,没必要开一篇博客这么大动干戈. 对于一张知道全路径的照片,如果其路径包含后缀名的话,要取得后缀名,只需要一行代码即可: 复制代码 代码如下: var ext = System.IO.Path.GetExtension("C:\\soar.jpg"); 可是,如果这个文件的文件名不包含后缀怎么办? 在C#中并没有提供直接获取图片格式的方法,如果想根据图片(也就是Image对象)获取图片格式,那么就需要另辟蹊径了. 首先,我们可以在`Image`对象中看到一个

  • C#中按指定质量保存图片的实例代码

    在程序中直接生产jpg图片,质量不如原图,是因为微软的Image.Save方法保存到图片压缩质量为75,所以保存的图片质量偏低了,要使生成的图片质量有所提高就需要自己设定EncoderParameters类的质量参数和ImageCodecInfo类的图片保存格式. System.Drawing.Imaging.Encoder类来制定需要呈现的方式和各种参数,例如图片质量参数,扫描方法参数,色度表参数,压缩参数,颜色深度等等.到此,大家应该明白修改图片质量的步骤和方法了.主要就是对System.D

  • c#在sql中存取图片image示例

    (1)控制台应用程序下演示插入图片 复制代码 代码如下: public void InsertIMG(){//将需要存储的图片读取为数据流FileStream fs = new FileStream(@"E:\c.jpg", FileMode.Open,FileAccess.Read);Byte[] btye2 = new byte[fs.Length];fs.Read(btye2 , 0, Convert.ToInt32(fs.Length));fs.Close(); using (

随机推荐