Page 1 of 1

Comparing images in database Inserting only unique images in your database

#1 FlashM  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 382
  • View blog
  • Posts: 1,195
  • Joined: 03-December 09

Post icon  Posted 29 December 2009 - 01:50 PM

I wrote this tutorial mainly because I helped some member on this forum who needed this solution and since I wrote almost complete solution, I decided to post it here, so other members will be able to reference it if needed. In this tutorial we are going to focus on how to verify if exactly the same image already exists in your database. As you know it is possible to store images in database as binary data and this approach we are going to use in our example.

Steps we are going to take are the following. We are going to take an image that we want to store in our database. Then the image will be converted into an array of bytes. Now here's the most important step. Before storing it into database, we are going to compute a hash code/digest using a cryptographic hash function already built into .NET (this ensures us that no image will give the same hash code when encrypted with this sort of algorithm). Same principal is also used for storing passwords in database since it is "impossible" to decode this hash digest. When the hash code is computed, we are going to compare it to hash codes stored in database. If we find that this hash code already exists in our database we know this same image has been also previously stored in database.

As database provider I used PostgreSQL database, but you can use any other. In my database I created a table named "images" with three columns as follows:

ID [bigserial NOT NULL]
HASH [character varying(255)]
IMAGE [bytea] //data type that can store an array of bytes

First, create a Windows Forms Application and add a button named btnSaveImage. Navigate to your form's code designer and before the Form's constructor add these global variables:

private NpgsqlConnection conn = null;  //PostgreSQL connection object
private ImageConverter converter = null;  //Image converter object
private SHA256Managed shaEncryptor = null;  //Sha algorithm encryptor object



Do not forget to code using statement for System.Security.Cryptography at the top of Form1.cs file.

Then I created a private method InitCustomComponents which is used to initialize our globally declared variables. This method is called in form's constructor just after InitializeComponent method.

private void InitCustomComponents()
{
	shaEncryptor = new SHA256Managed();  //initialize encryptor
	converter = new ImageConverter();  //initialize image converter
	conn = new NpgsqlConnection  //initialize connection string
		(@"Server=127.0.0.1;Port=5432;Database=imagesdb;User Id=YourUserId;Password=YourPassword;");
}



Then I created the InsertRecord method that accepts image's bytes array and a hash string argument.

private void InsertRecord(byte[] imgBytes, string hash)
{
	NpgsqlCommand cmd = new NpgsqlCommand();
	cmd.Connection = conn;
	cmd.CommandText = "INSERT INTO images (image, hash) VALUES(@image, @hash)";
	cmd.Parameters.Add("image", imgBytes);
	cmd.Parameters.Add("hash", hash);

	conn.Open();
	cmd.ExecuteNonQuery();
	conn.Close();
}



The next method we need is ComputeHashCode method that computes an array of bytes of image into a short hash string representation. Computed hash code is also an array of bytes, that's why I converted it into a string before returning this value to the caller.

private string ComputeHashCode(byte[] imgBytes)
{
	//Compute hash bytes
	byte[] hash = shaEncryptor.ComputeHash(imgBytes);

	//Convert hash bytes to string representation
	return Convert.ToBase64String(hash);
}



Another method we need is HashExists method. This method accepts a hash string argument and is used to query the database whether this has exists or not.

private bool HashExists(string hash)
{
	NpgsqlCommand cmd = new NpgsqlCommand();
	cmd.Connection = conn;
	cmd.CommandText = "SELECT hash from images where hash = @hash";
	cmd.Parameters.Add("hash", hash);

	conn.Open();

	//Execute scalar returns the first column of the first row in the result set
	string hashString = (string)cmd.ExecuteScalar();
	conn.Close();

	return (hashString != null);
}



The last method is the button's click event that is used to trigger the comparing and saving process.

private void btnSaveImage_Click(object sender, EventArgs e)
{
	//get some image from file system to store it in DB
	Bitmap image = new Bitmap(@"C:\Temp\progress.gif");

	//initialize byte array variable
	byte[] imgBytes = new byte[0];

	//convert image to byte array
	imgBytes = (byte[])converter.ConvertTo(image, imgBytes.GetType());

	//compute SHA hash string from image bytes
	string hash = ComputeHashCode(imgBytes);

	//if computed hash already exists in DB, do nothing
	if (HashExists(hash)) return;

	//Guess this has doesn't exist in DB - lets store this image to DB
	InsertRecord(imgBytes, hash);
}




