Categories: MSDN / DotNet / Java / Scripts / Linux / PHP Ask - La ask - La Answer

Image Comparison!

Hi All,
I have two questions.

1. Which ways is the best for comparing two JPG or BMP images?

2. Comparing two images without depending on Screen Resolution.
I also like to compare two images without depending on Screen Resolution.
Suppose: I capture one image in 1024 Resolutions( let's say "Image1.jpg")
And, I also capture another image in 800 resolutions ( "image2.jpg")
Then, I like to compare these two images and it should be the same.

Any Idea would be appreciated.

Thanks.
[548 byte] By [Sync] at [2007-11-11 8:07:29]
# 1 Re: Image Comparison!
Dim a As Picture
Dim b As Picture

''Browsing Image 1.
Private Sub Command1_Click()
With CommonDialog2
.ShowOpen
Text1 = .FileName
Set Picture1.Picture = LoadPicture(.FileName)
Set a = LoadPicture(.FileName)
End With
End Sub

''Browsing Image 2.
Private Sub Command2_Click()
With CommonDialog2
.ShowOpen
Text2 = .FileName
Set Picture2.Picture = LoadPicture(.FileName)
Set b = LoadPicture(.FileName)
End With
End Sub

''Comparing two images
Private Sub Command3_Click()
MsgBox a & " ::: " & b
MsgBox a = b
End Sub


Does anyone has any idea why a and b are different even both images ("image1 and image2") are the same?
- I'm sure that both images are the same because I depulicate those images by copying and pasting.
Sync at 2007-11-11 17:25:56 >
# 2 Re: Image Comparison!
I think these are different because of the handle of IPictureDisp. a and b have the default values of IPictureDisp.

* My1.JPG and My2.JPG are the same images.

Dim a As IPictureDisp
Dim b As IPictureDisp

Set a = LoadPicture("./My1.JPG")
Set b = LoadPicture("./My2.JPG")

Debug.Print _
a.Handle & " " & b.Handle & vbCrLf & _
a.Height & " " & b.Height & vbCrLf & _
a.hPal & " " & b.hPal & vbCrLf & _
a.Type & " " & b.Type & vbCrLf & _
a.Width & " " & b.Width & vbCrLf

Debug.Print "==============================="

MsgBox a = b


I have some more questions here..

Is there any ways to convert Picture to Bytes? Picture formats should be not only Bitmap but also other formats like JPG.

How to convert those bytes to Hash codes?

Thanks.
Sync at 2007-11-11 17:26:56 >
# 3 Re: Image Comparison!
I found one hash function from this article "Hashing a file with CryptoAPI" By Edonmo.

Hash.cls

Private Declare Function CryptAcquireContext Lib "advapi32.dll" _
Alias "CryptAcquireContextA" ( _
ByRef phProv As Long, _
ByVal pszContainer As String, _
ByVal pszProvider As String, _
ByVal dwProvType As Long, _
ByVal dwFlags As Long) As Long

Private Declare Function CryptReleaseContext Lib "advapi32.dll" ( _
ByVal hProv As Long, _
ByVal dwFlags As Long) As Long

Private Declare Function CryptCreateHash Lib "advapi32.dll" ( _
ByVal hProv As Long, _
ByVal Algid As Long, _
ByVal hKey As Long, _
ByVal dwFlags As Long, _
ByRef phHash As Long) As Long

Private Declare Function CryptDestroyHash Lib "advapi32.dll" ( _
ByVal hHash As Long) As Long

Private Declare Function CryptHashData Lib "advapi32.dll" ( _
ByVal hHash As Long, _
pbData As Byte, _
ByVal dwDataLen As Long, _
ByVal dwFlags As Long) As Long

Private Declare Function CryptGetHashParam Lib "advapi32.dll" ( _
ByVal hHash As Long, _
ByVal dwParam As Long, _
pbData As Any, _
pdwDataLen As Long, _
ByVal dwFlags As Long) As Long

Private Const PROV_RSA_FULL = 1

Private Const CRYPT_NEWKEYSET = &H8

Private Const ALG_CLASS_HASH = 32768

Private Const ALG_TYPE_ANY = 0

Private Const ALG_SID_MD2 = 1
Private Const ALG_SID_MD4 = 2
Private Const ALG_SID_MD5 = 3
Private Const ALG_SID_SHA1 = 4

Enum HashAlgorithm
MD2 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD2
MD4 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD4
MD5 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_MD5
SHA1 = ALG_CLASS_HASH Or ALG_TYPE_ANY Or ALG_SID_SHA1
End Enum

Private Const HP_HASHVAL = 2
Private Const HP_HASHSIZE = 4

Function HashFile( _
ByVal Filename As String, _
Optional ByVal Algorithm As HashAlgorithm = MD5) As String
Dim hCtx As Long
Dim hHash As Long
Dim lFile As Long
Dim lRes As Long
Dim lLen As Long
Dim lIdx As Long
Dim abHash() As Byte

' Check if the file exists (not the best method BTW!)
If Len(Dir$(Filename)) = 0 Then Err.Raise 53

' Get default provider context handle
lRes = CryptAcquireContext(hCtx, vbNullString, _
vbNullString, PROV_RSA_FULL, 0)

If lRes = 0 And Err.LastDllError = &H80090016 Then

' There's no default keyset container!!!
' Get the provider context and create
' a default keyset container
lRes = CryptAcquireContext(hCtx, vbNullString, _
vbNullString, PROV_RSA_FULL, CRYPT_NEWKEYSET)
End If

If lRes <> 0 Then

' Create the hash
lRes = CryptCreateHash(hCtx, Algorithm, 0, 0, hHash)

If lRes <> 0 Then

' Get a file handle
lFile = FreeFile

' Open the file
Open Filename For Binary As lFile

If Err.Number = 0 Then

Const BLOCK_SIZE As Long = 32 * 1024& ' 32K
ReDim abBlock(1 To BLOCK_SIZE) As Byte
Dim lCount As Long
Dim lBlocks As Long
Dim lLastBlock As Long

' Calculate how many full blocks
' the file contains
lBlocks = LOF(lFile) \ BLOCK_SIZE

' Calculate the remaining data length
lLastBlock = LOF(lFile) - lBlocks * BLOCK_SIZE

' Hash the blocks
For lCount = 1 To lBlocks

Get lFile, , abBlock

' Add the chunk to the hash
lRes = CryptHashData(hHash, abBlock(1), BLOCK_SIZE, 0)

' Stop the loop if CryptHashData fails
If lRes = 0 Then Exit For

Next

' Is there more data?
If lLastBlock > 0 And lRes <> 0 Then

' Get the last block
ReDim abBlock(1 To lLastBlock) As Byte
Get lFile, , abBlock

' Hash the last block
lRes = CryptHashData(hHash, abBlock(1), lLastBlock, 0)

End If

' Close the file
Close lFile

End If

If lRes <> 0 Then

' Get the hash lenght
lRes = CryptGetHashParam(hHash, HP_HASHSIZE, lLen, 4, 0)

If lRes <> 0 Then

' Initialize the buffer
ReDim abHash(0 To lLen - 1)

' Get the hash value
lRes = CryptGetHashParam(hHash, HP_HASHVAL, abHash(0), lLen, 0)

If lRes <> 0 Then

' Convert value to hex string
For lIdx = 0 To UBound(abHash)
HashFile = HashFile & _
Right$("0" & Hex$(abHash(lIdx)), 2)
Next

End If

End If

End If

' Release the hash handle
CryptDestroyHash hHash

End If

End If

' Release the provider context
CryptReleaseContext hCtx, 0

' Raise an error if lRes = 0
If lRes = 0 Then Err.Raise Err.LastDllError

End Function


Form1.frm

Dim str1 As String
Dim str2 As String

''Browsing Image2
Private Sub Command1_Click()
With CommonDialog2
.ShowOpen
Dim h1 As New Hash
str2 = h1.HashFile(.FileName, MD5)
Set h1 = Nothing
End With
End Sub

''Browsing Image1
Private Sub Command2_Click()
With CommonDialog2
.ShowOpen
Dim h2 As New Hash
str1 = h2.HashFile(.FileName, MD5)
Set h2 = Nothing
End With
End Sub

''Let's compare
Private Sub Command3_Click()
MsgBox str1 & vbCrLf & str2
MsgBox str1 = str2
End Sub


I like to hear any suggestion from everybody..
Is this good methods for comparing images?

One questions is ~
How to highlight the differents between two images? I like to display which part of images are different? as like File Comparor did.

Thanks in advances.
Sync at 2007-11-11 17:28:02 >
# 4 Re: Image Comparison!
this is a question for image processing, more than VB programming.
there is no really A way to compare images, there are many ways.

Two images are the same if their size (width and height) is the same and all the pixels have the same color. but maybe they are the same, just slightly rotated. or one is just darker.
It really depends on which kind of images you are working with, and kind of "similitude" are you looking for.

Marco
mstraf at 2007-11-11 17:28:56 >
# 5 Re: Image Comparison!
Thank you. Which type of image are good enough for image comparison? I think the size of BMP is good big. and GIF is not good enough for image comparison. maybe JPG is the best format for image comparison. What about png? What do you say?
Sync at 2007-11-11 17:29:57 >
# 6 Re: Image Comparison!
what does the format of the image have to do with the comparison? after reading and uncompressing the image into memory, regardless on the file format the image is stored in the pixel byte array.
Again, the most important thing to consider is "which kind of comparison we need". Pixel by pixel? pixel by pixel but with scale/rotation? pixel by pixel with distortion? Other type of comparison that are "features" based instead of pixel based?

Marco
mstraf at 2007-11-11 17:31:07 >
# 7 Re: Image Comparison!
Thank you. mstraf

the most important thing to consider is "which kind of comparison we need"

Could you please suggest me which one is the best for comparison?
Actually, I don't have so much idea about Image Processing. (If possible, could you please give me some useful links for img processing?). I'm thinking that we will load two images into memory. and we will compare these images by comparing byte by byte or bit by bit. But i'm afarid that it might take too long and maybe not good method for image comparison..

How can I convert StdPicture into Bytes?
Sync at 2007-11-11 17:31:59 >
# 8 Re: Image Comparison!
hi all
i am also facing the same problem but by the discussion so far i dont find a clear cut solution as to how two images are being compared pixel by pixel.
explain with code plzz.
aks79 at 2007-11-11 17:33:10 >
# 9 Re: Image Comparison!
I found the following articles by markrouse. Unfortunely, it's written in C#.
Comparing Images using GDI+ (C#)
http://www.codeproject.com/dotnet/comparingimages.asp

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Security.Cryptography;

namespace Imagio
{
public class ComparingImages
{
public enum CompareResult
{
ciCompareOk,
ciPixelMismatch,
ciSizeMismatch
};

public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
CompareResult cr = CompareResult.ciCompareOk;

//Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
cr = CompareResult.ciSizeMismatch;
}
else
{
//Convert each image to a byte array
System.Drawing.ImageConverter ic =
new System.Drawing.ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

//Compute a hash for each image
SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);

//Compare the hash values
for (int i = 0; i < hash1.Length && i < hash2.Length
&& cr == CompareResult.ciCompareOk; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.ciPixelMismatch;
}
}
return cr;
}
}
}


