We help IT Professionals succeed at work.

Can this bitmap compare be speed-tweaked?

riceman0
riceman0 asked
on
Medium Priority
481 Views
Last Modified: 2008-01-09

Hey, I have to compare a series of bitmaps to portions of a larger, stored bitmap to see if they match, and I've got code that works, but it would be better if it worked faster.  My code is below... I've tried a couple of things but right now that's best I can do.  Has anyone done this a different way that might be faster (I'll benchmark it)?

One weird thing is that my bitmaps seem to be not identical matches, what seems to work is if I give it a threshold of +-6 on the R, G, and B compare... thus the strange compare.

Thanks!

****


    Private Function ComparePixels(ByVal ox As Integer, ByVal oy As Integer, ByVal CompareTo As Bitmap) As Integer

        ' simple: got a match, add one; mismatch, subtract two

        Dim c1 As Color, c2 As Color, result As Integer = 0

        For x As Integer = 0 To CompareTo.Width - 1

            For y As Integer = 0 To CompareTo.Height - 1

                c1 = m_bmp.GetPixel(ox + x, oy + y)
                c2 = CompareTo.GetPixel(x, y)

                if CompareColor(c1, c2) then
                    result += 1
                Else
                    result -= 2
                End If

            Next

        Next

        ComparePixels = result

    End Function

    Private Function CompareColor(ByVal c1 As Color, ByVal c2 As Color) As Boolean

        Const T As Integer = 6

        If c1.R > c2.R - T Then
            If c1.R < c2.R + T Then
                If c1.G > c2.G - T Then
                    If c1.G < c2.G + T Then
                        If c1.B > c2.B - T Then
                            If c1.B < c2.B + T Then
                                Return True
                            End If
                        End If
                    End If
                End If
            End If
        End If

        Return False

    End Function
Comment
Watch Question

Author

Commented:

Oh, and I MIGHT be able to solve the (separate) mismatched images problem, which would mean that I don't need the +/- 6 threshold any nore, so I would also be interested in alternatives that only work on perfectly identical images.
Commented:
If you can get rid of the mismatched images problem, this might help

Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Security.Cryptography
Namespace Imagio

 Public Class ComparingImages

   Public Enum CompareResult
     Private ciCompareOk
     Private ciPixelMismatch
     Private ciSizeMismatch
   End Enum

   Public Shared Function Compare(ByVal bmp1 As Bitmap, ByVal bmp2 As Bitmap) As CompareResult
     Dim cr As CompareResult = CompareResult.ciCompareOk
     If Not (bmp1.Size = bmp2.Size) Then
       cr = CompareResult.ciSizeMismatch
     Else
       Dim ic As System.Drawing.ImageConverter = New System.Drawing.ImageConverter
       Dim btImage1(1) As Byte
       btImage1 = CType(ic.ConvertTo(bmp1, btImage1.GetType), Byte())
       Dim btImage2(1) As Byte
       btImage2 = CType(ic.ConvertTo(bmp2, btImage2.GetType), Byte())
       Dim shaM As SHA256Managed = New SHA256Managed
       Dim hash1 As Byte() = shaM.ComputeHash(btImage1)
       Dim hash2 As Byte() = shaM.ComputeHash(btImage2)
       Dim i As Integer = 0
       While i < hash1.Length AndAlso i < hash2.Length AndAlso cr = CompareResult.ciCompareOk
         If Not (hash1(i) = hash2(i)) Then
           cr = CompareResult.ciPixelMismatch
         End If
         System.Math.Min(System.Threading.Interlocked.Increment(i),i-1)
       End While
     End If
     Return cr
   End Function
 End Class
End Namespace

I'm just the messenger.  It's code from http://www.codeproject.com/dotnet/comparingimages.asp translated to VB.NET on http://www.developerfusion.co.uk/utilities/convertcsharptovb.aspx

Roger

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
What version of .NET are you using?

Bob
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
Here is a reference for VB.NET 2003:

Manipulate multiple images' pixels very quickly using LockBits wrapped in a class in VB .NET
http://www.vb-helper.com/howto_net_lockbits_images_class.html

Bob

Author

Commented:

.NET 2005

I'll try it when I get a chance, unless you know it does not work in 2005...
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008
Commented:
In 2005, you can mix C# code within your VB.NET project.  You could include a class that has C# code, which with unsafe pointers can be significantly faster than VB code doing the same thing:

http://www.bobpowell.net/lockingbits.htm

Bob

Author

Commented:

Bob, I would like to try to mix in the C# approach to locking bits to compare the speed, but I'm not sure how to do that?  Is there a certain class attribute or something that causes a file to be interpreted as c#?

Author

Commented:

Okay, that helped a lot thanks.  I arrived at an unexpected spot, though... I took the cue that GetPixel is fundamentally slow (which, I suppose, is why locking it helps), and I wrote a ColorField class that scanned all needed data once into my own array, and then compared the arrays of respective color fields, rather than pixels from the bitmap object (I didn't mentiont this, but I tend to compare the same pictures again and again, so this helped a lot).  The unexpected thing is that (a) below was significantly faster than (b), so I ended up not using the LockBits at all, I just minimized my use of GetPixel.   But I'm much better off now, thanks for the help.

Bob, if you could still give me a link or something showing how to mix in C# code, that would be helpful...

**** (a)

        Private Sub GetData(ByVal i As Bitmap, ByVal r As Rectangle)

            Dim x As Integer, y As Integer, c As Color

            For x = 0 To r.Width - 1
            For y = 0 To r.Height - 1

                c = i.GetPixel(x + r.Left, y + r.Top)

                Red(x, y) = c.R
                Green(x, y) = c.G
                Blue(x, y) = c.B

            Next
            Next

        End Sub

***** (b)

        Private Sub GetData2(ByVal i As Bitmap, ByVal r As Rectangle)

            Dim x As Integer, y As Integer

            Dim bd As BitmapData
            bd = i.LockBits(r, ImageLockMode.ReadOnly, i.PixelFormat)

            For x = 0 To r.Width - 1
            For y = 0 To r.Height - 1

                Blue(x, y) = Marshal.ReadByte(bd.Scan0, (bd.Stride * y) + (4 * x))
                Green(x, y) = Marshal.ReadByte(bd.Scan0, (bd.Stride * y) + (4 * x) + 1)
                Red(x, y) = Marshal.ReadByte(bd.Scan0, (bd.Stride * y) + (4 * x) + 2)

            Next
            Next

            i.UnlockBits(bd)

        End Sub
CERTIFIED EXPERT
Most Valuable Expert 2012
Top Expert 2008

Commented:
Create a class, put in the C# code, and reference it from a VB.NET class/form.

Bob

Author

Commented:
To be clear, I should add (and reference) a C# class library project to my solution?  Or can I somehow include a C# class file directly in my VB.NET project?
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.