I added another function just to show you how to retrieve an image that was stored as binary data and convert it back to an image:

private void GetImage(int recordIdx)
{
	NpgsqlCommand cmd = new NpgsqlCommand();
	cmd.Connection = conn;
	cmd.CommandText = "SELECT image FROM images WHERE id = @id";
	cmd.Parameters.Add("id", recordIdx);

	conn.Open();
	byte[] imgBytes = (byte[])cmd.ExecuteScalar();
	conn.Close();


	Bitmap image = new Bitmap(new System.IO.MemoryStream(imgBytes));
	pbMyPictureBox.Image = image;
}





The complete code looks like this:

using System;
using System.Drawing;
using System.Security.Cryptography;
using System.Windows.Forms;
using Npgsql;


namespace ImageHash
{
	public partial class Form1 : Form
	{
		private NpgsqlConnection conn = null;  //PostgreSQL connection object
		private ImageConverter converter = null;  //Image converter object
		private SHA256Managed shaEncryptor = null;  //Sha algorithm encryptor object

		public Form1()
		{
			InitializeComponent();
			InitCustomComponents();
		}

		private void InitCustomComponents()
		{
			shaEncryptor = new SHA256Managed();  //initialize encryptor
			converter = new ImageConverter();  //initialize image converter
			conn = new NpgsqlConnection  //initialize connection string
				(@"Server=127.0.0.1;Port=5432;Database=imagesdb;User Id=YourUserId;Password=YourPassword;");
		}

		private void btnSaveImage_Click(object sender, EventArgs e)
		{
			//get some image from file system to store it in DB
			Bitmap image = new Bitmap(@"C:\Temp\progress.gif");

			//initialize byte array variable
			byte[] imgBytes = new byte[0];

			//convert image to byte array
			imgBytes = (byte[])converter.ConvertTo(image, imgBytes.GetType());

			//compute SHA hash string from image bytes
			string hash = ComputeHashCode(imgBytes);

			//if computed hash already exists in DB, do nothing
			if (HashExists(hash)) return;

			//Guess this has doesn't exist in DB - lets store this image to DB
			InsertRecord(imgBytes, hash);
		}

		private void InsertRecord(byte[] imgBytes, string hash)
		{
			NpgsqlCommand cmd = new NpgsqlCommand();
			cmd.Connection = conn;
			cmd.CommandText = "INSERT INTO images (image, hash) VALUES(@image, @hash)";
			cmd.Parameters.Add("image", imgBytes);
			cmd.Parameters.Add("hash", hash);

			conn.Open();
			cmd.ExecuteNonQuery();
			conn.Close();
		}

		private string ComputeHashCode(byte[] imgBytes)
		{
			//Compute hash bytes
			byte[] hash = shaEncryptor.ComputeHash(imgBytes);

			//Convert hash bytes to string representation
			return Convert.ToBase64String(hash);
		}

		private bool HashExists(string hash)
		{
			NpgsqlCommand cmd = new NpgsqlCommand();
			cmd.Connection = conn;
			cmd.CommandText = "SELECT hash from images where hash = @hash";
			cmd.Parameters.Add("hash", hash);

			conn.Open();

			//Execute scalar returns the first column of the first row in the result set
			string hashString = (string)cmd.ExecuteScalar();
			conn.Close();

			return (hashString != null);
		}

		private void GetImage(int recordIdx)
		{
			NpgsqlCommand cmd = new NpgsqlCommand();
			cmd.Connection = conn;
			cmd.CommandText = "SELECT image FROM images WHERE id = @id";
			cmd.Parameters.Add("id", recordIdx);

			conn.Open();
			byte[] imgBytes = (byte[])cmd.ExecuteScalar();
			conn.Close();


			Bitmap image = new Bitmap(new System.IO.MemoryStream(imgBytes));
			pbMyPictureBox.Image = image;
		}
	}
}



I hope you liked the tutorial, feel free to ask if anything unclear or if any additional information needed.

Is This A Good Question/Topic? 1
  • +

Replies To: Comparing images in database

#2 Guest_Jp*


Reputation:

Posted 10 February 2010 - 04:11 PM

Can you let me know where can i download the complete project?
Was This Post Helpful? 0

#3 Guest_C Botha*


Reputation:

Posted 23 August 2010 - 03:45 AM

Thanks a mil
Was This Post Helpful? 0

Page 1 of 1