Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleMake CAPTCHA images (version 6) in Visual Basic .NET
DescriptionThis example shows how to make CAPTCHA images (version 6) in Visual Basic .NET.
KeywordsCAPTCHA, Turing test, image, image processing, distort image
CategoriesGraphics, Software Engineering
 

This program uses image processing techniques described in my book Ready-to-Run Visual Basic Graphics Programming.

CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) images are those distorted pictures of words that some Web sites make you enter to prove you are a human and not an automated process. The idea is to distort the characters in the image so it would be hard for an optical character recognition (OCR) application to read them but so it would still be easy for a person to read them.

This example draws text that has been warped by sine functions. When you click the Go button, the code draw the string on a source PictureBox. It then draws a grid on top if desired. This is useful for seeing how the image is deformed later but it might make it easier to automatically recognize the text so you might want to not use it in real use.

Next the code generates some random parameters for the equations that map the pixels in the image to the warped version. It displays the parameters in a label so you can see what's happening. You can change the way the parameters are generated (i.e. change the upper and lower bounds for the random numbers) to see how if changes the result.

Next the code loops through each pixel in the warped output image. For each pixel, it calls subroutine InvertXY to see what location in the original image would be mapped to that output location. It then uses bilinear interpolation to average the nearby pixels at integer locations in the original image to assign a value to the output image. The result is a smoothly transformed image.

Finally the code draws and erases some random lines over the top of the result if desired to make the image harder for an automated system to read.

 
Private Sub btnGo_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnGo.Click
    Dim rand As New Random()

    ' Draw the source image.
    Dim wid As Integer = picSource.ClientSize.Width
    Dim hgt As Integer = picSource.ClientSize.Height

    Dim src_bm As New Bitmap(wid, hgt)
    Using gr As Graphics = Graphics.FromImage(src_bm)
        gr.Clear(Color.White)

        ' Draw the text.
        Using fnt As New Font("Times New Roman", 20, _
            FontStyle.Bold, GraphicsUnit.Pixel)
            Using sf As New StringFormat()
                sf.Alignment = StringAlignment.Center
                sf.LineAlignment = StringAlignment.Center
                gr.DrawString(txtString.Text, fnt, _
                    Brushes.Black, wid / 2, hgt / 2, sf)
            End Using
        End Using

        ' Draw a grid if desired.
        If chkDrawGrid.Checked Then
            For x As Integer = 0 To wid Step 20
                For y As Integer = 0 To hgt Step 20
                    gr.DrawLine(Pens.Red, x, 0, x, hgt)
                    gr.DrawLine(Pens.Red, 0, y, wid, y)
                Next y
            Next x
        End If
    End Using
    picSource.Image = src_bm

    Dim mag0 As Single = rand.Next(2, 6)
    Dim per0 As Single = rand.Next(20, 30)
    Dim mag1 As Single = rand.Next(3, 6)
    Dim per1 As Single = rand.Next(20, 40)
    Dim mag2 As Single = rand.Next(1, 3)
    Dim per2 As Single = rand.Next(10, 20)
    lblParameters.Text = _
        mag0 & ", " & per0 & "; " & _
        mag1 & ", " & per1 & "; " & _
        mag2 & ", " & per2

    ' Make the destination bitmap.
    Dim bm As New Bitmap(wid, hgt)
    For x As Integer = 0 To wid - 1
        For y As Integer = 0 To hgt - 1
            ' Find source (x, y).
            Dim sx As Single
            Dim sy As Single
            InvertXY(mag0, per0, mag1, per1, mag2, per2, x, _
                y, sx, sy)

            ' Interpolate.
            Dim ix As Integer = Int(sx)
            Dim iy As Integer = Int(sy)

            If ix < 0 OrElse ix >= wid - 1 OrElse _
               iy < 0 OrElse iy >= hgt - 1 _
            Then
                bm.SetPixel(x, y, Color.White)
            Else
                Dim dx0 As Single = sx - ix
                Dim dy0 As Single = sy - iy
                Dim dx1 As Single = 1 - dx0
                Dim dy1 As Single = 1 - dy0
                Dim r As Integer = _
                    dy1 * _
                        (dx1 * src_bm.GetPixel(ix, iy).R + _
                         dx0 * src_bm.GetPixel(ix + 1, _
                             iy).R) + _
                    dy0 * _
                        (dx1 * src_bm.GetPixel(ix, iy + _
                            1).R + _
                         dx0 * src_bm.GetPixel(ix + 1, iy + _
                             1).R)
                Dim g As Integer = _
                    dy1 * _
                        (dx1 * src_bm.GetPixel(ix, iy).G + _
                         dx0 * src_bm.GetPixel(ix + 1, _
                             iy).G) + _
                    dy0 * _
                        (dx1 * src_bm.GetPixel(ix, iy + _
                            1).G + _
                         dx0 * src_bm.GetPixel(ix + 1, iy + _
                             1).G)
                Dim b As Integer = _
                    dy1 * _
                        (dx1 * src_bm.GetPixel(ix, iy).B + _
                         dx0 * src_bm.GetPixel(ix + 1, _
                             iy).B) + _
                    dy0 * _
                        (dx1 * src_bm.GetPixel(ix, iy + _
                            1).B + _
                         dx0 * src_bm.GetPixel(ix + 1, iy + _
                             1).B)
                bm.SetPixel(x, y, Color.FromArgb(255, r, g, _
                    b))
            End If
        Next y
    Next x

    ' Draw random lines if desired.
    If chkRandomLines.Checked Then
        Using gr As Graphics = Graphics.FromImage(bm)
            For i As Integer = 1 To 10
                gr.DrawLine(Pens.Black, rand.Next(0, wid), _
                    0, rand.Next(0, wid), hgt)
                gr.DrawLine(Pens.White, rand.Next(0, wid), _
                    0, rand.Next(0, wid), hgt)
            Next i
        End Using
    End If

    picDest.Image = bm
End Sub
 
Helper routine InvertXY finds the source point (sx, sy) that maps to the result position (x, y) under the function defined by the ranomized parameters.
 
Private Sub InvertXY(ByVal mag0 As Single, ByVal per0 As _
    Single, ByVal mag1 As Single, ByVal per1 As Single, _
    ByVal mag2 As Single, ByVal per2 As Single, ByVal x As _
    Integer, ByVal y As Integer, ByRef sx As Single, ByRef _
    sy As Single)
    sx = x - mag0 * Math.Cos(y * Math.PI / per0)
    sy = y - mag1 * Math.Sin(x * Math.PI / per1) - mag2 * _
        Math.Sin(x * Math.PI / per2)
End Sub
 
 
Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated