I want to find a specific pixel coordinates from screen. Here's my code (I'm mega-super-newbie, I just started today with C#:
static string GetPixel(int X, int Y)
{
Point position = new Point(X, Y);
var bitmap = new Bitmap(1, 1);
var graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(position, new Point(0, 0), new Size(1, 1));
var _Pixel = bitmap.GetPixel(0, 0);
return "0x" + _Pixel.ToArgb().ToString("x").ToUpper().Remove(0, 2);
//it returns a pixel color in a form of "0xFFFFFF" hex code
//I had NO idea how to convert it to hex code so I did that :P
}
static void Main()
{
// for x = 1 to screen width...
for (int x = 1; x <= Screen.PrimaryScreen.Bounds.Bottom; x++)
{
// for x = 1 and y = 1 to screen height...
for (int y = 1; y <= Screen.PrimaryScreen.Bounds.Height; y++)
{
string pixel = GetPixel(x, y);
if (pixel == "0x007ACC") //blue color
{
MessageBox.Show("Found 0x007ACC at: (" + x + "," + y + ")");
break; //exit loop
}
}
}
}
edit:
Here's an error which appears when I run this script:
An unhandled exception of type 'System.ArgumentOutOfRangeException'
occurred in mscorlib.dll
Additional information: Index and length must refer to a location
within the string
I have experience in AutoIt, it's my first day with C# ^^
Regards
Welcome to SO.
Most coordinates and other things are 0-based, just as in arrays.
That being said, it would be best to use the Bounds' X/Y/Width and Height properties for the loops:
var bounds = Screen.PrimaryScreen.Bounds;
for (int x = bounds.X; x < bounds.Width; x++) {
for(int y = bounds.Y; y < bounds.Height; y++) {
..
And the proper way to convert the ARGB value to hex is to use the string.Format() method:
string hex = string.Format("0x{0:8x}", argb);
EDIT: Apparently Graphics.CopyFromScreen leaks handles like there's no tomorrow, which causes strange exceptions to be thrown when no more handles are available (source)
A quick workaround for your scenario could be to capture the whole screen once and then search in the bitmap, i.e. Graphics.CopyFromScreen(new Position(0, 0), new Position(0, 0), new Size(bounds.Width, bounds.Height));
Unfortunately this didn't get fixed in .Net 4.0 (don't know about 4.5), so the only proper solution seems to be to P/Invoke the native GDI functions, as described here.
I'm trying to make a program that, using pointers, detects lines in an image and removes those lines. Currently, the detecting lines part is working really well, and for the most part the removing the lines part is working as well. However, after around 150-200 images, the program will throw random AccessViolationExceptions in places that have nothing to do with the unsafe bits of the code.
This is the bit that does the line removal:
static unsafe Bitmap RemoveLines(Bitmap input, int[] horizontalLines, int[] verticalLines)
{
Bitmap output;
if (input.PixelFormat == PixelFormat.Format24bppRgb)
{
output = (Bitmap) input.Clone();
}
else
{
output = ConvertTo24bpp((Bitmap)input.Clone());
}
BitmapData bitmapData = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.ReadWrite, output.PixelFormat);
int w = output.Width;
int h = output.Height;
int bpp = 3;
int s = bitmapData.Stride;
byte* p = (byte*) bitmapData.Scan0;
for (int r = 0; r < h; r++)
{
for (int c = 0; c < h; c++)
{
if (horizontalLines.Contains(r) || verticalLines.Contains(c))
{
int i = (r * s) + c * bpp;
p[i + 0] = 255;
p[i + 1] = 255;
p[i + 2] = 255;
}
}
}
output.UnlockBits(bitmapData);
return output;
}
After this code, I save the resulting Bitmap as well as embedding it in another Bitmap for comparison purposes:
// ... Detect lines and such
Bitmap export = new Bitmap(bitmap.Width * 3, bitmap.Height, PixelFormat.Format24bppRgb);
Graphics fg = Graphics.FromImage(export);
fg.DrawImage(bitmap, 0, 0); // Draw the original input bitmap
fg.DrawImage(edited, bitmap.Width, 0); // Draw the input after processing (Line Detection)
try
{
Bitmap lineRemoved = RemoveLines(bitmap, horizontalLines.ToArray(), verticalLines.ToArray()); // Remove lines based on earlier detection
lineRemoved.Save(cellDirectory + "\\Lines\\cell_lr_" + i.ToString("D2") + j.ToString("D2") + ".gif", ImageFormat.Gif); // Save image after removal
fg.DrawImage(lineRemoved, bitmap.Width * 2, 0); // Add image to composite for comparison; This line is what throws the error most of the time
lineRemoved.Dispose();
export.Save(cellDirectory + "\\Lines\\cell" + i.ToString("D2") + j.ToString("D2") + ".gif", ImageFormat.Gif);
}
catch (Exception ex)
{ }
The DrawImage call is what throws errors, and it is always an AccessViolationException followed by an InvalidOperationException. Looking at lineRemoved during the error shows that most of its members have "threw exception of type 'InvalidOperationException'" rather than actual values, even though one line before the same Bitmap saved just fine on its own. The input bitmap remains unchanged throughout the code, and is always Cloned or drawn to a different bitmap when I need to alter it in any way.
I've tried commenting out the lines after saving lineRemoved, but then the same error pops up later in the code. What's more, that try/catch doesn't actually catch the Exception - it always says unhandled. It's got to be something to do with the pointers, but otherwise I am completely lost as to what is causing this.
Your code contains a subtle one-character bug. The line that reads
for (int c = 0; c < h; c++)
should be
for (int c = 0; c < w; c++)
If the image is in landscape orientation, your bug would cause the right part of the image not being processed.
If the image is in protrait orientation, it would cause the buffer to overflow, leading to an access violation exception (if you're lucky) or memory corruption (if you're not).
That being said, your algorithm is not very efficient. For example, you are doing the calculation
int i = (r * s) + c * bpp;
for every pixel you're drawing, while obviously (r * s) doesn't change in the inner loop, and c * bpp can be replaced by something like currentPixel += bpp.
In fact it would probably be more efficient to loop over horizontalLines and verticalLines.
I recently was put in front of the problem of cropping and resizing images. I needed to crop the 'main content' of an image for example if i had an image similar to this:
(source: msn.com)
the result should be an image with the msn content without the white margins(left& right).
I search on the X axis for the first and last color change and on the Y axis the same thing. The problem is that traversing the image line by line takes a while..for an image that is 2000x1600px it takes up to 2 seconds to return the CropRect => x1,y1,x2,y2 data.
I tried to make for each coordinate a traversal and stop on the first value found but it didn't work in all test cases..sometimes the returned data wasn't the expected one and the duration of the operations was similar..
Any idea how to cut down the traversal time and discovery of the rectangle round the 'main content'?
public static CropRect EdgeDetection(Bitmap Image, float Threshold)
{
CropRect cropRectangle = new CropRect();
int lowestX = 0;
int lowestY = 0;
int largestX = 0;
int largestY = 0;
lowestX = Image.Width;
lowestY = Image.Height;
//find the lowest X bound;
for (int y = 0; y < Image.Height - 1; ++y)
{
for (int x = 0; x < Image.Width - 1; ++x)
{
Color currentColor = Image.GetPixel(x, y);
Color tempXcolor = Image.GetPixel(x + 1, y);
Color tempYColor = Image.GetPixel(x, y + 1);
if ((Math.Sqrt(((currentColor.R - tempXcolor.R) * (currentColor.R - tempXcolor.R)) +
((currentColor.G - tempXcolor.G) * (currentColor.G - tempXcolor.G)) +
((currentColor.B - tempXcolor.B) * (currentColor.B - tempXcolor.B))) > Threshold))
{
if (lowestX > x)
lowestX = x;
if (largestX < x)
largestX = x;
}
if ((Math.Sqrt(((currentColor.R - tempYColor.R) * (currentColor.R - tempYColor.R)) +
((currentColor.G - tempYColor.G) * (currentColor.G - tempYColor.G)) +
((currentColor.B - tempYColor.B) * (currentColor.B - tempYColor.B))) > Threshold))
{
if (lowestY > y)
lowestY = y;
if (largestY < y)
largestY = y;
}
}
}
if (lowestX < Image.Width / 4)
cropRectangle.X = lowestX - 3 > 0 ? lowestX - 3 : 0;
else
cropRectangle.X = 0;
if (lowestY < Image.Height / 4)
cropRectangle.Y = lowestY - 3 > 0 ? lowestY - 3 : 0;
else
cropRectangle.Y = 0;
cropRectangle.Width = largestX - lowestX + 8 > Image.Width ? Image.Width : largestX - lowestX + 8;
cropRectangle.Height = largestY + 8 > Image.Height ? Image.Height - lowestY : largestY - lowestY + 8;
return cropRectangle;
}
}
One possible optimisation is to use Lockbits to access the color values directly rather than through the much slower GetPixel.
The Bob Powell page on LockBits is a good reference.
On the other hand, my testing has shown that the overhead associated with Lockbits makes that approach slower if you try to write a GetPixelFast equivalent to GetPixel and drop it in as a replacement. Instead you need to ensure that all pixel access is done in one hit rather than multiple hits. This should fit nicely with your code provided you don't lock/unlock on every pixel.
Here is an example
BitmapData bmd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, b.PixelFormat);
byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);
// Blue Green Red
Color c = Color.FromArgb(row[x * pixelSize + 2], row[x * pixelSize + 1], row[x * pixelSize]);
b.UnlockBits(bmd);
Two more things to note:
This code is unsafe because it uses pointers
This approach depends on pixel size within Bitmap data, so you will need to derive pixelSize from bitmap.PixelFormat
GetPixel is probably your main culprit (I recommend running some profiling tests to track it down), but you could restructure the algorithm like this:
Scan first row (y = 0) from left-to-right and right-to-left and record the first and last edge location. It's not necessary to check all pixels, as you want the extreme edges.
Scan all subsequent rows, but now we only need to search outward (from center toward edges), starting at our last known minimum edge. We want to find the extreme boundaries, so we only need to search in the region where we could find new extrema.
Repeat the first two steps for the columns, establishing initial extrema and then using those extrema to iteratively bound the search.
This should greatly reduce the number of comparisons if your images are typically mostly content. The worst case is a completely blank image, for which this would probably be less efficient than the exhaustive search.
In extreme cases, image processing can also benefit from parallelism (split up the image and process it in multiple threads on a multi-core CPU), but this is quite a bit of additional work and there are other, simpler changes you still make. Threading overhead tends to limit the applicability of this technique and is mainly helpful if you expect to run this thing 'realtime', with dedicated repeated processing of incoming data (to make up for the initial setup costs).
This won't make it better on the order... but if you square your threshold, you won't need to do a square root, which is very expensive.
That should give a significant speed increase.
I'd like to optimize this piece of code :
public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height)
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
Byte pixelValue = image.GetPixel(x, y).B;
this.sumOfPixelValues[x, y] += pixelValue;
this.sumOfPixelValuesSquared[x, y] += pixelValue * pixelValue;
}
}
}
This is to be used for image processing, and we're currently running this for about 200 images. We've optimized the GetPixel value to use unsafe code, and we're not using image.Width, or image.Height, as those properties were adding to our runtime costs.
However, we're still stuck at a low speed. The problem is that our images are 640x480, so the middle of the loop is being called about 640x480x200 times.
I'd like to ask if there's a way to speed it up somehow, or convince me that it's fast enough as it is. Perhaps a way is through some fast Matrix Addition, or is Matrix Addition inherently an n^2 operation with no way to speed it up?
Perhaps doing array accesses via unsafe code would speed it up, but I'm not sure how to go about doing it, and whether it would be worth the time. Probably not.
Thanks.
EDIT : Thank you for all your answers.
This is the GetPixel method we're using:
public Color GetPixel(int x, int y)
{
int offsetFromOrigin = (y * this.stride) + (x * 3);
unsafe
{
return Color.FromArgb(this.imagePtr[offsetFromOrigin + 2], this.imagePtr[offsetFromOrigin + 1], this.imagePtr[offsetFromOrigin]);
}
}
Despite using unsafe code, GetPixel may well be the bottleneck here. Have you looked at ways of getting all the pixels in the image in one call rather than once per pixel? For instance, Bitmap.LockBits may be your friend...
On my netbook, a very simply loop iterating 640 * 480 * 200 times only take about 100 milliseconds - so if you're finding it's all going slowly, you should take another look at the bit inside the loop.
Another optimisation you might want to look at: avoid multi-dimensional arrays. They're significantly slower than single-dimensional arrays.
In particular, you can have a single-dimensional array of size Width * Height and just keep an index:
int index = 0;
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
Byte pixelValue = image.GetPixel(x, y).B;
this.sumOfPixelValues[index] += pixelValue;
this.sumOfPixelValuesSquared[index] += pixelValue * pixelValue;
index++;
}
}
Using the same simple test harness, adding a write to a 2-D rectangular array took the total time of looping over 200 * 640 * 480 up to around 850ms; using a 1-D rectangular array took it back down to around 340ms - so it's somewhat significant, and currently you've got two of those per loop iteration.
Read this article which also has some code and mentions about the slowness of GetPixel.
link text
From the article this is code to simply invert bits. This shows you the usage of LockBits as well.
It is important to note that unsafe code will not allow you to run your code remotely.
public static bool Invert(Bitmap b)
{
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte * p = (byte *)(void *)Scan0;
int nOffset = stride - b.Width*3;
int nWidth = b.Width * 3;
for(int y=0;y < b.Height;++y)
{
for(int x=0; x < nWidth; ++x )
{
p[0] = (byte)(255-p[0]);
++p;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return true;
}
I recommend that you profile this code and find out what's taking the most time.
You may find that it's the subscripting operation, in which case you might want to change your data structures from:
long sumOfPixelValues[n,m];
long sumOfPixelValuesSquared[n,m];
to
struct Sums
{
long sumOfPixelValues;
long sumOfPixelValuesSquared;
}
Sums sums[n,m];
This would depend on what you find once you profile the code.
Code profiling is the best place to start.
Matrix addition is a highly parallel operation and can be speed up by parallelizing the operation w/ multiple threads.
I would recommend using Intels IPP library that contains threaded highly optimized API for this sort of operation. Perhaps surprisingly it's only about $100 - but would add significant complexity to your project.
If you don't want to trouble yourself with mixed language programming and IPP, you could try out centerspace's C# math libraries. The NMath API contains easy to used, forward scaling, matrix operations.
Paul
System.Drawing.Color is a structure, which on current versions of .NET kills most optimizations. Since you're only interested in the blue component anyway, use a method that only gets the data you need.
public byte GetPixelBlue(int x, int y)
{
int offsetFromOrigin = (y * this.stride) + (x * 3);
unsafe
{
return this.imagePtr[offsetFromOrigin];
}
}
Now, exchange the order of iteration of x and y:
public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height)
{
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
Byte pixelValue = image.GetPixelBlue(x, y);
this.sumOfPixelValues[y, x] += pixelValue;
this.sumOfPixelValuesSquared[y, x] += pixelValue * pixelValue;
}
}
}
Now you're accessing all values within a scan line sequentially, which will make much better use of CPU cache for all three matrices involved (image.imagePtr, sumOfPixelValues, and sumOfPixelValuesSquared. [Thanks to Jon for noticing that when I fixed access to image.imagePtr, I broke the other two. Now the output array indexing is swapped to keep it optimal.]
Next, get rid of the member references. Another thread could theoretically be setting sumOfPixelValues to another array midway through, which does horrible horrible things to optimizations.
public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height)
{
uint [,] sums = this.sumOfPixelValues;
ulong [,] squares = this.sumOfPixelValuesSquared;
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
Byte pixelValue = image.GetPixelBlue(x, y);
sums[y, x] += pixelValue;
squares[y, x] += pixelValue * pixelValue;
}
}
}
Now the compiler can generate optimal code for moving through the two output arrays, and after inlining and optimization, the inner loop can step through the image.imagePtr array with a stride of 3 instead of recalculating the offset all the time. Now an unsafe version for good measure, doing the optimizations that I think .NET ought to be smart enough to do but probably isn't:
unsafe public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height)
{
byte* scanline = image.imagePtr;
fixed (uint* sums = &this.sumOfPixelValues[0,0])
fixed (uint* squared = &this.sumOfPixelValuesSquared[0,0])
for (int y = 0; y < Height; y++)
{
byte* blue = scanline;
for (int x = 0; x < Width; x++)
{
byte pixelValue = *blue;
*sums += pixelValue;
*squares += pixelValue * pixelValue;
blue += 3;
sums++;
squares++;
}
scanline += image.stride;
}
}
Where are images stored? If each is on disk, then a bit of your processing time issue may be in fetching them from the disk. You might examine this to see if it is an issue, and if so, then rewrite to pre-fetch the image data so that the array procesing code does not have to wait for the data...
If the overall application logic will allow it (Is each matrix addition independant, or dependant on output of a previous matrix addition?) If they are independant, I'd examine executing them all on separate threads, or in parallel..
The only possible way I can think of to speed it up would be to try do some of the additions in parallel, which with your size might be beneficial over the threading overhead.
Matrix addition is of course an n^2 operation but you can speed it up by using unsafe code or at least using jagged arrays instead of multidimensional.
About the only way to effectively speed up your matrix multiplication is to use the right algorithm. There are more efficient ways to speed up matrix multiplication.Take a look at the Stressen and Coopersmith Winograd algorithms. It is also noted [with the previous replies] that you can parallize the code, which helps quite a bit.
I'm not sure if it's faster but you may write something like;
public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height)
{
Byte pixelValue;
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
pixelValue = image.GetPixel(x, y).B;
this.sumOfPixelValues[x, y] += pixelValue;
this.sumOfPixelValuesSquared[x, y] += pixelValue * pixelValue;
}
}
}
If you only do matrix addition, you'd like to consider using multiple threads to speed up by taking advantage of multi-core processors. Also use one dimensional index instead of two.
If you want to do more complicated operations, you need to use a highly optimized math library, like NMath.Net, which uses native code rather than .net.
Sometimes doing things in native C#, even unsafe calls, is just slower than using methods that have already been optimized.
No results guaranteed, but you may want to investigate the System.Windows.Media.Imaging name space and look at your whole problem in a different way.
Although it's a micro-optimization and thus may not add much you might want to study what the likelihood is of getting a zero when you do
Byte pixelValue = image.GetPixel(x, y).B;
Clearly, if pixelValue = 0 then there's no reason to do the summations so your routine might become
public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height)
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
Byte pixelValue = image.GetPixel(x, y).B;
if(pixelValue != 0)
{
this.sumOfPixelValues[x, y] += pixelValue;
this.sumOfPixelValuesSquared[x, y] += pixelValue * pixelValue;
}}}}
However, the question is how often you're going to see pixelValue=0, and whether the saving on the compute-and-store will offset the cost of the test.
This is a classic case of micro-optimisation failing horribly. You're not going to get anything from looking at that loop. To get real speed benefits you need to start off by looking at the big picture:-
Can you asynchronously preload image[n+1] whilst processing image[n]?
Can you load just the B channel from the image? This will decrease memory bandwidth?
Can you load the B value and update the sumOfPixelValues(Squared) arrays directly, i.e. read the file and update instead of read file, store, read, update? Again, this decreases memory bandwidth.
Can you use one dimensional arrays instead of two dimensional? Maybe create your own array class that works either way.
Perhaps you could look into using Mono and the SIMD extensions?
Can you process the image in chunks and assign them to idle CPUs in a multi-cpu environment?
EDIT:
Try having specialised image accessors so you're not wasting memory bandwidth:
public Color GetBPixel (int x, int y)
{
int offsetFromOrigin = (y * this.stride) + (x * 3);
unsafe
{
return this.imagePtr [offsetFromOrigin + 1];
}
}
or, better still:
public Color GetBPixel (int offset)
{
unsafe
{
return this.imagePtr [offset + 1];
}
}
and use the above in a loop like:
for (int start_offset = 0, y = 0 ; y < Height ; start_offset += stride, ++y)
{
for (int x = 0, offset = start_offset ; x < Width ; offset += 3, ++x)
{
pixel = GetBPixel (offset);
// do stuff
}
}
matrix's addition complexity is O(n^2), in number of additions.
However, since there are no intermediate results, you can parallelize the additions using threads:
it easy to proof that the resulting algorithm will be lock-free
you can tune the optimal number of threads to use
Addendum: it seems to run correctly when I uncheck "optimize code" which leads me to believe it is some quirky configuration problem
Firstly I am trying to run unmanaged code. I have "allow unsafe code" checked. It is pointing to this line of code here where I am trying to read a bitmap without using the relatively slow getpixel:
byte[] buff = { scanline[xo], scanline[xo + 1], scanline[xo + 2], 0xff };
Entire snippet is below. How can I correct this problem?
private const int PIXELSIZE = 4; // Number of bytes in a pixel
BitmapData mainImageData = mainImage.LockBits(new Rectangle(0, 0, mainImage.Width, mainImage.Height), ImageLockMode.ReadOnly, mainImage.PixelFormat);
List<Point> results = new List<Point>();
foundRects = new List<Rectangle>();
for (int y = 0; y < mainImageData.Height
{
byte* scanline = (byte*)mainImageData.Scan0 + (y * mainImageData.Stride);
for (int x = 0; x < mainImageData.Width; x++)
{
int xo = x * PIXELSIZE;
byte[] buff = { scanline[xo], scanline[xo + 1],
scanline[xo + 2], 0xff };
int val = BitConverter.ToInt32(buff, 0);
// Pixle value from subimage in desktop image
if (pixels.ContainsKey(val) && NotFound(x, y))
{
Point loc = (Point)pixels[val];
int sx = x - loc.X;
int sy = y - loc.Y;
// Subimage occurs in desktop image
if (ImageThere(mainImageData, subImage, sx, sy))
{
Point p = new Point(x - loc.X, y - loc.Y);
results.Add(p);
foundRects.Add(new Rectangle(x, y, subImage.Width,
subImage.Height));
}
}
}
It's hard to say with the limited information we have, but I see a couple of obvious problems, one of which addresses your issue directly:
You are not checking the pixel format, but are assuming that it is 32bppRGB. It is likely 24bppRGB, and that would explain the error.
You are reading the RGB values incorrectly; Windows internally stores bitmaps in BGR order.
You are not calling UnlockBits at the end of the method.
What are the values xo + 1 and xo + 2 when x is mainImageData.Width - 1? They are surely walking off the reservation.
The most likely reason is that the image isn't 32bpp. it could be 24bpp, or possibly even 8 or 16 bit.
You should be getting PIXELSIZE from PixelFormat Rather than hard-coding it to 4.
Check to see that the value you are getting for Stride agrees with the Width.