More questions ~
1. Is it possible to use StdPicture in VB6 instead of using Bitmap (.NET)?
2. How can I know the size of StdPicture? ( bmp1.Size )
3. What is the equalvalent function( Vb6) for ImageConverter (c#)?

Thanks.
Sync at 2007-11-11 17:34:07 >
# 10 Re: Image Comparison!
size of the picture can by easily calculated if u somehow move the picture into an image list control
aks79 at 2007-11-11 17:35:07 >
# 11 Re: Image Comparison!
Thank you. Aks79.
Both of us have this problem. So, we will try to find the solution by sharing our ideas. As I said in thread #4, I did image files comparison by using Hash Class. But I'll change the way if I found better solution..
I also wanna do the image comparison without depending on Color Depth and Screen Resolution. Our group have the problem in comparing image if our standard color depth and resoluction aren't matched with the end user monitor.
Other thing that i wanna do is that I can find the different between two images and point it out to know the user clearly..

size of the picture can by easily calculated if u somehow move the picture into an image list control

I was thinking that it would be gr8 if I can load the image file in the memory like Stream in .NET. Otherwise, I don't wanna use any control.
Sync at 2007-11-11 17:36:06 >
# 12 Re: Image Comparison!
hi michael yes i am also working on the same problem but dont have concrete ideas as such i will share what i think
since i put my images into and out of the database as byte array so what i am planning to do is compare these byte array not for all but at randomly selected postions which most probably will come up with the correct result as well it wont make the process of comaparision a burden on the system
aks79 at 2007-11-11 17:37:06 >
# 13 Re: Image Comparison!
sorry i should have put in the following in my last post
also that as soon as a difference is found out it breaks out of the byte comparison loop and turning on a flag signalling that yes the picture has changed
aks79 at 2007-11-11 17:38:12 >
# 14 Re: Image Comparison!
As I'm working on automation tool, I think i have to ensure both images are the same by comparing all bytes until the program detect any different.
Sync at 2007-11-11 17:39:06 >
# 15 Re: Image Comparison!
i am also working on industrialization and automation softwares
but i would suggest u to convert these images into byte array before comparision bcoz that way ur image becomes independent on resolution and other stuff u mentioned above
and even if u compare the images for say 50 percent of the locations and if they turn out to be true u can be more than 95 percent sure of these images being similar.
if u want to know how to convert images into byte streams i can help u out
aks79 at 2007-11-11 17:40:10 >
# 16 Re: Image Comparison!
if u want to know how to convert images into byte streams i can help u out

Yeah. Please. Thank you so much.
Sync at 2007-11-11 17:41:11 >
# 17 Re: Image Comparison!
i would suggest u to convert these images into byte array before comparision

Yeah.. I like to do like this but I dont know how to convert StdPicture into Byte Array.
If you have it, please share with me.
I do appreciated for it. Thanks.
Sync at 2007-11-11 17:42:19 >
# 18 Re: Image Comparison!
if u have msdn just go and type this string
"store images in your database" include the quotes also u will get an interesting article
it will also show u how to write the get and set methods
aks79 at 2007-11-11 17:43:12 >
# 19 Re: Image Comparison!
i am using dao as connection but u can find the ado one in the msdn link i gave
aks79 at 2007-11-11 17:44:21 >
# 20 Re: Image Comparison!
did it serve ur purpose??
aks79 at 2007-11-11 17:45:12 >
# 21 Re: Image Comparison!
did it serve ur purpose??
I'm still doing... I'm trying to read some articles abt image processing..
Thnks..
Sync at 2007-11-11 17:46:20 >
# 22 Re: Image Comparison!
Here are two image compare apps that use different API calls.
Keithuk at 2007-11-11 17:47:19 >
# 23 Re: Image Comparison!
few ideas:
load the image into a stdPicture object, this for example loads from file:

Dim X As New StdPicture
Set X = LoadPicture("c:\windows\circles.bmp")

then you can use the width and height properties to get the image size (they are in hiMetric, you need to convert them to pixels)
you can use the Handle property and few APIs (like GetDibPixels) to get the image array IF the image was stored as a bitmap (the type property of the stdPicture must be vbPicTypeBitmap)

After you get the image byte array, you can start a pixel by pixel comparison if the size of the images is the same, otherwise you can "scale" the larger one. But be careful: expecially if you scale the image, pixels can be "slightly" different... so maybe you want to set a "threshold" to mark how much the pixels are are same. For example, if the pixel value of the two images are (r1,g1,b1) and (r2,g2,b2), you can do something like:

abs(r1-r2) <= thr and abs(g1-g2) <= thr and abs(b1-b2) <= thr then <<<< are the same!

where thr is you threshold (if zero, then pixels must match)

if this is what you want, use MSDN to get more information, there are also examples there.
mstraf at 2007-11-11 17:48:19 >
# 24 Re: Image Comparison!
Thank you.. Keithuk, mstraf and aks79.
Actually, I was so busy with my tool lately... I can't even come to this forum... Sorry..

I do appreciate for your suggestion, coding and helps...Thanks.

I also got it.. :)
I used one class called cDIBSection from www.vbaccelerator.com. Special Thanks to Steve.

