C#实现bitmap图像矫正

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Diagnostics;
using System.Drawing.Imaging;

//窗体调用

private Bitmap RotateImage(Bitmap bmp, double angle)
        {
            Graphics g = null;
            Bitmap tmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb);
            tmp.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
            g = Graphics.FromImage(tmp);
            try
            {
                g.FillRectangle(Brushes.White, 0, 0, bmp.Width, bmp.Height);
                g.RotateTransform((float)angle);
                g.DrawImage(bmp, 0, 0);
            }
            finally
            {
                g.Dispose();
            }
            return tmp;
        }

        private void button1_Click(object sender, EventArgs e)
        {

           string fnIn = "f:\\test\\image0097_4.tif";
            string fnOut = "f:\\test\\output.tif";
            Bitmap bmpIn = new Bitmap(fnIn);
            gmseDeskew sk = new gmseDeskew(bmpIn);
            double skewangle = sk.GetSkewAngle();
            Bitmap bmpOut = RotateImage(bmpIn, -skewangle);
            bmpOut.Save(fnOut, ImageFormat.Tiff);//此处简单保存,可采用压缩方式保存
                   }

#region 算法处理类

public class gmseDeskew
    {
        public 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;
            public double d;
        }
        Bitmap cBmp;
        double cAlphaStart = -20;
        double cAlphaStep = 0.2;
        int cSteps = 40 * 5;
        double[] cSinA;
        double[] cCosA;
        double cDMin;
        double cDStep = 1;
        int cDCount;
        // Count of points that fit in a line.
        int[] cHMatrix;
        public double GetSkewAngle()
        {
            gmseDeskew.HougLine[] hl = null;
            int i = 0;
            double sum = 0;
            int count = 0;
            // Hough Transformation 

           Calc();
            // Top 20 of the detected lines in the image.
            hl = GetTop(20);
            // Average angle of the lines
            for (i = 0; i <= 19; i++)
            {
                sum += hl[i].Alpha;
                count += 1;
            }
            return sum / count;
        }
        private HougLine[] GetTop(int Count)
        {
            HougLine[] hl = null;
            int i = 0;
            int j = 0;
            HougLine tmp = null;
            int AlphaIndex = 0;
            int dIndex = 0;
            hl = new HougLine[Count + 1];
            for (i = 0; i <= Count - 1; i++)
            {
                hl[i] = new HougLine();
            }
            for (i = 0; i <= cHMatrix.Length - 1; i++)
            {
                if (cHMatrix[i] > hl[Count - 1].Count)
                {
                    hl[Count - 1].Count = cHMatrix[i];
                    hl[Count - 1].Index = i;
                    j = Count - 1;
                    while (j > 0 && hl[j].Count > hl[j - 1].Count)
                    {
                        tmp = hl[j];
                        hl[j] = hl[j - 1];
                        hl[j - 1] = tmp; j -= 1;
                    }
                }
            }
            for (i = 0; i <= Count - 1; i++)
            {
                dIndex = hl[i].Index / cSteps;
                AlphaIndex = hl[i].Index - dIndex * cSteps;
                hl[i].Alpha = GetAlpha(AlphaIndex);
                hl[i].d = dIndex + cDMin;
            }
            return hl;
        }
        public gmseDeskew(Bitmap bmp)
        {
            cBmp = bmp;
        }
        private void Calc()
        {
            int x = 0;
            int y = 0;
            int hMin = cBmp.Height / 4;
            int hMax = cBmp.Height * 3 / 4;
            Init();
            for (y = hMin; y <= hMax; y++)
            {
                for (x = 1; x <= cBmp.Width - 2; x++)
                {    // Only lower edges are considered.
                    if (IsBlack(x, y))
                    {
                        if (!IsBlack(x, y + 1))
                        {
                            Calc(x, y);
                        }
                    }
                }
            }
        }
        private void Calc(int x, int y)
        {
            int alpha = 0;
            double d = 0;
            int dIndex = 0;
            int Index = 0;
            for (alpha = 0; alpha <= cSteps - 1; alpha++)
            {
                d = y * cCosA[alpha] - x * cSinA[alpha];
                dIndex = (int)CalcDIndex(d);
                Index = dIndex * cSteps + alpha;
                try
                {
                    cHMatrix[Index] += 1;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
            }
        }
        private double CalcDIndex(double d)
        {
            return Convert.ToInt32(d - cDMin);
        }
        private bool IsBlack(int x, int y)
        {
            Color c = default(Color);
            double luminance = 0;
            c = cBmp.GetPixel(x, y);
            luminance = (c.R * 0.299) + (c.G * 0.587) + (c.B * 0.114);
            return luminance < 140;
        }
        private void Init()
        {
            int i = 0;
            double angle = 0;
            // Precalculation of sin and cos.
            cSinA = new double[cSteps];
            cCosA = new double[cSteps];
            for (i = 0; i <= cSteps - 1; i++)
            {
                angle = GetAlpha(i) * Math.PI / 180.0;
                cSinA[i] = Math.Sin(angle);
                cCosA[i] = Math.Cos(angle);
            }  // Range of d:
            cDMin = -cBmp.Width;
            cDCount = (int)(2 * (cBmp.Width + cBmp.Height) / cDStep);
            cHMatrix = new int[cDCount * cSteps + 1];
        }
        public double GetAlpha(int Index)
        {
            return cAlphaStart + Index * cAlphaStep;
        }
    }

