C#实现bitmap图像矫正
2024-08-31 23:21:31
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, , , bmp.Width, bmp.Height);
g.RotateTransform((float)angle);
g.DrawImage(bmp, , );
}
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 = -;
double cAlphaStep = 0.2;
int cSteps = * ;
double[] cSinA;
double[] cCosA;
double cDMin;
double cDStep = ;
int cDCount;
// Count of points that fit in a line.
int[] cHMatrix;
public double GetSkewAngle()
{
gmseDeskew.HougLine[] hl = null;
int i = ;
double sum = ;
int count = ;
// Hough Transformation Calc();
// Top 20 of the detected lines in the image.
hl = GetTop();
// Average angle of the lines
for (i = ; i <= ; i++)
{
sum += hl[i].Alpha;
count += ;
}
return sum / count;
}
private HougLine[] GetTop(int Count)
{
HougLine[] hl = null;
int i = ;
int j = ;
HougLine tmp = null;
int AlphaIndex = ;
int dIndex = ;
hl = new HougLine[Count + ];
for (i = ; i <= Count - ; i++)
{
hl[i] = new HougLine();
}
for (i = ; i <= cHMatrix.Length - ; i++)
{
if (cHMatrix[i] > hl[Count - ].Count)
{
hl[Count - ].Count = cHMatrix[i];
hl[Count - ].Index = i;
j = Count - ;
while (j > && hl[j].Count > hl[j - ].Count)
{
tmp = hl[j];
hl[j] = hl[j - ];
hl[j - ] = tmp; j -= ;
}
}
}
for (i = ; i <= Count - ; 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 = ;
int y = ;
int hMin = cBmp.Height / ;
int hMax = cBmp.Height * / ;
Init();
for (y = hMin; y <= hMax; y++)
{
for (x = ; x <= cBmp.Width - ; x++)
{ // Only lower edges are considered.
if (IsBlack(x, y))
{
if (!IsBlack(x, y + ))
{
Calc(x, y);
}
}
}
}
}
private void Calc(int x, int y)
{
int alpha = ;
double d = ;
int dIndex = ;
int Index = ;
for (alpha = ; alpha <= cSteps - ; alpha++)
{
d = y * cCosA[alpha] - x * cSinA[alpha];
dIndex = (int)CalcDIndex(d);
Index = dIndex * cSteps + alpha;
try
{
cHMatrix[Index] += ;
}
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 = ;
c = cBmp.GetPixel(x, y);
luminance = (c.R * 0.299) + (c.G * 0.587) + (c.B * 0.114);
return luminance < ;
}
private void Init()
{
int i = ;
double angle = ;
// Precalculation of sin and cos.
cSinA = new double[cSteps];
cCosA = new double[cSteps];
for (i = ; i <= cSteps - ; 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)( * (cBmp.Width + cBmp.Height) / cDStep);
cHMatrix = new int[cDCount * cSteps + ];
}
public double GetAlpha(int Index)
{
return cAlphaStart + Index * cAlphaStep;
}
} #endregion
具体算法为:由左边界开始扫描,从开始发现黑色素到黑色素达到平均值,在这个距离内的长度和版心的高度通过直角三角形的函数进行换算,这样就知道了倾斜的角度。
最新文章
- jquery实现限制textarea输入字数
- CF#335 Sorting Railway Cars
- ArrayAdapter参数的不同运用
- [Sparrow OS 设计文档连载(一)] Introduction
- LINUX 添加定时任务
- 随机List中数据的排列顺序
- 最大流加强 dinic+当前弧优化
- 第一个androidAPP项目总结—数据请求
- VS2012+SQL2008+ODBC编程,第一篇博客,写的不好忘各位大神指点一二~
- ArcEngine栅格和矢量渲染(含可视化颜色带)
- C++_知识点_namespace
- pythonchallenge
- 如何用CSS和jQuery实现一个侧滑导航菜单
- nyoj234 吃土豆 01背包
- [译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块
- 使用Python操作MongoDB
- JavaScript传递参数方法
- OPENAPI规范Swagger
- android 组件使用()
- HDU 1535 Invitation Cards(逆向思维+邻接表+优先队列的Dijkstra算法)