Como bien lo han comentado ya, comparando pixel por pixel se puede saber si dos imágenes son distintas. Lo sé porque yo mismo tenía un método que hacía esto. Sin embargo, no estaba conforme con el mismo, pues cuando comparaba imágenes grandes, o de alta resolución, el método tardaba demasiado. Por tal motivo, me puse a indagar por la web, y encontré dos formas más de hacerlo, ambas mucho más rápidas que comparando pixel por pixel. En ambos casos se hace lo mismo, pero por medios distintos: crear un array de bytes de cada imagen, y luego comparar cada array.
En el primer caso se usa el método Image.Save(Stream, ImageFormat) para guardar la imagen en un espacio de la memoria, el cual luego se transforma en un array de bytes usando el método ToArray del objeto Stream. No obstante, al final decidí no usar esté método, sino el otro que conseguí.
Esta otra técnica, se vale del método Marshal.Copy, que en esencia hace lo mismo que el método Image.Save ya mencionado antes, pero con más rapidez (no me pregunten por qué; tal vez los más experimentados puedan emitir su opinión), aunque extrañamente me parece que hace un trabajo mayor. Como sea, aquí les dejo el código que tengo.
'Método función para convertir la imagen en un array de BytesPublicSharedFunction ImageToArray(ByVal img As Bitmap) AsByte()'Variable que retornará el array de bytesDim result(0) AsByte'Uso un clon de la imagen recibida en el parámetro img.'Esto para evitar errores al usar diferentes ThreadsUsing tmpImg AsNew Bitmap(img)'Obtengo la data de la imagenDim imgData As BitmapData = _ tmpImg.LockBits(New Rectangle(0, 0, tmpImg.Width, tmpImg.Height), _ ImageLockMode.ReadOnly, tmpImg.PixelFormat)'Reajusto el tamaño de la variable array según la data de la imagen Array.Resize(result, imgData.Stride * tmpImg.Height)'Empleo el método Copy de la clase Marshal para copiar la imagen en'la memoria y asignar su array de Bytes a la variable result Marshal.Copy(imgData.Scan0, result, 0, result.Length)EndUsing'Devuelvo el array de BytesReturn resultEndFunction'Método función que compara dos imágenesPublicSharedFunction ImageComparator(ByVal imgA As Bitmap, _ByVal imgB As Bitmap) AsBoolean'Evalúo si las dos o alguna de las imágenes son Nothing, 'y retorno un valor dependiendo de elloIf imgA IsNothingAnd imgB IsNothingThenReturnTrueIf imgA IsNothingAnd imgB IsNotNothingThenReturnFalseIf imgA IsNotNothingAnd imgB IsNothingThenReturnFalse'Clono ambas imágenes recibidas en los parámetros, también para'evitar errores al usar un Thread diferenteUsing tmpImgA AsNew Bitmap(imgA), tmpImgB AsNew Bitmap(imgB)'Si el tamaño o los flags no coinsiden, retorno False sin'necesidad de comparar la data de las imágenesIf tmpImgA.Size <> tmpImgB.Size ThenReturnFalseIf tmpImgA.Flags <> tmpImgB.Flags ThenReturnFalse'En caso de que el tamaño y los flags sean los mismos,'procedo a obtener y comparar los array de BytesDim iaArray() AsByte = ImageToArray(tmpImgA)Dim ibArray() AsByte = ImageToArray(tmpImgB)For ca AsInteger = 0 To iaArray.Count - 1'Apenas un valor sea distino del otro, retorno FalseIf iaArray(ca) <> ibArray(ca) ThenReturnFalseNextEndUsing'Si la ejecución del código llega hasta este punto, solo'significa que son las mismas imágenes; retorno TrueReturnTrueEndFunction
Como verán, empleo dos métodos para efectuar la comparación. Me pareció más adecuado tener un método para cada cosa (comparar imágenes, obtener array de Bytes), aunque el método para obtener el array de Bytes también sirve para cuando necesitemos guardar una imagen en una base de datos.
También habrán notado que ambos métodos son Shared; esto se debe a que los tengo dentro de una clase creada especialmente para el tratamiento de imágenes.
De verdad recomiendo altamente el uso de esta técnica para la comparación de imágenes, pues como mencioné, ya he pasado por varias, y esta es la que mejor resulta. Pueden hacer sus propias pruebas, si quieren, y verán que es cierto. Usen la comparación pixel por pixel para comparar dos imágenes grandes, y luego usen este método. Verán claramente la diferencia.
Saludos.
Olvidé mencionar que es necesario importar las siguientes librerías al inicio:
Imports System.Drawing.Imaging 'Para BitmapDataImports System.Runtime.InteropServices 'Para Marshal
Cualquier duda no dejen de preguntar. ;)
Aquel que pregunta es un tonto por cinco minutos, pero el que no pregunta permanece tonto por siempre
Proverbio chino