【问题标题】:De-skew Image by Angle按角度去歪斜图像
【发布时间】:2013-03-19 15:11:57
【问题描述】:

我花了几个小时研究这个,我已经取得了一些进展,但仍然需要一些帮助。

我知道有一些库可以做到这一点,但由于我的场景非常简单,我宁愿拥有自己的代码。我正在用支票扫描仪扫描支票,但有些图片歪了,需要去歪斜;

这是我的代码:

Function DeskewImage(Original As Bitmap) As Bitmap
    Dim w = Original.Width
    Dim h = Original.Height
    'i go over the first 200 rows of pixels and for each row i get the first black pixel. this should be enough to get me the angle
    Dim FirstBlacks As New List(Of Point)
    For row = 0 To 200
        For col = 0 To w - 1
            Dim p = Original.GetPixel(col, row)
            Dim rl = CInt(p.R) + p.G + p.B
            If rl < 760 Then
                FirstBlacks.Add(New Point(col, row))
                Exit For
            End If
        Next
    Next
    'here i try to get the angle, im not sure its correct though
    Dim xyAvg = FirstBlacks.Select(Function(pnt) pnt.X * pnt.Y).Average
    Dim xAvg = FirstBlacks.Select(Function(pnt) pnt.X).Average
    Dim yAvg = FirstBlacks.Select(Function(pnt) pnt.Y).Average
    Dim xVar = FirstBlacks.Select(Function(pnt) pnt.X).Variance
    Dim coefficient = (xyAvg - xAvg * yAvg) / xVar
    Dim LeftTop = -20
    'now id like utilize the angle to skew
    Dim destinationPoints = {New Point(0, LeftTop), New Point(w, 0), New Point(0, h)}
    Dim ret = New Bitmap(w, h)
    Dim g = Graphics.FromImage(ret)
    g.DrawImage(Original, destinationPoints)
    ret.Save("D:\aa.jpg")
    Return Original
End Function

我有 2 个问题:

  1. 我的系数正确吗?这是基于这里的一篇文章 http://www.experts-exchange.com/Microsoft/Development/MS_Access/A_2799-Simple-Linear-Regression-in-MS-Access.html 但我不确定我是否正确移植了它
  2. 如何利用系数在 .net 中倾斜图像?唯一的 我可以的功能 找到需要的目的地点,我有 不知道怎么找

我还觉得奇怪的是我需要在绘制之前指定返回图像的高度和宽度。我应该如何知道偏斜之前的尺寸?

编辑

感谢 Pieter Geerkens,我将代码更改为旋转而不是倾斜

问题仍然在于算法

首先是示例图片

我上面的算法为此示例图片返回大约 -0.33 的结果。实际上我需要大约+4度的旋转。那么算法错了吗?还是需要将结果转换为度数?有什么想法吗?

赞赏

【问题讨论】:

  • 您确定需要取消倾斜吗?还是您的意思是“取消旋转”?
  • 嘿,你可能是对的。我会尽快检查一下!
  • 请看我的更新。谢谢!

标签: .net vb.net bitmap rotation angle


【解决方案1】:

尝试如下更改destinationPoints的分配:

Dim dh = coefficient * h
Dim dw = coefficient * w
Dim destinationPoints = { 
  New Point(0, LeftTop), 
  New Point(w,-dw), 
  New Point(dh, h) 
}

根据以下 OP 说明更新:

对于小角度 theta(以弧度测量),theta ~ sin(theta) ~ tan(theta)。因此,旋转角度(以度为单位)约为 l (180/PI) * 系数 * w / w = (180/PI) * 系数。

【讨论】:

  • 感谢您的回答。但根据您的建议,我使用RotateTransform(angle)。所以没有使用目的地点。我们只需要找到正确的度数。请指教。谢谢
  • 谢谢。我不明白如何在代码中编写 PI * 系数 * w / w = PI * 系数?这是一个等式(=)吗?我在使用180 / Math.PI * Radians 转换之前尝试过,但它不正确
  • 只需使用= PI * coefficient。前半部分只是展示了它的派生,而w/w 以简化形式取消了。
  • pi*coefficient 没有给出正确的结果,请在 q 中查看我的示例图片。和我发布的结果。我非常感谢您的时间和洞察力。
  • 糟糕! (羞愧地垂下头)我已经用正确的弧度公式更新了公式。这将产生大约 15 倍的答案,因此 0.33 将变为大约 5.0。该符号只是 CW 或 CCW 是否为正的约定,但对于任何约定都一致,因此在上面的公式中添加一个减号。
【解决方案2】:

好的。感谢http://www.alcula.com/calculators/statistics/linear-regression/ 我能够调试我的算法结果。这个工具帮助我发现我实际上是在混淆 xs 和 ys。正确的代码如下。

我也不得不忽略实际上是左边框而不是上边框的低 x 值。

Dim ret As Double?
    Dim w = Original.Width
    Dim h = Original.Height
    Dim FirstBlacks = New List(Of Point)
    Dim MaxHeight = h - 1
    Dim done = False
    For y = 0 To MaxHeight
        If done Then Exit For
        For x = 0 To w - 1
            Dim p = Original.GetPixel(x, y)
            Dim rl = p.GetBrightness
            If rl < 1 Then
                If x < 20 Then
                    done = True
                Else
                    FirstBlacks.Add(New Point(x, y))
                End If
                Exit For
            End If
        Next
    Next
    If FirstBlacks.Count > 2 Then
        Dim xyAvg = FirstBlacks.Select(Function(pnt) pnt.X * pnt.Y).Average
        Dim xAvg = FirstBlacks.Select(Function(pnt) pnt.X).Average
        Dim yAvg = FirstBlacks.Select(Function(pnt) pnt.Y).Average
        Dim xVar = FirstBlacks.Select(Function(pnt) pnt.X).Variance
        ret = (xyAvg - xAvg * yAvg) / xVar
    End If
    Return ret

感谢 Pieter-Geerkens 在此过程中提供的所有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 2012-03-30
    • 2020-04-26
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    相关资源
    最近更新 更多