Question

What would be the best method to compare 2 bitmaps and get the correlation between the 2 (0 being completely different and 1 being exactly the same) in Unity3d on the iPhone? I am using C# since documentation says that using Boo or UnityScript will increase the size of the application.

What I need is something similar to the fingerprint identification methods but not as accurate. Since this is intended to run on the iPhone performance is a big issue here.

Example images:

alt text http://img25.imageshack.us/img25/303/294906.jpg alt text http://img138.imageshack.us/img138/842/40248741fireworkexplosi.jpg

For those I would expect to have a correlation factor of about 0.5 since they are similar but differ in color. There are a number of different dimensions of comparison, but the basic ones are color and shape.

Any help will be greatly appreciated.

Was it helpful?

Solution

To answer (sort of) my own question, after days of googling, I found this. The basic idea is to test for images with offset/rotation, the search for a dominant color and so on. So far this is the best information I could find, so I will give it a try.

The code suggested there looks like this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace BitmapSimilarity
{
    public interface IBitmapCompare
    {
        double GetSimilarity(Bitmap a, Bitmap b);
    }

    class BitmapCompare: IBitmapCompare
    {
        public struct RGBdata
        {
            public int r;
            public int g;
            public int b;

            public int GetLargest()
            {
                if(r>b)
                {
                    if(r>g)
                    {
                        return 1;
                    }
                    else
                    {
                        return 2;
                    }
                }
                else
                {
                    return 3;
                }
            }
        }

        private RGBdata ProcessBitmap(Bitmap a)
        {
            BitmapData bmpData = a.LockBits(new Rectangle(0,0,a.Width,a.Height),ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);
            IntPtr ptr = bmpData.Scan0;
            RGBdata data = new RGBdata();

            unsafe
            {
                byte* p = (byte*)(void*)ptr;
                int offset = bmpData.Stride - a.Width * 3;
                int width = a.Width * 3;

                for (int y = 0; y < a.Height; ++y)
                {
                    for (int x = 0; x < width; ++x)
                    {
                        data.r += p[0];             //gets red values
                        data.g += p[1];             //gets green values
                        data.b += p[2];             //gets blue values
                        ++p;
                    }
                    p += offset;
                }
            }
            a.UnlockBits(bmpData);
            return data;
        }

        public double GetSimilarity(Bitmap a, Bitmap b)
        {
            RGBdata dataA = ProcessBitmap(a);
            RGBdata dataB = ProcessBitmap(b);
            double result = 0;
            int averageA = 0;
            int averageB = 0;
            int maxA = 0;
            int maxB = 0;

            maxA = ((a.Width * 3) * a.Height);
            maxB = ((b.Width * 3) * b.Height);

            switch (dataA.GetLargest())            //Find dominant color to compare
            {
                case 1:
                    {
                        averageA = Math.Abs(dataA.r / maxA);
                        averageB = Math.Abs(dataB.r / maxB);
                        result = (averageA - averageB) / 2;
                        break;
                    }
                case 2:
                    {
                        averageA = Math.Abs(dataA.g / maxA);
                        averageB = Math.Abs(dataB.g / maxB);
                        result = (averageA - averageB) / 2;
                        break;
                    }
                case 3:
                    {
                        averageA = Math.Abs(dataA.b / maxA);
                        averageB = Math.Abs(dataB.b / maxB);
                        result = (averageA - averageB) / 2;
                        break;
                    }
            }

            result = Math.Abs((result + 100) / 100);

            if (result > 1.0)
            {
                result -= 1.0;
            }

            return result;
        }
    }

    class Program
    {
        static BitmapCompare SimpleCompare;
        static Bitmap searchImage;

        static private void Line()
        {
            for (int x = 0; x < Console.BufferWidth; x++)
            {
                Console.Write("*");
            }
        }

        static void CheckDirectory(string directory,double percentage,Bitmap sImage)
        {
            DirectoryInfo dir = new DirectoryInfo(directory);
            FileInfo[] files = null;
            try
            {
                files = dir.GetFiles("*.jpg");
            }
            catch (DirectoryNotFoundException)
            {
                Console.WriteLine("Bad directory specified");
                return;
            }

            double sim = 0;

            foreach (FileInfo f in files)
            {
                sim = Math.Round(SimpleCompare.GetSimilarity(sImage, new Bitmap(f.FullName)),3);
                if (sim >= percentage)
                {
                    Console.WriteLine(f.Name);
                    Console.WriteLine("Match of: {0}", sim);
                    Line(); 
                }
            }
        }

        static void Main(string[] args)
        {
            SimpleCompare = new BitmapCompare();
            Console.Write("Enter path to search image: ");
            try
            {
                searchImage = new Bitmap(Console.ReadLine());
            }
            catch (ArgumentException)
            {
                Console.WriteLine("Bad file");
                return;
            }

            Console.Write("Enter directory to scan: ");
            string dir = Console.ReadLine();
            Line();
            CheckDirectory(dir, 0.95 , searchImage);        //Display only images that match by 95%
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top