how to get exact part of Bitmap object - c#

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;
}

Related

How can I convert the Int given by GetPixel of Android.Graphics to a Color?

I want to get the Color of a pixel in a Bitmap. For that normally I use GetPixel(x,y). But with Android.Graphics that method gives me an int representing the Color. So I need to know how can I get this Color from that integer.
In fact that is what I want to do finaly (a white removal in the mPlan):
for (int x=0; x < PlanWidth; x++)
{
for (int y=0; y < PlanHeight; y++)
{
if (mPlan.GetPixel(x, y) == Color.White)
mPlan.SetPixel(x, y, (Color.White - mPlan.GetPixel(x, y)));
}
}
Android.Graphics.Color has constructor Color(Int32). To convert int to Color you can do something like this:
new Color(mPlan.GetPixel(x, y)) == Color.White
but I think will be better to convert Color.White to int using Color.White.ToArgb() and replace SetPixel() argument by Color.Black because Color.White - Color.White will be Color.Black.
int white = Color.White.ToArgb();
for (int x=0; x < PlanWidth; x++)
{
for (int y=0; y < PlanHeight; y++)
{
if (mPlan.GetPixel(x, y) == white)
mPlan.SetPixel(x, y, Color.Black);
}
}
To cast your int color to RGB color in xamarinC# for android you just have to do this :
Color myColor = new Color(yourBitmap.GetPixel(x,y);
Then you can work with it's components like this :
byte myColorRedValue = myColor.R;
byte myColorBlueValue = myColor.B;
byte myColorGreenValue = myColor.G;
byte myColorAlphaValue = myColor.A;
So for example if you want to darken your color just do this :
myColor.R = (byte)(myColor.R / 2);
myColor.G = (byte)(myColor.G / 2);
myColor.B = (byte)(myColor.B / 2);
This will give you three int between 0 and 255. To darken your color you just have to substract them with some number (obviously you have to check if your results are superiors or equals to zero).
This is the easiest way to achieve what you want and to understand how it works from a beginner perspective

How to loop through every square in a rectangle?

In c#, I want to loop through every square possible in a rectangle. The square size is much smaller than the rectangle dimensions. But note that I don't mean loop through every square in a grid pattern, I mean every square at any type of location (not limited to a grid). Its like randomly picking a square at a random location, but it needs to go through all possible locations and only get each one once (no duplicates).
Does anyone know of an algorithm for this?
Thanks
Al you need to do is set an origin (say, left-top), find out the maximum side length from that location, and iterate from 1 to that value for every pixel in your image.
Class names are fictional, adapt to your own needs.
IEnumerable<Rectangle> AllSquaresIn(Rectangle rect)
{
for (int x = 0; i x < rect.Width; x++)
{
for (int y = 0; y < rect.Height; y++)
{
int maxLength = Math.Min(rect.Width - x, rect.Height - y);
for (int i = 1; i <= maxLength; i++)
{
yield return new Rectangle(x, y, x + i, y + i);
}
}
}
}
Since i is always positive, it will be impossible to have duplicate rectangles.
Since it appears from the comments that you only want the rectangles of a given size:
IEnumerable<Rectangle> AllSquaresIn(Rectangle rect, int length)
{
for (int x = 0; i x < rect.Width - length; x++)
{
for (int y = 0; y < rect.Height - length; y++)
{
yield return new Rectangle(x, y, x + length, y + length);
}
}
}

Complete differences between images are not comming, error occured GDI+ (c#)

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#

C# Changing the value of an element in a list of type Rectangle

I'm struggling to set the values of an element at a specific index within a list to a new value.
The list is of type object Rectangle and i get the following error when I try change any of the values of the rectangle in the list e.g.
Property or indexer 'System.Drawing.Rectangle.Bottom' cannot be
assigned to -- it is read only
I've tried converting the list to an array but i still run into the same issue of the values being read-only.
Basically the app takes in a user defined number of rectangles and draws the rectangles with varying widths and heights but along the same baseline. The code im trying to implement needs to take those rectangles and redraw them vertically from the base upwards, while keeping the same number of rectangles and keeping the same outer shape as the previous rectangles created.
Code:
public void RotateRectangles(List<Rectangle> Rectangles, int startPositionX, int userInput, Graphics DrawingSurface)
{
Graphics RectangleGraphics = DrawingSurface;
try
{
// loop in reverse to compare one rectangle to all the other rectangles in the vector
for (int i = Rectangles.Count - 1; i > -1; --i)
{
bool mustChange = true;
for (int t = Rectangles.Count - 1; t > -1; --t)
{
// only compare if the current position in the vector A if different to the position in vector B.
if (i > t)
{
if (mustChange == true)
{
// If the top Y coordinate of RECT at Position i in vector A is bigger than Y coordinate
// at Position t in vector B
if (Rectangles[i].Top >= Rectangles[t].Top)
{
//adjusting points accordingly
Rectangles[i].Left = (Rectangles[t].Left);
Rectangles[t].Bottom = (Rectangles[i].Top);
}
else
{
// If the Y coordinate is not bigger, then we need to stop checking
mustChange = false;
}
}
}
}
}
// loop forward to compare one rectangle to all the other rectangles in the vector
for (int i = 0; i < Rectangles.Count; ++i)
{
bool forwardChange = true;
for (int t = 0; t < Rectangles.Count; ++t)
{
// If the top Y coordinate of RECT at Position i in vector A is bigger than Y coordinate at Position t
// in vector B AND the two rectangales touch
if (i < t && Rectangles[i].Top <= Rectangles[t].Bottom)
{
if (forwardChange == true)
{
// If the top Y coordinate of RECT at Position i in vector A is bigger than Y coordinate at Position t
// in vector B
if (Rectangles[i].Top > Rectangles[t].Top)
{
//adjusting points accordingly
Rectangles[i].Right = (Rectangles[t].Right);
Rectangles[t].Bottom = (Rectangles[i].Top);
}
else
{
// If the Y coordinate is not bigger, then we need to stop checking
forwardChange = false;
// Addjust the Y position of each rectangle so it does not overlap with the first drawing
for (int z = 0; z < Rectangles.Count; ++z)
{
Rectangles[z].Top = (250 - Rectangles[z].Top);
Rectangles[z].Bottom = (250 - Rectangles[z].Bottom);
}
}
}
}
}
}
for (int z = 0; z < Rectangles.Count; ++z)
{
Rectangle DrawRec = myRectangleClass.MyRectangle(Rectangles[z].Left, Rectangles[z].Top, Rectangles[z].Right, Rectangles[z].Bottom);
RectangleGraphics.DrawRectangle(Pen, DrawRec);
ReadWrite.writeOutput(Rectangles[z].Left, Rectangles[z].Top, Rectangles[z].Right, Rectangles[z].Bottom);
}
}
catch (Exception e)
{
}
}
The parts that are giving the errors are:
Rectangles[i].Left = (Rectangles[t].Left);
Rectangles[t].Bottom = (Rectangles[i].Top);
Rectangles[i].Right = (Rectangles[t].Right);
Rectangles[t].Bottom = (Rectangles[i].Top);
Rectangles[z].Top = (250 - Rectangles[z].Top);
Rectangles[z].Bottom = (250 - Rectangles[z].Bottom);
Please can someone help me out or at least direct me in the right direction
The properties Right, Left, Top, Bottom are read-only. You can use the methods Offset and Inflate, and the properties Location, Size, Width and Height, to adjust the position and size of the rectangle, or you can replace an existing rectangle with a newly created one.
e.g.
Rectangle ri = Rectangles[i];
Rectangle rt = Rectangles[t];
Rectangle[i] = new Rectangle( rt.Left, ri.Bottom, rt.Height, rt.Width );
the problem is less the value type of the rectangle, more that the List[] operator returns a new value object.
List<Rectangle> a;
a[4].X += 4; // does the same like the following code:
var r = a[4]
r.X += 4; // will change r, but not a[4]
so you need to store back the rectangle value in the list
Rectangles[i] = new Rectangle(Rectangles[t].Left, Rectangles[i].Top, Rectangles[i].Width, Rectangles[i].Height);
Assign a new rectangle to the wanted index.

C# Graphics class: get size of drawn content

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.

Categories

Resources