Here is coding.
Firstly, you browse two images which you like to compare.
Then click Command3, the different image will be shown in Picture3. (same bits will be shown in white color. and different bit will be shown in black color.)
So, you can easily find the differences between those images.

Note: Put three buttons and three pictureboxes on the form."from1"

Form1.frm

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

Private Type SAFEARRAYBOUND
cElements As Long
lLbound As Long
End Type
Private Type SAFEARRAY2D
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
Bounds(0 To 1) As SAFEARRAYBOUND
End Type
Private Declare Function VarPtrArray Lib "msvbvm50.dll" Alias "VarPtr" (Ptr() As Any) As Long

Private Sub Command1_Click()
With CommonDialog1
.ShowOpen
If Not .CancelError Then
Set Picture1.Picture = LoadPicture(.FileName)
End If
End With
End Sub
Private Sub Command2_Click()
With CommonDialog1
.ShowOpen
If Not .CancelError Then
Set Picture2.Picture = LoadPicture(.FileName)
End If
End With
End Sub

Private Sub Command3_Click()
''Left Image.
Dim oDIBSection1 As New cDIBSection
oDIBSection1.CreateFromPicture Picture1
''Right Image.
Dim oDIBSection2 As New cDIBSection
oDIBSection2.CreateFromPicture Picture2

