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 cmdGo_Click()
Dim wid As Integer
Dim hgt As Integer
Dim src_bm As Picture
Dim x As Integer
Dim y As Integer
Dim mag0 As Single
Dim per0 As Single
Dim mag1 As Single
Dim per1 As Single
Dim mag2 As Single
Dim per2 As Single
Dim ix As Integer
Dim iy As Integer
Dim dx0 As Single
Dim dy0 As Single
Dim dx1 As Single
Dim dy1 As Single
Dim r As Integer
Dim g As Integer
Dim b As Integer
Dim r00 As Integer
Dim g00 As Integer
Dim b00 As Integer
Dim r01 As Integer
Dim g01 As Integer
Dim b01 As Integer
Dim r10 As Integer
Dim g10 As Integer
Dim b10 As Integer
Dim r11 As Integer
Dim g11 As Integer
Dim b11 As Integer
Dim clr As OLE_COLOR
Dim i As Integer
' Draw the source image.
wid = picSource.ScaleWidth
hgt = picSource.ScaleHeight
picSource.Cls
picDest.Cls
' Draw the text.
picSource.CurrentX = (wid - _
picSource.TextWidth(txtString.Text)) / 2
picSource.CurrentY = (hgt - _
picSource.TextHeight(txtString.Text)) / 2
picSource.Print txtString.Text
' Draw a grid if desired.
If chkDrawGrid.Value = vbChecked Then
For x = 0 To wid Step 20
For y = 0 To hgt Step 20
picSource.Line (x, 0)-(x, hgt), vbRed
picSource.Line (0, y)-(wid, y), vbRed
Next y
Next x
End If
mag0 = Random(2, 6)
per0 = Random(20, 30)
mag1 = Random(3, 6)
per1 = Random(20, 40)
mag2 = Random(1, 3)
per2 = Random(10, 20)
lblParameters.Caption = _
mag0 & ", " & per0 & "; " & _
mag1 & ", " & per1 & "; " & _
mag2 & ", " & per2
' Make the destination bitmap.
For x = 0 To wid - 1
For y = 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.
ix = Int(sx)
iy = Int(sy)
If ix < 0 Or ix >= wid - 1 Or _
iy < 0 Or iy >= hgt - 1 _
Then
picDest.PSet (x, y), vbWhite
Else
ReverseRGB picSource.Point(ix, iy), r00, _
g00, b00
ReverseRGB picSource.Point(ix + 1, iy), _
r10, g10, b10
ReverseRGB picSource.Point(ix, iy + 1), _
r01, g01, b01
ReverseRGB picSource.Point(ix + 1, iy + 1), _
r11, g11, b11
dx0 = sx - ix
dy0 = sy - iy
dx1 = 1 - dx0
dy1 = 1 - dy0
r = dy1 * (dx1 * r00 + dx0 * r10) + _
dy0 * (dx1 * r01 + dx0 * r11)
g = dy1 * (dx1 * g00 + dx0 * g10) + _
dy0 * (dx1 * g01 + dx0 * g11)
b = dy1 * (dx1 * b00 + dx0 * b10) + _
dy0 * (dx1 * b01 + dx0 * b11)
picDest.PSet (x, y), RGB(r, g, b)
End If
Next y
Next x
' Draw random lines if desired.
If chkRandomLines.Value = vbChecked Then
For i = 1 To 10
picDest.Line (Random(0, wid), 0)-(Random(0, _
wid), hgt), vbBlack
picDest.Line (Random(0, wid), 0)-(Random(0, _
wid), hgt), vbWhite
Next i
End If
End Sub
|
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)
Const PI As Single = 3.14159265
sx = x - mag0 * Cos(y * PI / per0)
sy = y - mag1 * Sin(x * PI / per1) - mag2 * Sin(x * PI _
/ per2)
End Sub
|