Yisroel M. Olewski
Yisroel M. Olewski

Reputation: 1628

De-skew Image by Angle

I've spent a few hours researching this and I've made some progress but still need some help.

I'm aware there are libraries to do this, but since my scenario is terribly simple, I'd rather have my own code. I'm scanning checks in a check scanner, but some images get in crooked and need to be de-skewed;

Here is my code:

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

I have 2 issues:

  1. Is my coefficient correct? this was based on an article here http://www.experts-exchange.com/Microsoft/Development/MS_Access/A_2799-Simple-Linear-Regression-in-MS-Access.html but im not sure i ported it correctly
  2. how do i utilize the coefficient to skew the image in .net? the only function that i can find needs destination points, which i have no idea how to find

I also find it odd that I need to specify the height & width of the return image before drawing. How am I supposed to know the size before the skew?

EDIT

thanks to Pieter Geerkens i changed my code to rotating instead of skewing

the problem now remains with the algorithm

first off heres is a sample image sample

my algorithm above returns a result of approx -0.33 forthis sample pic. where in reality i need approx a +4 degree rotation. so is the algorithm wrong? or does the result need to be converted to degrees? any ideas?

with appreciation

Upvotes: 0

Views: 655

Answers (2)

Yisroel M. Olewski
Yisroel M. Olewski

Reputation: 1628

OK. thanks to http://www.alcula.com/calculators/statistics/linear-regression/ i was able to debug my algo results. this tool helped me find out that i was actually mixing up the xs and ys. the correct code follows.

also i had to ignore low x values which are actually the left border, not top border.

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

thanks to Pieter-Geerkens for all his help along the way

Upvotes: 0

Pieter Geerkens
Pieter Geerkens

Reputation: 11893

Try changing the assignment of destinationPoints as follows:

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

Update as per OP note below:

For small angles theta (measured in radians), theta ~ sin(theta) ~ tan(theta). Therefore tha angle of rotation (in degrees) is approximatelyl (180/PI) * coefficient * w / w = (180/PI) * coefficient.

Upvotes: 1

Related Questions