Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Feb 15th, 2007, 7:48 PM   #11
Wizard1988
Professional Programmer
 
Wizard1988's Avatar
 
Join Date: Oct 2005
Location: Chitown
Posts: 417
Rep Power: 3 Wizard1988 is on a distinguished road
Send a message via AIM to Wizard1988
I added the HistogramComparison class but it is not working correctly. The result of applying the formula either gives me 1 or 0. Something is definitely wrong however I can't find it. I am not sure if I am going about making the histogram the correct way.

Here is the code.:mad:

csharp Syntax (Toggle Plain Text)
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.IO;
  8.  
  9. namespace BitmapSimilarity
  10. {
  11. public interface IBitmapCompare
  12. {
  13. double GetSimilarity(Bitmap a, Bitmap b);
  14. }
  15.  
  16. class HistogramBitmapCompare
  17. {
  18. private int min(int a, int b)
  19. {
  20. if (a > b)
  21. {
  22. return b;
  23. }
  24. return a;
  25. }
  26.  
  27. private int sum(int[, ,] a)
  28. {
  29. int sum = 0;
  30.  
  31. for (int x = 0; x < 4; x++)
  32. {
  33. for (int y = 0; y < 4; y++)
  34. {
  35. for (int z = 0; z < 4; z++)
  36. {
  37. sum += a[x, y, z];
  38. }
  39. }
  40. }
  41. return sum;
  42. }
  43.  
  44. public double GetSimilarity(Bitmap a, Bitmap b)
  45. {
  46. int[, ,] histA = ProcessBitmap(a);
  47. int[, ,] histB = ProcessBitmap(b);
  48. int minSum = 0;
  49. double distance = 0;
  50.  
  51. for (int x = 0; x < 4; x++)
  52. {
  53. for (int y = 0; y < 4; y++)
  54. {
  55. for (int z = 0; z < 4; z++)
  56. {
  57. minSum += min(histA[x,y,z],histB[x,y,z]);
  58. }
  59. }
  60. }
  61. distance = minSum / min(sum(histA),sum(histB));
  62. return distance;
  63. }
  64.  
  65. private int[, ,] ProcessBitmap(Bitmap img)
  66. {
  67. BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  68. IntPtr ptr = bmpData.Scan0;
  69. int[] color = new int[3];
  70. int[, ,] histogram = new int[4, 4, 4];
  71. int lBound, uBound;
  72. int x = 0;
  73. int y = 0;
  74. int z = 0;
  75.  
  76. //Clear histogram array;
  77. for (int a = 0; a < 4; a++)
  78. {
  79. for (int b = 0; b < 4; b++)
  80. {
  81. for (int c = 0; c < 4; c++)
  82. {
  83. histogram[a, b, c] = 0;
  84. }
  85. }
  86. }
  87.  
  88. unsafe
  89. {
  90. byte* p = (byte*)(void*)ptr;
  91. int offset = bmpData.Stride - img.Width * 3;
  92. int width = img.Width * 3;
  93.  
  94. for (int a = 0; a < img.Height; ++a)
  95. {
  96. for (int b = 0; b < width; ++b)
  97. {
  98. color[0] = p[0];
  99. color[1] = p[1];
  100. color[2] = p[2];
  101.  
  102. ++p;
  103. }
  104.  
  105. for (int i = 0; i < 4; i++)
  106. {
  107. lBound = (i * 64);
  108. uBound = (64 * i) + 63;
  109.  
  110. //Check which bin the color belongs in
  111. if ((color[0] >= lBound) && (color[0] <= uBound))
  112. {
  113. x = i;
  114. }
  115. if ((color[1] >= lBound) && (color[1] <= uBound))
  116. {
  117. y = i;
  118. }
  119. if ((color[2] >= lBound) && (color[2] <= uBound))
  120. {
  121. z = i;
  122. }
  123. }
  124. histogram[x, y, z]++;
  125. p += offset;
  126. }
  127. }
  128. img.UnlockBits(bmpData);
  129. return histogram;
  130. }
  131.  
  132. }
  133.  
  134. class Program
  135. {
  136. static HistogramBitmapCompare HistogramCompare;
  137. static Bitmap searchImage;
  138.  
  139. static private void Line()
  140. {
  141. for (int x = 0; x < Console.BufferWidth; x++)
  142. {
  143. Console.Write("*");
  144. }
  145. }
  146.  
  147. static void CheckDirectory(string directory,double percentage,Bitmap sImage)
  148. {
  149. DirectoryInfo dir = new DirectoryInfo(directory);
  150. FileInfo[] files = null;
  151. double sim = 0;
  152.  
  153. try
  154. {
  155. files = dir.GetFiles("*.jpg");
  156. }
  157. catch (DirectoryNotFoundException)
  158. {
  159. Console.WriteLine("Bad directory specified");
  160. return;
  161. }
  162.  
  163. foreach (FileInfo f in files)
  164. {
  165. sim = HistogramCompare.GetSimilarity(sImage, new Bitmap(f.FullName));
  166.  
  167. Console.WriteLine(f.Name);
  168. Console.WriteLine("Histogram Intersection");
  169. Console.WriteLine("Match of: {0}", sim);
  170. Line();
  171. }
  172. }
  173.  
  174. static void Main(string[] args)
  175. {
  176. HistogramCompare = new HistogramBitmapCompare();
  177.  
  178. Console.Write("Enter path to search image: ");
  179. try
  180. {
  181. searchImage = new Bitmap(Console.ReadLine());
  182. }
  183. catch (ArgumentException)
  184. {
  185. Console.WriteLine("Bad file");
  186. return;
  187. }
  188.  
  189. Console.Write("Enter directory to scan: ");
  190. string dir = Console.ReadLine();
  191. Line();
  192. CheckDirectory(dir, 0.95 , searchImage); //Display only images that match by 95%
  193. }
  194. }
  195. }

