I am trying to compare images in folder(s) and storing diffrence on a 3rd folder.
While I am trying to compare between Image-1 and Image-2, the difference should be Image-3.
Difference between first two images (Image-3) is not showing full, only partial is showing, and I am getting GDI+ error
Code is
// Create the difference image.
bool are_identical = true;
Color eq_color = Color.White;
Color ne_color = Color.Red;
for (int x = 0; x < wid; x++)
{
for (int y = 0; y < hgt; y++)
{
if (bm1.GetPixel(x, y).Equals(bm2.GetPixel(x, y)))
{
bm3.SetPixel(x, y, eq_color);
}
else
{
bm3.SetPixel(x, y, ne_color);
are_identical = false;
bm3.Save(#"C:\XPS Files\DiffrenceofImages\" + new1[i]);
}
}
}
GDI+ error occurs at
bm3.save(#"C:\XPS Files\DiffrenceofImages\" + new1[i]);
So the difference of image shows partial (until loop completed) e.g. if difference of 2 image is a circle, I get 80% of that circle.
You should save the image outside the loop. If the pixels on the right are equal, the image isn't saved anymore. So you get a partial image.
// Create the difference image.
bool are_identical = true;
Color eq_color = Color.White;
Color ne_color = Color.Red;
for (int x = 0; x < wid; x++)
{
for (int y = 0; y < hgt; y++)
{
if (bm1.GetPixel(x, y).Equals(bm2.GetPixel(x, y)))
{
bm3.SetPixel(x, y, eq_color);
}
else
{
bm3.SetPixel(x, y, ne_color);
are_identical = false;
}
}
}
bm3.Save(#"C:\XPS Files\DiffrenceofImages\" + new1[i]);
If you want to speed it up, you could check here: Fast work with Bitmaps in C#
Related
i am using the getPixels of Bitmap in C# to detect patterns of colors. I have an image file, but I need only to investigate a part of the file (exactly a rectangle inside of the image, cropped 5% from all sides)
I was wondering where is the origin (0,0) of the file so I can use a simple function that goes through all the pixels (see code). is there a convention of where is the 0,0 ??? top left? top right? bottom left? bottom right?
the function i show you here is ok for me, no need for a more effective way to check the file, because the file is not big enough. so maximum 1 second if i go through all the file. I just need to understand how the axis x and y are located
thank you,
Josh.
ulong CountPixels(Bitmap bm, Color target_color)
{
// Loop through the pixels.
ulong matches = 0;
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
if (bm.GetPixel(x, y) == target_color)
{
matches++;
}
}
}
return matches;
}
You can just get a Rectangle as a parameter and look just at the points inside that rectangle, to make sure that all points in rectangle falls inside the bitmap, you need to do Math.Min(bmp.Height, region.Y + region.Height) and Math.Min(bmp.Width, region.X+Region.Width) instead of just region.Y + region.Height and region.X+Region.Width:
ulong CountPixels(Bitmap bm, Color target_color, Rectangle region)
{
// Loop through the pixels.
ulong matches = 0;
for (int y = region.Y; y < Math.Min(bmp.Height, region.Y + region.Height); y++)
{
for (int x = region.X; x < Math.Min(bmp.Width, region.X+Region.Width); x++)
{
if (bm.GetPixel(x, y) == target_color)
{
matches++;
}
}
}
return matches;
}
I am trying to write a program that clicks on the first pixel it finds which has a certain color. Unfortunately, it appears that sometimes my program is unable to detect that there is actually the color on the screen. I am taking a screenshot of the screen and then using the GetPixel() method to find the color of every pixel.
Here is my method I use:
private static Point FindFirstColor(Color color)
{
int searchValue = color.ToArgb();
Point location = Point.Empty;
using (Bitmap bmp = GetScreenShot())
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
if (searchValue.Equals(bmp.GetPixel(x, y).ToArgb()))
{
location = new Point(x, y);
}
}
}
}
return location;
}
In order to take a screenshot of my screen, I use:
private static Bitmap GetScreenShot()
{
Bitmap result = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
{
using (Graphics gfx = Graphics.FromImage(result))
{
gfx.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
}
}
return result;
}
Even when I use a color which I know is on the screen, it still returns Point.Empty. What is the reason for this?
Just copied your method and used as color the find Color.Black and it worked without any problems.
The only thing that's currently maybe not correctly in your code is that you don't immediately return after finding the first matching point. Instead you simply continue to iterate over all points thus leading to the fact that you'll going to return the last occurrence of a matching color.
To avoid this you can change your code into:
private static Point FindFirstColor(Color color)
{
int searchValue = color.ToArgb();
using (Bitmap bmp = GetScreenShot())
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
if (searchValue.Equals(bmp.GetPixel(x, y).ToArgb()))
{
return new Point(x, y);
}
}
}
}
return Point.Empty;
}
In this image black colour graph is in the white background. I want to get the pixel length between the two peak waves in the graph and the average amplitude (height of the peak) of the peak waves.
I'm stuck with the logic to implement this code.can anyone help me to implement this. I'm using C#
public void black(Bitmap bmp)
{
Color col;
for (int i = 0; i < bmp.Height; i++)
{
for (int j = 0; j < bmp.Width; j++)
{
col = bmp.GetPixel(j, i);
if (col.R == 0) //check whether black pixel
{
y = i; //assign black pixel x,y positions to a variable
x = j;
}
}
}
}
my supervisor told i have to use a 2D array to store increments and decrements(start point pixel value and end point pixel value of each increment and decrement) of the line to get these values.But i haven't sufficient coding skills to apply that logic to this code.
Bitmap img = new Bitmap(pictureBox1.Image);
int width = img.Width;
int height = img.Height;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Color pixelColor = img.GetPixel(x, y);
if (pixelColor.R == 0 && pixelColor.G == 0 && pixelColor.B == 0)
//listBox1.Items.Add(String.Format("x:{0} y:{1}", x, y));
textBox1.Text = (String.Format("x:{0} y:{1}", x, y));
}
}
I was trying to create simple program that would perform some trivial operation with given image.
For some reason, it works only for the first time (when the app is launched):
//pseudo code
Bitmap im=Bitmap.FromFile("D:\\x.BMP");
Color [,] ColorArray=new [im.Width,im.Height];
private override voide OnPaint(EventArgs e)
{
for(int X=0;X<im.Width;X++)
{
for(int Y=0;Y<im.Height;Y++)
{
ColorArray[X,Y]=im.GetPixel[X,Y];
}
}
for(int X=0;X<im.Width;X++)
{
for(int Y=0;Y<im.Height;Y++)
{
Color c=ColorArray[X,Y];
...
//some code that adds 100 to R,G,B
im.SetPixel(X,Y,c);
}
}
e.Graphics.DrawImage(im);
}
[EDIT]
I have modified my sample code. With the previous version, it could be hard to see the difference from one iteration to the next (especially with the bmp I was using for testing). This one allows you to change color gradually by pressing 1, 2, or 3 on the Num Pad. As others have mentioned, SetPixel/GetPixel is slow, so each KeyUp event does take some time to run.
This works fine for me.
Create a new Windows Forms project. Drop this code in. Make sure you have "x.bmp" available. Each time you press 1, 2, or 3 on the number pad (you might need turn on Num Lock), the colors of the bitmap change slightly:
public partial class Form1 : Form
{
Bitmap bm;
Color [,] colors;
public Form1()
{
bm = (Bitmap)Bitmap.FromFile("x.bmp");
colors = new Color[bm.Width, bm.Height];
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bm,new Point(0,0));
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
//Change the colors a little bit on each KeyUp.
//On NumPad1, change red.
//On NumPad2, change green.
//On NumPad3, change blue.
//Mod with 256 to ensure a value between 0 and 255.
int rInc = 0;
int gInc = 0;
int bInc = 0;
switch (e.KeyCode)
{
case Keys.NumPad1:
rInc = 20;
break;
case Keys.NumPad2:
gInc = 20;
break;
case Keys.NumPad3:
bInc = 20;
break;
default:
break;
}
for (int x = 0; x < bm.Width; x++)
{
for (int y = 0; y < bm.Height; y++)
{
colors[x, y] = bm.GetPixel(x, y);
}
}
for (int x = 0; x < bm.Width; x++)
{
for (int y = 0; y < bm.Height; y++)
{
Color c = colors[x, y];
int r = (c.R + rInc) % 256;
int g = (c.G + gInc) % 256;
int b = (c.B + bInc) % 256;
c = Color.FromArgb(255, r, g, b);
bm.SetPixel(x, y, c);
}
}
Invalidate();
}
}
It's not very sophisticated, but it does what you asked with real code that closely matches your pseudocode.
You can improve your performance when looping over pixels, arrange the loops to access the pixels in row order (x coordinates) in the inner loop. That best matches the image memory layout so it will improve CPU cache performance
for ( y = 0, y < bm.Height; y++)
{
...
for ( x = 0, x < bm.Width; x++)
{
...
}
}
I am writing to a Graphics object dynamically and don't know the actual size of the final image until all output is passed.
So, I create a large image and create Graphics object from it:
int iWidth = 600;
int iHeight = 2000;
bmpImage = new Bitmap(iWidth, iHeight);
graphics = Graphics.FromImage(bmpImage);
graphics.Clear(Color.White);
How can I find the actual size of written content, so I will be able to create a new bitmap with this size and copy the content to it.
It is really hard to calculate the content size before drawing it and want to know if there is any other solution.
The best solution is probably to keep track of the maximum X and Y values that get used as you draw, though this will be an entirely manual process.
Another option would be to scan full rows and columns of the bitmap (starting from the right and the bottom) until you encounter a non-white pixel, but this will be a very inefficient process.
int width = 0;
int height = 0;
for(int x = bmpImage.Width - 1, x >= 0, x++)
{
bool foundNonWhite = false;
width = x + 1;
for(int y = 0; y < bmpImage.Height; y++)
{
if(bmpImage.GetPixel(x, y) != Color.White)
{
foundNonWhite = true;
break;
}
}
if(foundNonWhite) break;
}
for(int y = bmpImage.Height - 1, x >= 0, x++)
{
bool foundNonWhite = false;
height = y + 1;
for(int x = 0; x < bmpImage.Width; x++)
{
if(bmpImage.GetPixel(x, y) != Color.White)
{
foundNonWhite = true;
break;
}
}
if(foundNonWhite) break;
}
Again, I don't recommend this as a solution, but it will do what you want without your having to keep track of the coordinate space that you actually use.
Just check the value of these properties
float width = graphics.VisibleClipBounds.Width;
float height = graphics.VisibleClipBounds.Height;
A RectangleF structure that represents a bounding rectangle for the visible clipping region of this Graphics.