【发布时间】:2010-11-29 07:33:17
【问题描述】:
我正在尝试编写一个程序来以编程方式确定任意图像中的倾斜或旋转角度。
图像具有以下属性:
- 由浅色背景上的深色文本组成
- 偶尔包含仅以 90 度角相交的水平线或垂直线。
- 在 -45 到 45 度之间倾斜。
- 请参阅 this image 作为参考(倾斜了 2.8 度)。
到目前为止,我想出了这个策略:从左到右绘制一条路线,始终选择最近的白色像素。据推测,从左到右的路线会更喜欢沿着图像倾斜的文本行之间的路径。
这是我的代码:
private bool IsWhite(Color c) { return c.GetBrightness() >= 0.5 || c == Color.Transparent; }
private bool IsBlack(Color c) { return !IsWhite(c); }
private double ToDegrees(decimal slope) { return (180.0 / Math.PI) * Math.Atan(Convert.ToDouble(slope)); }
private void GetSkew(Bitmap image, out double minSkew, out double maxSkew)
{
decimal minSlope = 0.0M;
decimal maxSlope = 0.0M;
for (int start_y = 0; start_y < image.Height; start_y++)
{
int end_y = start_y;
for (int x = 1; x < image.Width; x++)
{
int above_y = Math.Max(end_y - 1, 0);
int below_y = Math.Min(end_y + 1, image.Height - 1);
Color center = image.GetPixel(x, end_y);
Color above = image.GetPixel(x, above_y);
Color below = image.GetPixel(x, below_y);
if (IsWhite(center)) { /* no change to end_y */ }
else if (IsWhite(above) && IsBlack(below)) { end_y = above_y; }
else if (IsBlack(above) && IsWhite(below)) { end_y = below_y; }
}
decimal slope = (Convert.ToDecimal(start_y) - Convert.ToDecimal(end_y)) / Convert.ToDecimal(image.Width);
minSlope = Math.Min(minSlope, slope);
maxSlope = Math.Max(maxSlope, slope);
}
minSkew = ToDegrees(minSlope);
maxSkew = ToDegrees(maxSlope);
}
这在某些图像上效果很好,在其他图像上效果不佳,而且速度很慢。
是否有更有效、更可靠的方法来确定图像的倾斜度?
【问题讨论】:
-
我喜欢代码如何将snake_case、camelCase 和PascalCase 混合在一个简短的代码块中。显然我写的 F# 太多了。
-
你为什么使用
decimal?它不会为计算斜率增加太多精度,并且无论如何在将其传递给atan方法时,您必须将其转换回double。 -
@Cecil:将一堆双精度数相加和相除会导致精度问题。预先处理小数,然后在最后转换为双精度似乎可以轻松完成。
-
Google 和 Google Scholar 为“文档倾斜角度”提供了无数点击(感谢您提供的关键字,底座)。你看过那里的算法创意吗?
-
这里很棒。谢谢。与其只选择下一个白色像素,不如选择离其区域相邻黑色像素最远的下一个白色像素呢? font_height 大小的区域应该工作得很好。与内核的卷积可以很快地做到这一点。
标签: c# image-processing