Any ideas?
__________________
JG-Webdesign

Last edited by Wizard1988; Feb 15th, 2007 at 8:03 PM.
Wizard1988 is offline   Reply With Quote
Old Feb 15th, 2007, 10:09 PM   #12
Wizard1988
Professional Programmer
 
Wizard1988's Avatar
 
Join Date: Oct 2005
Location: Chitown
Posts: 417
Rep Power: 3 Wizard1988 is on a distinguished road
Send a message via AIM to Wizard1988
I decided that it will be easier if I just use 3 arrays instead of a cubed array.

I reviewed my code and I wanted to cry a little. It was way too messy. I realized that the three dimensional array wasn't the way to go. Instead I have a struct which contains three arrays which represent the red, blue and green channels. Unfortunately I am again having trouble with the comparison. The way Arevos showed the comparison makes sense but I am not sure how I would do it with a histogram constructed of three arrays.

Here is the updated code:

csharp Syntax (Toggle Plain Text)
  1. class HistogramBitmapCompare : IBitmapCompare
  2. {
  3. public struct RGBHistogram
  4. {
  5. public void Initialize(int bins)
  6. {
  7. red = new int[bins];
  8. green = new int[bins];
  9. blue = new int[bins];
  10. }
  11. public void Clear()
  12. {
  13. for (int x = 0; x < red.Length; x++)
  14. {
  15. red[x] = 0;
  16. green[x] = 0;
  17. blue[x] = 0;
  18. }
  19. }
  20.  
  21. public int NumberOfBinsPerChannel()
  22. {
  23. return red.Length;
  24. }
  25.  
  26. public int ChannelSum(int channel)
  27. {
  28. int sum = 0;
  29. switch (channel)
  30. {
  31. case 1:
  32. {
  33. for (int x = 0; x < red.Length; x++)
  34. {
  35. sum += red[x];
  36. }
  37. break;
  38. }
  39. case 2:
  40. {
  41. for (int x = 0; x < green.Length; x++)
  42. {
  43. sum += green[x];
  44. }
  45. break;
  46. }
  47. case 3:
  48. {
  49. for (int x = 0; x < blue.Length; x++)
  50. {
  51. sum += blue[x];
  52. }
  53. break;
  54. }
  55. }
  56. return sum;
  57. }
  58.  
  59. public int Sum()
  60. {
  61. int sum = 0;
  62. for (int x = 0; x < red.Length; x++)
  63. {
  64. sum += red[x];
  65. sum += green[x];
  66. sum += blue[x];
  67. }
  68. return sum;
  69. }
  70.  
  71. public int[] red;
  72. public int[] green;
  73. public int[] blue;
  74. }
  75.  
  76. private int Minimum(int a, int b)
  77. {
  78. if (a > b)
  79. {
  80. return b;
  81. }
  82. return a;
  83. }
  84.  
  85. private RGBHistogram ProcessBitmap(Bitmap img)
  86. {
  87. BitmapData bmpData = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  88. IntPtr ptr = bmpData.Scan0;
  89. RGBHistogram histogram = new RGBHistogram();
  90. int[] color = new int[3];
  91. int lBound, uBound;
  92.  
  93. histogram.Initialize(4);
  94. histogram.Clear();
  95.  
  96. unsafe
  97. {
  98. byte* p = (byte*)(void*)ptr;
  99. int offset = bmpData.Stride - img.Width * 3;
  100. int width = img.Width * 3;
  101.  
  102. for (int y = 0; y < img.Height; ++y)
  103. {
  104. for (int x = 0; x < width; ++x)
  105. {
  106. color[0] = p[0];
  107. color[1] = p[1];
  108. color[2] = p[2];
  109.  
  110. for (int i = 0; i < histogram.NumberOfBinsPerChannel(); i++)
  111. {
  112. lBound = (i * 64);
  113. uBound = (64 * i) + 63;
  114.  
  115. if ((lBound <= color[0]) && (uBound >= color[0]))
  116. {
  117. histogram.red[i]++;
  118. }
  119. if ((lBound <= color[1]) && (uBound >= color[1]))
  120. {
  121. histogram.green[i]++;
  122. }
  123. if ((lBound <= color[2]) && (uBound >= color[2]))
  124. {
  125. histogram.blue[i]++;
  126. }
  127. }
  128. ++p;
  129. }
  130. p += offset;
  131. }
  132. }
  133. img.UnlockBits(bmpData);
  134. return histogram;
  135. }
  136.  
  137. public double GetSimilarity(Bitmap a, Bitmap b)
  138. {
  139. RGBHistogram histogramA = ProcessBitmap(a);
  140. RGBHistogram histogramB = ProcessBitmap(b);
  141. int min;
  142.  
  143.  
  144. return 0;
  145. }
  146. }

