Reputation: 2800
Basically its my program to search image in another image pixel by pixel with simpliest nested loop. It works fine for lookin 2x2 in 9x9 image, but it fails to search in 8408 x 8337 resolution (I guess I don't need that much, but I wanted to check how slow it will be)
Error occures when declaring Color 2D array So I am asking for help because of why, and how to fix this
I suspect that OOM error is caused by that he SizeOfColorType * 8337 is bigger than Int32... but I am not sure if this is correct
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace IMGReach
{
class Program
{
static void Main(string[] args)
{
String basePath = @"C:\Users\Administrator\Desktop\IMGReachImages\1.jpg"; // 8408x8337
String searchPath = @"C:\Users\Administrator\Desktop\IMGReachImages\2.jpg"; // 69 x 56
Bitmap b = new Bitmap(basePath); // base image
Bitmap s = new Bitmap(searchPath); // image to search inside of base image
var x = ImageInImage(b, s);
Console.WriteLine(x[0]); // x coord of found image
Console.WriteLine(x[1]); // y coord of found image
Console.Write("END");
Console.ReadKey();
}
private static int[] ImageInImage(Bitmap source, Bitmap searchIt)
{
// Creates array of colors based on image
Color[,] basePixels = AreaToArray(source, 0, 0, source.Width, source.Height);
Color[,] searchPixels = AreaToArray(searchIt, 0, 0, searchIt.Width, searchIt.Height);
Color hookPixel = searchPixels[0, 0];
for (int xpos = 0; xpos < basePixels.GetLength(0); xpos++)
{
for (int ypos = 0; ypos < basePixels.GetLength(1); ypos++)
{
if (basePixels[xpos, ypos] == hookPixel)
{
Color[,] checkMap = AreaToArray(source, xpos, ypos, searchIt.Width, searchIt.Height);
if (sameArray(checkMap, searchPixels))
return new int[] { xpos, ypos };
}
}
}
return null;
}
private static Color[,] AreaToArray(Bitmap source, int start_x, int start_y, int width, int height)
{
if (start_x < 0)
throw new ArgumentException("Invalid parameter value (less than zero)", "start_x");
if (start_y < 0)
throw new ArgumentException("Invalid parameter value (less than zero)", "start_y");
if (width > source.Width)
throw new ArgumentException("Width parameter is bigger than source width", "width");
if (height > source.Height)
throw new ArgumentException("Height parameter is bigger than source height", "height");
Color[,] pixelSet = new Color[width, height]; // [2,2]
for (int ix = 0; ix < width; ix++ )
for (int iy = 0; iy < height; iy++)
pixelSet[ix, iy] = source.GetPixel(ix + start_x, iy + start_y);
return pixelSet;
}
private static bool sameArray(int[,] a1, int[,] a2)
{
if (a1.GetLength(0) != a2.GetLength(0))
return false;
if (a1.GetLength(1) != a2.GetLength(1))
return false;
for (int i = 0; i < a1.GetLength(0); i++)
{
for (int j = 0; j < a1.GetLength(1); j++)
{
if (a1[i, j] == a2[i, j])
{
continue;
}
else
{
return false;
}
}
}
return true;
}
private static bool sameArray(Color[,] a1, Color[,] a2)
{
if (a1.GetLength(0) != a2.GetLength(0))
return false;
if (a1.GetLength(1) != a2.GetLength(1))
return false;
for (int i = 0; i < a1.GetLength(0); i++)
{
for (int j = 0; j < a1.GetLength(1); j++)
{
if (a1[i, j] == a2[i, j])
{
continue;
}
else
{
return false;
}
}
}
return true;
}
}
}
Upvotes: 0
Views: 54
Reputation: 133995
An image that's 8408 x 8337 contains a little over 70 million pixels. The Color
structure is at least 4 bytes in size. So you're trying to allocate a minimum of 280 megabytes. Your system must have 280 megabytes of contiguous memory free. If you're running on a 32-bit system (or running the program in 32 bit mode), it's quite possible that you don't have that memory available. Thus, OutOfMemoryException
.
It gets worse. Even if you somehow manage to allocate memory for that image, your ImageInImage
method needs to allocate the basePixels
array, which will be the same size.
You've probably noticed by now that your program is pretty slow even on small images. Using GetPixel
to read the image colors is going to be really slow. You need to look into using Bitmap.LockBits so that you can access the image bits directly. That MSDN topic has a basic example. You'll need to understand a little about the internal bitmap structure if you want to use it effectively, but there are plenty of examples available if you search a bit.
Upvotes: 2