[Java] <8Ms Captcha OCR

Discussion in 'Code Snippets and Tutorials' started by Ryan, Sep 11, 2007.

  1. Ryan

    Ryan Level II

    Joined:
    Jan 23, 2007
    Messages:
    251
    Likes Received:
    1
    Here is my optimized, but unthreaded Neopets OCR.

    I have tested it on four images loaded from Imageshack because I haven't yet programmed the cookie handling for Neopets:
    Code (Text):
    1. <div class="text" id="{CB}" style="font-family: monospace;"><ol><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">[url=http://img294.imageshack.us/img294/8046/captchashowqr3.jpg]http://img294.imageshack.us/img294/8046 ... howqr3.jpg[/url]</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">[url=http://img395.imageshack.us/img395/8898/cap2rx5.jpg]http://img395.imageshack.us/img395/8898/cap2rx5.jpg[/url]</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">[url=http://img257.imageshack.us/img257/5319/ca3dw8.jpg]http://img257.imageshack.us/img257/5319/ca3dw8.jpg[/url]</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">[url=http://img294.imageshack.us/img294/4618/cap4ah9.jpg]http://img294.imageshack.us/img294/4618/cap4ah9.jpg[/url]</li></ol></div>
    It has so far worked extremely quickly and accurately.

    My optimizations involved cutting out the outside 10 pixels from the image as the targets do not appear off the image. I then only check every second pixel off the x-axis, from testing this has not affected the results whatsoever (although skipping on the y axis does).
    I also only use the blue channel. I found that the red channel generally targeted the outlines, and the green channel was not quite as accurate as the blue.

    I will probably leave it unthreaded as any performance gained will be nothing in comparison to internet lag, and since the creation cost of a thread is ~200Ms. There is no way I am going to stick a thread pool into the code for what will probably come out to 1-2Ms (if not a loss of performance).

    Code (Java):
    1. <div class="java" id="{CB}" style="font-family: monospace;"><ol><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;"><span style="color: #000000; font-weight: bold;">try</span> <span style="color: #66cc66;">{</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; [url=http://www.google.com/search?hl=en&q=allinurl%3ABufferedImage+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">BufferedImage</span>[/url] bCapcha = ImageIO.<span style="color: #006600;">read</span> <span style="color: #66cc66;">(</span><span style="color: #000000; font-weight: bold;">new</span> [url=http://www.google.com/search?hl=en&q=allinurl%3AURL+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">URL</span>[/url] <span style="color: #66cc66;">(</span><span style="color: #ff0000;">"ImageUrl"</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span>;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">int</span> nX = <span style="color: #cc66cc;">0</span>;</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">int</span> nY = <span style="color: #cc66cc;">0</span>;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">int</span> nD = <span style="color: #cc66cc;">255</span>;</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">int</span> nBlue;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">int</span> nWidth = bCapcha.<span style="color: #006600;">getWidth</span><span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span><span style="color: #cc66cc;">-10</span>;</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">int</span> nHeight = bCapcha.<span style="color: #006600;">getHeight</span><span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span><span style="color: #cc66cc;">-10</span>;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #993333;">long</span> nTime = [url=http://www.google.com/search?hl=en&q=allinurl%3ASystem+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">System</span>[/url].<span style="color: #006600;">currentTimeMillis</span><span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span>;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">//</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #66cc66;">(</span><span style="color: #993333;">int</span> x = <span style="color: #cc66cc;">10</span>; x < nWidth;x += <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #66cc66;">(</span><span style="color: #993333;">int</span> y = <span style="color: #cc66cc;">10</span>; y < nHeight;y += <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nBlue = <span style="color: #66cc66;">(</span>bCapcha.<span style="color: #006600;">getRGB</span> <span style="color: #66cc66;">(</span>x,y<span style="color: #66cc66;">)</span> >> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">)</span> & 0xff;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">(</span>nBlue < nD<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nD = nBlue;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nX = x;</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nY = y;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">}</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #66cc66;">}</span></li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; <span style="color: #66cc66;">}</span></li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; nTime = [url=http://www.google.com/search?hl=en&q=allinurl%3ASystem+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">System</span>[/url].<span style="color: #006600;">currentTimeMillis</span><span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span> - nTime;</li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; [url=http://www.google.com/search?hl=en&q=allinurl%3ASystem+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">System</span>[/url].<span style="color: #006600;">out</span>.<span style="color: #006600;">println</span> <span style="color: #66cc66;">(</span>nTime + <span style="color: #ff0000;">"Ms "</span> + nX + <span style="color: #ff0000;">", "</span> + nY<span style="color: #66cc66;">)</span>;</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;"><span style="color: #66cc66;">}</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #66cc66;">(</span>[url=http://www.google.com/search?hl=en&q=allinurl%3AException+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">Exception</span>[/url] e<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></li><li style="padding: 0 5px; background-color: #fff; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;">&nbsp; &nbsp; [url=http://www.google.com/search?hl=en&q=allinurl%3ASystem+java.sun.com&btnI=I%27m%20Feeling%20Lucky]<span style="color: #aaaadd; font-weight: bold;">System</span>[/url].<span style="color: #006600;">out</span>.<span style="color: #006600;">println</span> <span style="color: #66cc66;">(</span><span style="color: #ff0000;">"Error: "</span> + e.<span style="color: #006600;">toString</span><span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span><span style="color: #66cc66;">)</span>;</li><li style="padding: 0 5px; background-color: #f9f9f9; line-height: 16px; border-bottom: 1px solid #efefef; border-left: 1px solid #999;"><span style="color: #66cc66;">}</span></li></ol></div>
     
  2. Chaos_Blader

    Chaos_Blader Newbie

    Joined:
    Sep 18, 2007
    Messages:
    17
    Likes Received:
    0
    1.You don't need to handle cookies to get the captcha image.
    2. Why are you looping through each pixel? Doesn't Java have an image library for this sort of stuff. Im not a pro at java but most things are faster than looping through each pixel (unless you are looping through a list).
     
  3. ricky92

    ricky92 Administrator
    Staff Member

    Joined:
    Nov 10, 2006
    Messages:
    1,866
    Likes Received:
    67
    First, welcome to the site, Chaos_Blader. Then I just want to say that if you try to get a captcha image without neo cookies you will get a login page, nothing else. If you get the captcha image from the wrapper (or whatever you use in Python) it uses your cookies so you probably didn't ever noticed this. And welcome, again. I'm happy that you joined the site! :)
     
  4. Ryan

    Ryan Level II

    Joined:
    Jan 23, 2007
    Messages:
    251
    Likes Received:
    1
    I am looping through each pixel because I am not aware of any language, anywhere that has a library that will find the darkest pixel in an image. Its such a useless and simple process that no one has thought of including it, plus such a library would be slower since my for loop trades accuracy for speed, which no general purpose function would do and there is no other way to find the darkest pixel in an image (or at least, no other practical way).
    I will assuming you are using expon or someone else's http wrapper. I can guarantee you there is a for loop inside it.

    And believe me, you very much do need cookies to get the image, I spend a few hours trying to figure out why it could pull images from any .php except neopets, now I have to stream the data into a bytearray and convert that into an image.
     
  5. Chaos_Blader

    Chaos_Blader Newbie

    Joined:
    Sep 18, 2007
    Messages:
    17
    Likes Received:
    0
    1. Yes I am just seeing that lol. I usually just visit the captcha in firefox, without knowing im logged in.
    2. I am not using expon's wrapper. I am not using VB either, but anyways, none of my wrappers have for loops in it (wait they do, but its not when visiting a page, only when formatting headers).
    3. Since Java communicated with the JVM I would expect that its loop are slower. Do a pixel for loop in C++ or VB and see how fast it is. Its impossible to time. But on Java you get 8ms. There is nothing wrong, because that is still fast. The reason why I am saying this is because people are coding in different languages and if you translate that code to Python, Perl, or PHP which all have fast page loading times, It will take 2s+.
     
  6. Ryan

    Ryan Level II

    Joined:
    Jan 23, 2007
    Messages:
    251
    Likes Received:
    1
    Visual basic is a lot slower than Java, C# and Java are about on par, and C++ is way faster than Java at math, and moderately faster in most other categories.

    I have been pointing out that saving a few MS here and there is pretty much worthless, but a lot of people place a lot of value on the buy times so I skipped every second pixel.

    Java isn't interpreted anymore, it is JIT compiled, so instead of being compiled ahead of time on the developers machine, it is compiled on the users machine for their specific hardware. In theory, that means that the potential speed of Java is fastest, but it generally doesn't work out that way, and the Client VM (there is a server version which has a massive startup time for compiling) compiles parts of the program while it is running.

    A lot of the code you use to read page data will have loops as well, even if its behind the scenes. If you are matching patterns in strings, whatever method you are using will have to use a loop somewhere. Also, reading data from a stream generally requires a for loop depending on the implementation, but that is generally handled behind the scenes.

    Most of the functions and libraries are just normal code, you can look through and edit them, most of the more complicated ones let you re-write sections.
     
  7. Chaos_Blader

    Chaos_Blader Newbie

    Joined:
    Sep 18, 2007
    Messages:
    17
    Likes Received:
    0
    Well Im not sure about VB because I dont code in VB as your sig says it has garbage syntax. Java is potentially the fastest but it is still a high level code compared to C++ (because its compiled thats why I even mentioned VB) which is closer to ASM, which is directly acccessing the processor. I realize that they are loops everywhere, but its an idea to limit them and maybe not even remove them, but improve them. With your implementation you are using getRGB on every turn. That also includes loops and accessing something not native to your code, the gdi (on windows anyways). Here is a possible speed up, use a library that converts it into a list of pixels. Then just loop through those. Looping through numbers instead of getrgb is alot faster. It just saves a little time here and there thats all.
     
  8. Ryan

    Ryan Level II

    Joined:
    Jan 23, 2007
    Messages:
    251
    Likes Received:
    1
    Any library that converted the entire image into an array of pixel data would end up calling getRGB (or an equivalent) on every pixel anyways, which is the problem here. No matter how many libraries I hide it behind, at some point there is going to be a stacked for loop reading the pixel data. There is no processor instruction like "Return all pixel data", or windows call for it. A library is just code in a separate file, it doesn't have anything that I don't have (except for very specific libraries, which aren't used for dealing with images). Using a library would be slower because it would extract the RGB for every single pixel, and then I would loop through the numbers, again.
    I would use a library just to pull some of the code out of my program, but currently I am skipping pixels, which would give me the edge over any library that went through the entire thing.

    Technically, I could just copy-paste code out of the image class into my file to skip the function calls, but there is a point where you start taking things too far.
     
  9. expon

    expon Administrator
    Staff Member

    Joined:
    Oct 30, 2006
    Messages:
    1,393
    Likes Received:
    56
    Location:
    UK
    Hi ryan,
    you've posted some very nice java snippets so I just wanted to say thanks :)
     
  10. tac123

    tac123 Level I

    Joined:
    Apr 29, 2007
    Messages:
    124
    Likes Received:
    0
    BTW, C# has a method that returns the darkest pixel in an image. Therefore you can build a Neopets CAPTCHA OCR in one line. The problem is that it returns the darkest pixel by checking all pixels, so you can make a faster method by skipping around.

    Maybe i'll post my OCR method up later, but it lets you check only one in every 16 pixels, and still finds the neopet accurately.
     
  11. Zer0

    Zer0 Level IV

    Joined:
    Mar 2, 2008
    Messages:
    3,037
    Likes Received:
    180
    Location:
    Home sweet home
    Are all OCRs based upon finding the darkest pixel? It seems very subject to error (especially if TNT changes the security algorithm a bit).
    Anyways, nice coding!

    PS. Why do you bit-shift 0 to the right? o_O
     
  12. punkpaul

    punkpaul Level I

    Joined:
    Jan 17, 2009
    Messages:
    107
    Likes Received:
    1
    is it possible that anyone could help me covert this script to where it would work with greasemonkey? it should be able to right? i would be very appreciative. =)