#endregion

具体算法为:由左边界开始扫描,从开始发现黑色素到黑色素达到平均值,在这个距离内的长度和版心的高度通过直角三角形的函数进行换算,这样就知道了倾斜的角度。

时间: 2024-10-02 05:10:43

C#实现bitmap图像矫正的相关文章

WPF笔记整理 - Bitmap和BitmapImage

项目中有图片处理的逻辑,因此要用到Bitmap.而WPF加载的一般都是BitmapImage.这里就需要将BitmapImage转成Bitmap 1. 图片的路径要用这样的,假设图片在project下的Images目录,文件名XXImage.png. pack://application:,,,/xxx;component/Images/XXImage.png 2. 代码: Bitmap bmp = null; var image = new BitmapImage(new Uri(this.X

【Android自学日记】关于Bitmap的理解和使用-不完整版

最近的Android自学刚好学习到异步线程的使用,对于开启异步线程加载网络图片中用到的Bitmap有点小蒙逼,这到底是个啥???所以我就自信的打开了百度!!以下就是我学习到的知识! 百度定义: 位图文件(Bitmap),扩展名可以是.bmp或者.dib.位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2.4.8.16.24和32位色彩.例如,一幅1024×768分辨率的32位真彩图片,其所占存储字节数为:1024×768×32/(8*1024)

bitset bitmap 海量数据处理

bitmap:是一个十分有用的结构.所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省.      适用范围:可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下 基本原理及要点:使用bit数组来表示某些元素是否存在,比如8位电话号码 扩展:bloom filter可以看做是对bit-map的扩展 问题实例: 1)已知某个文件内包含一些电话号码,每个号码为8位数字,统计不

Android异步加载全解析之Bitmap

Android异步加载全解析之Bitmap 在这篇文章中,我们分析了Android在对大图处理时的一些策略--Android异步加载全解析之大图处理  戳我戳我 那么在这篇中,我们来对图像--Bitmap进行一个更加细致的分析,掌握Bitmap的点点滴滴. 引入 Bitmap这玩意儿号称Android App头号杀手,特别是3.0之前的版本,简直就是皇帝般的存在,碰不得.摔不得.虽然后面的版本Android对Bitmap的管理也进行了一系列的优化,但是它依然是非常难处理的一个东西.在Androi

基于Redis bitmap实现开关配置功能

作者:zhanhailiang 日期:2014-12-21 bitmap api SETBIT key offset value 对key所储存的字符串值,设置或清除指定偏移量上的位(bit). 位的设置或清除取决于value参数,可以是0也可以是1. 当key不存在时,自动生成一个新的字符串值. 字符串会进行伸展(grown)以确保它可以将value保存在指定的偏移量上. 当字符串值进行伸展时,空白位置以0填充. offset参数必须大于或等于0,小于2^32(bit映射被限制在512MB之内

基于Redis bitmap实现签到功能

作者:zhanhailiang 日期:2014-12-21 需求场景 Bitmap 对于一些特定类型的计算非常有效. 假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户A上线了多少天,用户B上 线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加beta测试等活动--这个模式可以使 用SETBIT和BITCOUNT来实现. 比如说,每当用户在某一天上线的时候,我们就使用SETBIT,以用户名作为key,将那天所代表的网站 的上线日作为offset 参数,并将这个offset

Android艺术——Bitmap高效加载和缓存(1)

通过Bitmap我们可以设计一个ImageLoader,实现应该具有的功能是: 图片的同步加载:图片的异步加载:图片的压缩:内存缓存:磁盘缓存:网络获取: 1.加载 首先提到加载:BitmapFactory类提供了四类方法:decodeFile.decodeResource.decodeStream和decideByteArray.分别是文件系统.资源.输入流和字节数加载Bitmap对象. 2.压缩 如何进行图片的压缩?首先我们为什么图片压缩呢?因为很多时候ImageView尺寸小于图片原始尺寸

C# Bitmap类型与Byte[]类型相互转化

Bitmap   =>   byte[] Bitmap b = new Bitmap( "test.bmp "); MemoryStream ms = new MemoryStream(); b.Save(ms,System.Drawing.Imaging.ImageFormat.Bmp); byte[] bytes= ms.GetBuffer(); //byte[] bytes= ms.ToArray(); 这两句都可以,至于区别么,下面有解释 ms.Close(); byte

Bitmap 内存优化

Android在加载大背景图或者大量图片时,经常导致内存溢出(Out of Memory  Error),本文根据我处理这些问题的经历及其它开发者的经验,整理解决方案如下(部分代码及文字出处无法考证):  方案一.读取图片时注意方法的调用,适当压缩  尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