If oDIBSection1.DIBitmap.bmiColors.rgbBlue <> oDIBSection2.DIBitmap.bmiColors.rgbBlue Then
MsgBox oDIBSection1.DIBitmap.bmiColors.rgbBlue & " <> " & oDIBSection2.DIBitmap.bmiColors.rgbBlue
Exit Sub
End If
If oDIBSection1.DIBitmap.bmiColors.rgbGreen <> oDIBSection2.DIBitmap.bmiColors.rgbGreen Then
MsgBox oDIBSection1.DIBitmap.bmiColors.rgbGreen & " <> " & oDIBSection2.DIBitmap.bmiColors.rgbGreen
Exit Sub
End If
If oDIBSection1.DIBitmap.bmiColors.rgbRed <> oDIBSection2.DIBitmap.bmiColors.rgbRed Then
MsgBox oDIBSection1.DIBitmap.bmiColors.rgbRed & " <> " & oDIBSection2.DIBitmap.bmiColors.rgbRed
Exit Sub
End If
If oDIBSection1.DIBitmap.bmiColors.rgbReserved <> oDIBSection2.DIBitmap.bmiColors.rgbReserved Then
MsgBox oDIBSection1.DIBitmap.bmiColors.rgbReserved & " <> " & oDIBSection2.DIBitmap.bmiColors.rgbReserved
Exit Sub
End If

