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
riceman0Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

riceman0Author 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.
0
SanclerCommented:
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
0
Bob LearnedCommented:
What version of .NET are you using?

Bob
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

Bob LearnedCommented:
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
0
riceman0Author Commented:

.NET 2005

I'll try it when I get a chance, unless you know it does not work in 2005...
0
Bob LearnedCommented:
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

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
riceman0Author 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#?
0
riceman0Author 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
0
Bob LearnedCommented:
Create a class, put in the C# code, and reference it from a VB.NET class/form.

Bob
0
riceman0Author 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?
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.