1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

[.NET / C#] Fastest Neopets OCR

Discussion in 'Code Snippets and Tutorials' started by Lightning, Jul 23, 2011.

  1. Lightning

    Lightning Administrator
    Staff Member

    Joined:
    Nov 8, 2008
    Messages:
    3,021
    Likes Received:
    195
    Gender:
    Male
    Location:
    Florida, USA
    C#
    Code (Text):
    1.  
    2. /// <summary>
    3.         /// Returns a string of the pet OCR location required to complete a main shop purchase in Neopets.
    4.         /// </summary>
    5.         /// <param name="imgOCR">Required. The image to find the darkest pixel of (OCR in Neopets).</param>
    6.         /// <param name="xSpeed">Optional. The increments of X to scan by.</param>
    7.         /// <param name="ySpeed">Optional. The increments of Y to scan by.</param>
    8.         /// <param name="xError">Optional. The integer to adjust the X value by before returning.</param>
    9.         /// <param name="yError">Optional. The integer to adjust the Y value by before returning.</param>
    10.         /// <param name="retBright">Optional. If this value is found, it will immediately return the X and Y values and stop checking for lower values.</param>
    11.         /// <returns></returns>
    12.         public string NeopetsOCR(Bitmap imgOCR, int xSpeed = 10, int ySpeed = 10, int xError = 10, int yError = 10, int retBright = 110)
    13.         {
    14.             System.Drawing.Imaging.BitmapData imgData = imgOCR.LockBits(new Rectangle(10, 10, imgOCR.Width - 11, imgOCR.Height - 11), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    15.             int retX = 0, retY = 0;
    16.             int curBright = 0;
    17.             int maxBright = 255;
    18.             int indxBright = 0;
    19.             IntPtr ptrScan0 = imgData.Scan0;
    20.            
    21.  
    22.             try
    23.             {
    24.                 if (xSpeed + ySpeed < 4)
    25.                 {
    26.                     int[] rgbValues = new int[imgData.Width * imgData.Height + 1];
    27.                     Marshal.Copy(ptrScan0, rgbValues, 0, rgbValues.Length);
    28.                     imgOCR.UnlockBits(imgData);
    29.  
    30.                     for (int Y = 0; Y <= imgData.Height - 1; Y += ySpeed)
    31.                     {
    32.                         for (int X = 0; X <= imgData.Width - 1; X += xSpeed)
    33.                         {
    34.                             indxBright = (Y * (imgData.Width)) + X;
    35.  
    36.                             curBright = (int)((0.2 * ((rgbValues[indxBright] & 0xff0000) / 65536)) + (0.7 * ((rgbValues[indxBright] & 0xff00) / 256)) + (0.1 * (rgbValues[indxBright] & 0xff)));
    37.  
    38.                             if (curBright <= retBright)
    39.                             {
    40.                                 return "&x=" + (X + xError + 10).ToString() + "&y=" + (Y + yError + 10).ToString();
    41.                             }
    42.                             else if (curBright < maxBright)
    43.                             {
    44.                                 retY = Y;
    45.                                 retX = X;
    46.                                 maxBright = curBright;
    47.                             }
    48.                         }
    49.                     }
    50.                 }
    51.                 else
    52.                 {
    53.                     for (int Y = 0; Y <= imgData.Height - 1; Y += ySpeed)
    54.                     {
    55.                         for (int X = 0; X <= imgData.Width - 1; X += xSpeed)
    56.                         {
    57.                             indxBright = Marshal.ReadInt32(ptrScan0, (imgData.Stride * Y) + (X * 4));
    58.                             curBright = (int)((0.2 * ((indxBright & 0xff0000) / 65536)) + (0.7 * ((indxBright & 0xff00) / 256)) + (0.1 * (indxBright & 0xff)));
    59.  
    60.                             if (curBright == 0)
    61.                             {
    62.                                 return "&x=" + (X + xError + 10).ToString() + "&y=" + (Y + yError + 10).ToString();
    63.                             }
    64.                             else if (curBright < maxBright)
    65.                             {
    66.                                 maxBright = curBright;
    67.                                 retX = X;
    68.                                 retY = Y;
    69.                             }
    70.                         }
    71.                     }
    72.                     imgOCR.UnlockBits(imgData);
    73.                 }
    74.                
    75.             }
    76.             catch (Exception ex)
    77.             {
    78.                 //Do something
    79.             }
    80.             return "&x=" + (retX + xError + 10).ToString() + "&y=" + (retY + yError + 10).ToString();
    81.             }
    82.  


    VB.NET
    Code (Text):
    1.  
    2. ''' <summary>
    3. ''' Returns a string of the pet OCR location required to complete a main shop purchase in Neopets.
    4. ''' </summary>
    5. ''' <param name="imgOCR">Required. The image to find the darkest pixel of (OCR in Neopets).</param>
    6. ''' <param name="xSpeed">Optional. The increments of X to scan by.</param>
    7. ''' <param name="ySpeed">Optional. The increments of Y to scan by.</param>
    8. ''' <param name="xError">Optional. The integer to adjust the X value by before returning.</param>
    9. ''' <param name="yError">Optional. The integer to adjust the Y value by before returning.</param>
    10. ''' <param name="retBright">Optional. If this value is found, it will immediately return the X and Y values and stop checking for lower values.</param>
    11. ''' <returns></returns>
    12. Public Function NeopetsOCR(imgOCR As Bitmap, Optional xSpeed As Integer = 10, Optional ySpeed As Integer = 10, Optional xError As Integer = 10, Optional yError As Integer = 10, Optional retBright As Integer = 110) As String
    13.     Dim imgData As System.Drawing.Imaging.BitmapData = imgOCR.LockBits(New Rectangle(10, 10, imgOCR.Width - 11, imgOCR.Height - 11), System.Drawing.Imaging.ImageLockMode.[ReadOnly], System.Drawing.Imaging.PixelFormat.Format32bppArgb)
    14.     Dim retX As Integer = 0, retY As Integer = 0
    15.     Dim curBright As Integer = 0
    16.     Dim maxBright As Integer = 255
    17.     Dim indxBright As Integer = 0
    18.     Dim ptrScan0 As IntPtr = imgData.Scan0
    19.  
    20.  
    21.     Try
    22.         If xSpeed + ySpeed < 4 Then
    23.             Dim rgbValues As Integer() = New Integer(imgData.Width * imgData.Height) {}
    24.             Marshal.Copy(ptrScan0, rgbValues, 0, rgbValues.Length)
    25.             imgOCR.UnlockBits(imgData)
    26.  
    27.             Dim Y As Integer = 0
    28.             While Y <= imgData.Height - 1
    29.                 Dim X As Integer = 0
    30.                 While X <= imgData.Width - 1
    31.                     indxBright = (Y * (imgData.Width)) + X
    32.  
    33.                     curBright = CInt(Math.Truncate((0.2 * ((rgbValues(indxBright) And &Hff0000) \ 65536)) + (0.7 * ((rgbValues(indxBright) And &Hff00) \ 256)) + (0.1 * (rgbValues(indxBright) And &Hff))))
    34.  
    35.                     If curBright <= retBright Then
    36.                         Return "&x=" & (X + xError + 10).ToString() & "&y=" & (Y + yError + 10).ToString()
    37.                     ElseIf curBright < maxBright Then
    38.                         retY = Y
    39.                         retX = X
    40.                         maxBright = curBright
    41.                     End If
    42.                     X += xSpeed
    43.                 End While
    44.                 Y += ySpeed
    45.             End While
    46.         Else
    47.             Dim Y As Integer = 0
    48.             While Y <= imgData.Height - 1
    49.                 Dim X As Integer = 0
    50.                 While X <= imgData.Width - 1
    51.                     indxBright = Marshal.ReadInt32(ptrScan0, (imgData.Stride * Y) + (X * 4))
    52.                     curBright = CInt(Math.Truncate((0.2 * ((indxBright And &Hff0000) \ 65536)) + (0.7 * ((indxBright And &Hff00) \ 256)) + (0.1 * (indxBright And &Hff))))
    53.  
    54.                     If curBright = 0 Then
    55.                         Return "&x=" & (X + xError + 10).ToString() & "&y=" & (Y + yError + 10).ToString()
    56.                     ElseIf curBright < maxBright Then
    57.                         maxBright = curBright
    58.                         retX = X
    59.                         retY = Y
    60.                     End If
    61.                     X += xSpeed
    62.                 End While
    63.                 Y += ySpeed
    64.             End While
    65.             imgOCR.UnlockBits(imgData)
    66.  
    67.         End If
    68.     Catch ex As Exception
    69.         'Do something
    70.     End Try
    71.     Return "&x=" & (retX + xError + 10).ToString() & "&y=" & (retY + yError + 10).ToString()
    72. End Function
    73.  
    74.  


    This is probably the fastest you will ever get a Neopets OCR in .NET to go. Although you really don't need it this fast cause you want to look human, it is still good to have the speed when you need it or when you're going all-out illegit.

    What it does:
    • Returns on finding any pixel with a brightness of 0.
    • Calculates whether the Marshal.Copy or Marshal.ReadInt32 methods are faster. I found that when the x and y speeds add up to anything less than 4, it is faster to use Marshal.Copy, while when you are going by increments of 10 and 15, it is a waste of time to Copy the whole image data to an array before reading it.
    • Allows you to enter a specific xError and yError to add to the final OCR value, and specific xSpeed and ySpeed to find the right balance between speed and accuracy. I find that 10 for all of those values work perfectly fine.
    • Cuts off 10 pixels each side as they don't usually contain the pet anyways. Saves more time.
    • Return brightness can be set by a parameter. If this value is found, it will immediately return the X and Y values and stop checking for lower values.
    • XML Documentation :)
    • Returns a string that is needed for the POST data when buying an item from Neopets' main shops.
     
  2. Junior

    Junior Administrator
    Staff Member

    Joined:
    Nov 8, 2009
    Messages:
    3,350
    Likes Received:
    169
    Location:
    I come from a land down under! (Maaaate!)
    *cough* AU update *cough*
     
  3. Lightning

    Lightning Administrator
    Staff Member

    Joined:
    Nov 8, 2008
    Messages:
    3,021
    Likes Received:
    195
    Gender:
    Male
    Location:
    Florida, USA
    Haha, AU actually does a pretty nice job. Inversing the colors and finding the strongest red concentration in the picture -- idk, but AU always seems to be right on the edge of the picture. Although I do suggest calculating approximate luminance ((0.2*R) + (0.7*G) + (0.1*B)) which accounts for what the human eye sees, which is what this function does. The human eye sees the most green, followed by red and a little of blue.