If oDIBSection1.DIBitmap.bmiHeader.biHeight <> oDIBSection2.DIBitmap.bmiHeader.biHeight Then
MsgBox oDIBSection1.DIBitmap.bmiHeader.biHeight & " <> " & oDIBSection2.DIBitmap.bmiHeader.biHeight
Exit Sub
End If

If oDIBSection1.DIBitmap.bmiHeader.biWidth <> oDIBSection2.DIBitmap.bmiHeader.biWidth Then
MsgBox oDIBSection1.DIBitmap.bmiHeader.biWidth & " <> " & oDIBSection2.DIBitmap.bmiHeader.biWidth
Exit Sub
End If

If oDIBSection1.DIBitmap.bmiHeader.biSize <> oDIBSection2.DIBitmap.bmiHeader.biSize Then
MsgBox oDIBSection1.DIBitmap.bmiHeader.biSize & " <> " & oDIBSection2.DIBitmap.bmiHeader.biSize
Exit Sub
End If

If oDIBSection1.DIBitmap.bmiHeader.biSizeImage <> oDIBSection2.DIBitmap.bmiHeader.biSizeImage Then
MsgBox oDIBSection1.DIBitmap.bmiHeader.biSizeImage & " <> " & oDIBSection2.DIBitmap.bmiHeader.biSizeImage
Exit Sub
End If

Dim tSA1 As SAFEARRAY2D
Dim bDib1() As Byte
With tSA1
.cbElements = 1
.cDims = 2
.Bounds(0).cElements = oDIBSection1.Height
.Bounds(0).lLbound = 0
.Bounds(1).cElements = oDIBSection1.BytesPerScanLine
.Bounds(1).lLbound = 0
.pvData = oDIBSection1.DIBSectionBitsPtr
End With
CopyMemory ByVal VarPtrArray(bDib1()), VarPtr(tSA1), 4

Dim tSA2 As SAFEARRAY2D
Dim bDib2() As Byte
With tSA2
.cbElements = 1
.cDims = 2
.Bounds(0).cElements = oDIBSection2.Height
.Bounds(0).lLbound = 0
.Bounds(1).cElements = oDIBSection2.BytesPerScanLine
.Bounds(1).lLbound = 0
.pvData = oDIBSection2.DIBSectionBitsPtr
End With
CopyMemory ByVal VarPtrArray(bDib2()), VarPtr(tSA2), 4

Dim x As Long
Dim y As Long
Dim xEnd As Long
Dim yEnd As Long

xEnd = oDIBSection2.BytesPerScanLine() - 3
yEnd = oDIBSection1.Height - 1

For x = 0 To xEnd Step 3
For y = 0 To yEnd
If bDib1(x, y) <> bDib2(x, y) Then
bDib2(x, y) = 0
bDib2(x + 1, y) = 0
bDib2(x + 2, y) = 0
Else
bDib2(x, y) = 255
bDib2(x + 1, y) = 255
bDib2(x + 2, y) = 255
End If
Next y
Next x

''Clear
CopyMemory ByVal VarPtrArray(bDib1()), 0&, 4
CopyMemory ByVal VarPtrArray(bDib2()), 0&, 4

oDIBSection2.PaintPicture Picture3.HDC
MsgBox "Done"

Set oDIBSection1 = Nothing
Set oDIBSection2 = Nothing

End Sub


Thanks to vbAccelerator.com (Steve)
cDIBSection.cls

Sorry! I can't post it here.. goto vbaccelerator.com and download this class.
1. The text that you have entered is too long (29493 characters). Please shorten it to 10000 characters long.

Hi, Free feel to let me know if you found any issue...
Sync at 2007-11-11 17:49:18 >
# 25 Re: Image Comparison!
Hi aks79,
How's your project going?
Can you PM me ur email id? in case, we need to discuss about image processing. :)
Sync at 2007-11-11 17:50:20 >