Am I supposed to take the sum the minimum of each channel from the specific bin per histogram?
__________________
JG-Webdesign

Last edited by Wizard1988; Feb 15th, 2007 at 10:43 PM.
Wizard1988 is offline   Reply With Quote
Old Feb 16th, 2007, 4:05 AM   #13
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by Wizard1988 View Post
I added the HistogramComparison class but it is not working correctly. The result of applying the formula either gives me 1 or 0. Something is definitely wrong however I can't find it. I am not sure if I am going about making the histogram the correct way.
You're dividing by two integers. I think that might be your only problem. Cast one to a double and see if it works. e.g.
c# Syntax (Toggle Plain Text)
  1. distance = (double)minSum / min(sum(histA),sum(histB));

As an aside, I'd say there was an advantage to using a three dimensional array over a set of three arrays; you don't have to have any specific switch statements.
Arevos is offline   Reply With Quote
Old Feb 16th, 2007, 6:21 AM   #14
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
A quick addendum. Three separate arrays wouldn't work, or at least the results produced by them will be less accurate. Typically, a colour histogram is a 2D or 3D set of tabulated data. So if you put all red values in 4 bins, and all blue values in 4 bins, then you'll end up with a 2D table of 4 rows (for reds) and 4 columns (for blues), and a total of 4 * 4 cells. Likewise, a 3 colour histogram with 4 bins per colour typically takes up 4 * 4 * 4 cells in total.

By contrast, a set of three arrays only holds 4 + 4 + 4 elements, and since the results aren't cross-referenced, the amount of information you'll get with three separate 1D histograms is significantly less than with one correlated 3D histogram. In order to get any data out of these three histograms, you'll have to find their intersections individually and then average the result. However, I'd advise you stick with a single 3D histogram. You'll likely get more useful data that way.

So your initial attempt using a 3 dimensional array is correct, I feel. The logic for placing the colours in the right bins also appears correct. The only part where you slipped up is when you attempted to divide two integers expecting a floating point number as a result. C# isn't smart enough to figure out that just because you're putting the result into a double, that it should use floating point arithmetic. You need to explicitly declare one of the variables in the equation as a float or a double in order for it to work.
Arevos is offline   Reply With Quote
Old Feb 16th, 2007, 7:50 AM   #15
Wizard1988
Professional Programmer
 
Wizard1988's Avatar
 
Join Date: Oct 2005
Location: Chitown
Posts: 417
Rep Power: 3 Wizard1988 is on a distinguished road
Send a message via AIM to Wizard1988
So would it be possible to add a method to RGBHistogram struct which would construct a 3 dimensional array out of the one dimensional ones?
__________________
JG-Webdesign
Wizard1988 is offline   Reply With Quote
Old Feb 16th, 2007, 8:59 AM   #16
Arevos
Programming Guru
 
Arevos's Avatar
 
Join Date: Aug 2005
Location: England
Posts: 1,499
Rep Power: 5 Arevos is on a distinguished road
Quote:
Originally Posted by Wizard1988 View Post
So would it be possible to add a method to RGBHistogram struct which would construct a 3 dimensional array out of the one dimensional ones?
No, because with three 1D histograms you have 12 bins in total, and with a single 3D histogram you have 64. The three 1D histograms have less information than the 3D one, so you can't convert them into a 3D histogram because you don't have the information to do so.

Just use your original code. If you've overwritten your local copy, you can use the code from your earlier post. A three dimensional array is the best way to do this, because your histogram is essentially a 3D cube of values. Trying to fit this into a data-structure that isn't 3D isn't going to work as well.
Arevos is offline   Reply With Quote
Old Feb 16th, 2007, 9:32 AM   #17
Wizard1988
Professional Programmer
 
Wizard1988's Avatar
 
Join Date: Oct 2005
Location: Chitown
Posts: 417
Rep Power: 3 Wizard1988 is on a distinguished road
Send a message via AIM to Wizard1988
Ok thanks. I will try to fix my code when I get home.
__________________
JG-Webdesign
Wizard1988 is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
confused with distances ktsirig Perl 1 Mar 23rd, 2006 1:02 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 10:36 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC