Link to home
Start Free TrialLog in
Avatar of riceman0
riceman0

asked on

Can this bitmap compare be speed-tweaked?


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
Avatar of riceman0
riceman0

ASKER


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.
SOLUTION
Avatar of Sancler
Sancler

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Bob Learned
What version of .NET are you using?

Bob
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

.NET 2005

I'll try it when I get a chance, unless you know it does not work in 2005...
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

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#?

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
Create a class, put in the C# code, and reference it from a VB.NET class/form.

Bob
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?