• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 447
  • Last Modified:

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
0
riceman0
Asked:
riceman0
  • 5
  • 4
2 Solutions
 
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

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

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now