Using this image as a refernce I want to find the dirty spot at the bottom of this image.
I was able to turn second image to the same scale and orientation and now trying fo find the spot using absdiff but since images are not perfectly matchet I have edges on the diff image.
I'm thinking that instead of difference between pixels with same coordinates I need find minimal difference in an area like n by n pixels. So the question is: does OpenCV have something buitin for that and/or is there better solution to the problem?
EDIT: Solution using threshold and erode:
public static Image<Bgr, Byte> Diff(Image<Bgr, Byte> image1,
Image<Bgr, byte> image2,
int erodeIterations=2)
{
return Diff(image1, image2, new Bgr(50, 50, 50), erodeIterations);
}
public static Image<Bgr, Byte> Diff(Image<Bgr, Byte> image1,
Image<Bgr, byte> image2,
Bgr thresholdColor,
int erodeIterations)
{
var diff = image1.AbsDiff(image2);
diff = diff.ThresholdToZero(thresholdColor);
diff = diff.Erode(erodeIterations);
return diff;
}
Not sure about OpenCV, but solving this problem shouldn't be difficult. Align the two images and find the difference image as you've already done. Use a NxN sliding window across the difference image, and compute the number of pixels that are significantly different within the window i.e. ignore differences of up to say 10 grey levels. Find the maxima of these sums over the entire image, and this should highlight what you need.
You could create a similarity map where each pixel will be assinged with the histogram comparison value calculated on an n by b area focused on each pixel.
Related
I have a 256x256 matrix and each element of the matrix: myMatrix[i,j] // represents a pixel
How can I store my matrix in a picture Box in C#?
The simplest method is to create a bitmap of equal size and use SetPixel for each x,y value.
You will need some kind of transform between the values in the matrix and the color values in the image. If your values is in [0,255] you can just clamp the values. Otherwise the simplest method would be to use linear interpolation between min and max:
var i = (byte)((matrixValue - matrixMinValue) * 255 / (matrixMinValue - matrixMinValue))
var color = Color.FromArgb(i,i,i);
myBitmap.SetPixel(x, y, color)
Set the bitmap to the pictureBox.Image property and you should be good to go.
SetPixel should be adequate for a small image that is set infrequently. If you need higher performance you can look at using pointers to copy data.
I am trying to use image processing to detect and extract information such
Attacker hero
Victim hero
However my method is not that accurate and I could use some ideas to help make it better.
I have a screenshot of a killfeed from a game:
I use Emgu to perform a canny edge detection of the image:
using (Image<Bgr, Byte> img = new Image<Bgr, byte>(bitmap))
{
//Convert the image to grayscale and filter out the noise
using (Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp())
{
Image<Gray, Byte> cannyEdges = gray.Canny(40, 100);
//Smooth out found edges
cannyEdges._SmoothGaussian(3);
}
}
And get this result:
From the result I loop through the image to find a straight line with a width of 2 to then detect the border of the icon.
This however is really inaccurate as you can see the canny edged image has lines that I am not interested in, and the second icon does not even have a clear enough border for me to detect.
Is there any way better way to detect the icons?
Before using hard algorithm like cannyEdge and other fft things, I would recommand to use common sense and eyes to :
select a subset of the image you want to search In
clean it
For instance, you may want to :
filter on cyan color in order to detect the cyan square and/or cyan name (it also works with red).
search for the white arrow that is always the same, then deduce where the squares are
Once it's clean, you'll have only the zone you want to process (for instance both squares with heroes). Then all kinds of algorythms you will use will be much more effective.
If the heroes pics always are the same you even may want to perform a simple difference between screen-zone and reference.
I'm making a tool that does some graphical editing to some bitmaps. I have some 8bppIndexed bitmaps with an existing color palette that I have to convert to 24bppRgb to allow me to draw on it and edit colors of pixels based on some options the user selected. Bitmap graphic is the original 8bpp .bmp file:
//Get Bitmap from file
Bitmap graphic = new Bitmap(source);
//Get palette and pixel format
ColorPalette pal = graphic.Palette;
PixelFormat pix = graphic.PixelFormat; //Format8bppIndexed
//Create datagraphic in 24bppRgb to allow for editing
PixelFormat datapix = PixelFormat.Format24bppRgb;
Bitmap datagraphic = graphic.Clone(new Rectangle(0, 0, graphic.Width, graphic.Height), datapix);
After drawing and editing Bitmap datagraphic, I'm trying to convert it back to 8bppIndexed with the same color palette as Bitmap graphic. I can do that like this:
//Convert back to graphic pixel format
datagraphic = datagraphic.Clone(new Rectangle(0, 0, datagraphic.Width, datagraphic.Height), pix); //Format8bppIndexed
//Apply color palette
datagraphic.Palette = pal;
However, after cloning datagraphic with the same pixel format as graphic, it creates an entirely new color palette. The colors in datagraphic are then all incorrect after applying ColorPalette pal. They only match by their index number between the two palettes. Is there another way of doing this that preserves the colors?
And yes, the bitmaps need to be 8bppIndexed with the custom palette. I'm trying to avoid the need to go through Photoshop to change the color index of all the end result data graphics with the correct palette.
I should say that I'm still fairly new to C#. I hope I was clear as to what I'm trying to do. I appreciate any help here. Thanks in advance.
Converting an 8-bit image to 24bpp is trivial: you just paint it on a new image of the same dimensions and the preferred pixel format.
public static Bitmap PaintOn24bpp(Image image)
{
Bitmap bp = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
using (Graphics gr = Graphics.FromImage(bp))
gr.DrawImage(image, new Rectangle(0, 0, bp.Width, bp.Height));
return bp;
}
This works with any source image no matter its pixel format, though for images containing transparency you may want to preprocess them to fill any transparent areas, because I don't know if painting with transparency taken into account will work if the image you're drawing on doesn't support alpha.
The reverse, to convert a high-colour image to indexed, is a lot trickier, but if you have the palette, it is certainly possible. The main problem in this case is that using Graphics doesn't work, since indexed graphics don't have coloured pixels; they have a coloured palette, and pixels that just reference those colours.
Editing 8-bit data generally boils down to building a byte array containing the image data, and converting that to an image with the palette slapped onto it. The actual conversion is done by making a new 8bpp Bitmap, opening its backing byte array with the LockBits function, and copying your new data into it with Marshal.Copy.
After that, the final missing link is a method to match your image's coloured pixels to their closest palette match, so you can then take the array of resulting matches and bake it into an 8bpp image. This is generally done by calculating the Pythagorean distance (in 3D RGB colour space) of your colour to each of the palette colours, and then taking the index of the colour for which that distance is the smallest.
The whole process, from start to end, is explained in detail in this answer:
A: How to convert a colored image to a image that has only two predefined colors?
This deals with 2 colours, but the method for dealing with 2 or with 256 colours is completely identical, since the end result in both cases was an 8bpp image.
It could be optimised for dealing with 24bpp images directly instead of converting the input to 32bpp, but that's probably not worth the effort, especially since the method posted there works with absolutely any input.
This question already has answers here:
opencv finding image cordinates on another image
(3 answers)
Closed 9 years ago.
I'm new to emgu and would like some advice on where to start.
I've looked through the shape detection but its far too complex for what i need .. i think.. and my surfexample isn't working. I get this error:
Cannot get SURF example in EMGU.CV to work?
Anyway, this is what i would like to do: Find image A in image B. Image A is a simple square which always has the same grey 1 pixel border and always the same size (i believe) but the inner colour could be black or one of about 7 other colours (only ever a solid colour). i need to find the coordinates of image A in image b when i press a button. see the below images.
Image B
And
Image A
Goosebumps answer is correct, but I thought that a bit of code might be helpful also. This is my code using MatchTemplate to detect a template (image A) inside a source image (image B). As Goosebumps noted, you probably want to include some grey around the template.
Image<Bgr, byte> source = new Image<Bgr, byte>(filepathB); // Image B
Image<Bgr, byte> template = new Image<Bgr, byte>(filepathA); // Image A
Image<Bgr, byte> imageToShow = source.Copy();
using (Image<Gray, float> result = source.MatchTemplate(template, Emgu.CV.CvEnum.TM_TYPE.CV_TM_CCOEFF_NORMED))
{
double[] minValues, maxValues;
Point[] minLocations, maxLocations;
result.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);
// You can try different values of the threshold. I guess somewhere between 0.75 and 0.95 would be good.
if (maxValues[0] > 0.9)
{
// This is a match. Do something with it, for example draw a rectangle around it.
Rectangle match = new Rectangle(maxLocations[0], template.Size);
imageToShow.Draw(match, new Bgr(Color.Red), 3);
}
}
// Show imageToShow in an ImageBox (here assumed to be called imageBox1)
imageBox1.Image = imageToShow;
You could have a look at http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html
This is probably what you are looking for. Your Black square would be the template. You may try to also include a little bit of grey around it. This will keep the detector from fireing on large black areas.
I know there's been many topics similar to this one but none of them had a precise answer to what I'm searching for so please if anybody knows, and also I'm doing it in C#.
You all probably know (FPS) games and on the game screen with resolution say 1024x768 i need to find a red rectangle(which is the enemy) and move the mouse to it.
So my main problem is to find that red rectangle. OK so here's what I've tried so far:
I've tried the AForge and ran out of memory:
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0);
TemplateMatch[] matchings = tm.ProcessImage(image1.Clone(r,
System.Drawing.Imaging.PixelFormat.Format24bppRgb), image2);
I've used CopyfromScreen to create a image1 and image2 is a template I have.
I've tried the LockBits, so I can create the 2 dimensional code array for a bitmap and find the code for color red and try to ID if it's a rectangle but the idea seems very complicated been stuck here for a 4 days now.
The web is full of info on this but the more I go into the more I get confused :(
Anyway please ppl help me out here:
Well, first I need to say that this will be probably slow, so if the red rectangle is moving fast, you will need some other solution. C++, CUDA, etc...
First:
Save a image of the red rectangle.
Define the area of possible locations of the red rectangle.
Steps:
Capture the game image (you can use Graphics CopyFromScreen).Copy only the area that the red rectangle might be, to reduce processing time.
Use EmguCV MatchTemplate to find the position of the red
rectangle.
Move the mouse to the position.
Some thread sleep and Repeat 1...
To process the image use EmguCV
To control the mouse use MouseKeyboardActivityMonitor
Speedup note: EmguCV have some CUDA support now, so you can try to use the CUDA version of the method.
//You can check if a 8bpp image is enough for the comparison,
//since it will be much more faster. Otherwise, use 24bpp images.
//Bitmap pattern = "YOUR RED RECTANGLE IMAGE HERE!!"
Point location = Point.Empty;
//source is the screen image !!
Image<Bgr, Byte> srcBgr = new Image<Bgr, Byte>(source);
Image<Bgr, Byte> templateBgr = new Image<Bgr, Byte>(pattern);
Image<Gray, Byte> src;
Image<Gray, Byte> template;
src = srcBgr.Convert<Gray, Byte>();
template = templateBgr.Convert<Gray, Byte>();
Image<Gray, float> matchFloat;
matchFloat = src.MatchTemplate(template, TM_TYPE.CV_TM_CCOEFF_NORMED);
if (debug)
{
//matchFloat.Save(#"match.png");
//Process.Start(#"D:\match.png");
}
//Gets the max math value
double max;
double[] maxs, mins;
Point[] maxLocations, minLocations;
matchFloat.MinMax(out mins, out maxs, out minLocations, out maxLocations);
max = maxs[0];
if (max > threshold)
{
location = maxLocations[0];
//Point the mouse... Do your stuff