I thought trying to get pixel data would be a simple thing to do, but it has become a big headache.
My original goal is to go through every pixel in the bitmap and then do some modification with the data. However every time I try to get the pixel I get 0 as a result. It feels like the image is not going to the bitmap. Am I missing something in my code or the code in general wrong?
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var imageView1 = FindViewById<ImageView>(Resource.Id.imageView1);
imageView1.SetImageResource(Resource.Drawable.pic1);
Bitmap b = BitmapFactory.DecodeResource(Resources,Resource.Drawable.pic1);
b = Bitmap.CreateBitmap(b);
imageView1.SetImageBitmap(b);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
int pixel = b.GetPixel(i, j);
int A = Color.GetAlphaComponent(pixel);
int R = Color.GetRedComponent(pixel);
int G = Color.GetGreenComponent(pixel);
int B = Color.GetBlueComponent(pixel);
}
}
}
Needed to use
Bitmap b = BitmapFactory.DecodeResource(Resources,Resource.Drawable.pic1);
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
Color pixel = new Color(b.GetPixel(i, j));
int A = Color.GetAlphaComponent(pixel);
int R = Color.GetRedComponent(pixel);
int G = Color.GetGreenComponent(pixel);
int B = Color.GetBlueComponent(pixel);
}
}
Related
usage
public UserControlTester()
{
InitializeComponent();
GetSetPixelsRandom();
}
code
private void GetSetPixelsRandom()
{
Bitmap img = new Bitmap(#"d:\\downloaded images\\test.gif");
for (int i = 0; i < img.Width; i++)
{
for (int j = 0; j < img.Height; j++)
{
Color pixel = img.GetPixel(i, j);
pixels.Add(pixel);
}
}
Bitmap img1 = new Bitmap(512,512);
for (int i = 0; i < img1.Width; i++)
{
for (int j = 0; j < img1.Height; j++)
{
for (int c = 0; c < pixels.Count; c++)
{
img1.SetPixel(i, j, pixels[c]);
}
}
}
img1.Save(#"d:\\downloaded images\\test3.gif");
}
Not sure if this is the right way. the inner loop with the variable c take a lot of time because there are more then 290,000 pixels.
Assuming you want to resize the image, this can be done easily. The Bitmap constructor has rescaling build in:
Bitmap img = new Bitmap(#"d:\\downloaded images\\test.gif");
Bitmap img1 = new Bitmap(img, new Size(512, 512));
img1.Save(#"d:\\downloaded images\\test3.gif");
If you do not want to resize but indeed take random pixels take a look at what at MickyD mentioned.
Note that in your provided example every pixel in the new image is effectively set to the last pixel in the pixels list because you loop over every pixel in pixels for every pixel in the new image.
What?
I have an application that scans an image of my screen by a color code .
Problem!
This process takes too long , because the entire screen is searched.
My Goal
I would like the search to a region around the current mouse position.
But how do i do that?
Code
Here is my Code:
Creates a Screen
private Bitmap CaptureScreen()
{
//Point a = new Point();
//a = Control.MousePosition;
Bitmap b = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
using (Graphics g = Graphics.FromImage(b))
{
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), b.Size);
}
return b;
}
Search for Color Code
public Point GetPixelPosition(Color SearchColor, bool IgnoreAlphaChannel)
{
//Point a = new Point();
//a = Control.MousePosition;
_ColorFound = false;
Point PixelPt = new Point(0, 0);
using (Bitmap b = CaptureScreen())
{
for (int i = 0; i < b.Width; i++)
{
if (this._ColorFound)
break;
for (int j = 0; j < b.Height; j++)
{
if (this._ColorFound)
break;
Color tmpPixelColor = b.GetPixel(i, j);
if (((tmpPixelColor.A == SearchColor.A) || IgnoreAlphaChannel)
&& (tmpPixelColor.R == SearchColor.R)
&& (tmpPixelColor.G == SearchColor.G)
&& (tmpPixelColor.B == SearchColor.B)
)
{
PixelPt.X = i;
PixelPt.Y = j;
this._ColorFound = true;
}
}
}
}
return PixelPt;
}
I don't think your way of scanning is very effective... but in this answer I'm aiming at doing exactly what you want, by using your code (I haven't optimized absolutely anything):
public Point GetPixelPosition(Color SearchColor, bool IgnoreAlphaChannel, int pixelsToSearchAround)
{
Point mousePosition = Cursor.Position;
_ColorFound = false;
Point PixelPt = new Point(0, 0);
using (Bitmap b = CaptureScreen())
{
int minX = mousePosition.X - pixelsToSearchAround;
int maxX = mousePosition.X + pixelsToSearchAround;
int minY = mousePosition.Y - pixelsToSearchAround;
int maxY = mousePosition.Y + pixelsToSearchAround;
if(minX < 0) minX = 0;
if(minY < 0) minY = 0;
if(maxX > b.Width) maxX = b.Width;
if(maxY > b.Height) maxY = b.Height;
for (int i = minX; i < maxX; i++)
{
if (this._ColorFound)
break;
for (int j = minY; j < maxY; j++)
{
if (this._ColorFound)
break;
Color tmpPixelColor = b.GetPixel(i, j);
if (((tmpPixelColor.A == SearchColor.A) || IgnoreAlphaChannel)
&& (tmpPixelColor.R == SearchColor.R)
&& (tmpPixelColor.G == SearchColor.G)
&& (tmpPixelColor.B == SearchColor.B)
)
{
PixelPt.X = i;
PixelPt.Y = j;
this._ColorFound = true;
}
}
}
}
return PixelPt;
}
This should do what you are looking for in a very unoptimized manner: it's not what I'd do to search for a pixel component on screen.
You'd use the third parameter to determine how many pixels around the cursor to search for.
For further optimization, you could only capture the screen region that you are aiming to capture, but I'll leave that up to you (hint: instead of doing it in GetPixelPosition, you could do it in CaptureScreen, modifying the arguments to g.CopyFromScreen, instead of modifying the loop bounds).
Instead of limiting the region, you can improve the performance of the color checking method.
Don't use Bitmap.GetPixel! Use Bitmap.UnlockBits instead.
public static unsafe Point GetPoint (Bitmap bmp, Color c) {
BitmapData bmd = bmp.LockBits (new Rectangle(0,0,bmp.Width,bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
try {
int s = bmd.Stride;
int search = (c.A<<0x18)|(c.R<<0x10)|(c.G<<0x08)|c.B;
int* clr = (int*)(void*)bmd.Scan0;
int tmp;
int* row = clr;
for (int i = 0; i < bmp.Height; i++) {
int* col = row;
for (int j = 0; j < bmp.Width; j++) {
tmp = *col;
if(tmp == search) {
return new Point(j,i);
}
col++;
}
row += s>>0x02;
}
return new Point(-1,-1);
} finally {
bmp.UnlockBits (bmd);
}
}
This method returns (-1,-1) if the color cannot be found. You can adapt it to ignore the alpha-channel as well:
public static unsafe Point GetPoint (Bitmap bmp, Color c, bool ignoreAlpha = false) {
BitmapData bmd = bmp.LockBits (new Rectangle(0,0,bmp.Width,bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
try {
int s = bmd.Stride;
int search = (c.A<<0x18)|(c.R<<0x10)|(c.G<<0x08)|c.B;
if(ignoreAlpha) {
search &= 0xffffff;
}
int* clr = (int*)(void*)bmd.Scan0;
int tmp;
int* row = clr;
for (int i = 0; i < bmp.Height; i++) {
int* col = row;
for (int j = 0; j < bmp.Width; j++) {
tmp = *col;
if(ignoreAlpha) {
tmp &= 0xffffff;
}
if(tmp == search) {
return new Point(j,i);
}
col++;
}
row += s>>0x02;
}
return new Point(-1,-1);
} finally {
bmp.UnlockBits (bmd);
}
}
The reason GetPixel is slower is because you don't process them in batch. This is because the method always needs to decode the image and wait until the pixel you are querying walks by. Using UnlockBits you decode only once and then can iterate over all pixels.
Necessary to draw by pixels array with data (large). How can I do that?
I tried a Canvas and Rectangle on it - the computer hanged himself ...
Tried the following options below (DrawingContext) - computer still hangs himself, but a little bit less.
Please recommend options with the least load on the computer.
int width = 800; - the size of the array (large!!!)
int size = 1; - it is desirable to be able to make the fragment is not only one but several pixels
protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
Random rnd = new Random();
int width = 800;
int size = 1;
CellType[,] types = new CellType[width, width];
for (int i = 0; i < width; i++)
{
for (int j = 0; j < width; j++)
{
int r = rnd.Next(0, 100);
if (r >= 70) types[j,i] = CellType.IsOccupied;
else types[j, i] = CellType.IsEmpty;
}
}
for (int i = 0; i < width; i++)
{
for (int j = 0; j < width; j++)
{
Brush brush = Brushes.Black;
switch (types[j, i])
{
case CellType.IsEmpty: brush = Brushes.Green;
break;
case CellType.IsOccupied: brush = Brushes.Black;
break;
}
drawingContext.DrawRectangle(brush,
new Pen(brush, 1),
new Rect(j * size, i * size, size, size));
}
}
base.OnRender(drawingContext);
}
For how long does it freeze? A couple of years ago I did something quite similar in Silverlight. It was a bit slow but still acceptable. Try using WriteableBitmap with SetPixel or FillRectangle methods, but please keep in mind that drawing pixel by pixel in a loop will always take some time.
Forgot to mention SetPixel and FillRectangle may need WriteableBitmapEx, available here:
http://writeablebitmapex.codeplex.com/
I am just experimenting with Silverlight however I've run into an issue with a Canvas element. I am trying to generate a grid of rectangle based off a multidimensional array but when I run the code, the canvas has no elements. I wonder if you could offer some guidance for this?
public void generate(Rectangle[, ,] worldData)
{
int locx = 0, locy = 0;
Rectangle currentBlock = new Rectangle();
int z = 0;
for (int x = 0; x < worldData.GetLength(1); x++)
{
for (int y = 0; y < worldData.GetLength(2); y++)
{
currentBlock = worldData[z, x, y];
Canvas.SetTop(currentBlock, locy);
Canvas.SetLeft(currentBlock, locx);
locy = locy + 32;
gridDisplayCanvas.Children.Add(currentBlock);
}
locx = locx + 32;
locy = 0;
}
}
I figured out what is causing the issue, the images where being referenced with a \ but silverlight expects a \
I have a matrix (2D) of an image in EMGU cv,how can I fill the rest of the matrix with zeros but keep a certain area(rectangle) with the original data?
Method 1
One way to achieve what your after is to access the Data of the Matrix directly and set the values to '0' the following code will set the lower quarter of 'My_Matrix' to 0 where all other values will remain 20.
Matrix<double> My_Matrix_Image = new Matrix<double>(8,10);
My_Matrix_Image.SetValue(20); //set all values of Matrix to 20
for(int i = 4; i< My_Matrix_Image.Height; i++)
{
for (int j = 5; j < My_Matrix_Image.Width; j++)
{
My_Matrix_Image.Data[i,j] = 0;
}
}
To achieve what you wanted from your comment you must still take the same approach My_Matrix_Image would contain your image data values from 0-255 I will give solutions for both greyscale and colour images. I will keep the first 30 rows of the image and set the rest to zero the image will be 100x100 pixels in size. Change j = 30 to alter the amount of rows.
First Colour Image Matrix there will be 3 channels Red, Green and Blue:
for(int i = 0; i< My_Matrix_Image.Height; i++)
{
for (int j = 30; j < My_Matrix_Image.Width; j++)
{
My_Matrix_Image.Data[i,j,0] = 0; //RED
My_Matrix_Image.Data[i,j,1] = 0; //GREEN
My_Matrix_Image.Data[i,j,2] = 0; //BLUE
}
}
Greyscale Image Matrices are easier as there will be 1 channel:
for(int i = 0; i< My_Matrix_Image.Height; i++)
{
for (int j = 30; j < My_Matrix_Image.Width; j++)
{
My_Matrix_Image.Data[i,j,0] = 0;
}
}
Now lets assume you want to keep the Middle 40 Rows you will have to add an additional loop remember this is the only way with a Matrix I have only provided the colour image example as you can see it starts getting a little messy and Method 2 may be better:
for(int i = 0; i< My_Matrix_Image.Height; i++)
{
//LOOP 1 SET THE FRONT ROWS
for (int j = 0; j<40; j++)
{
My_Matrix_Image.Data[i,j,0] = 0; //RED
My_Matrix_Image.Data[i,j,1] = 0; //GREEN
My_Matrix_Image.Data[i,j,2] = 0; //BLUE
}
// LOOP 2 SET THE BACK ROWS
for (int j = 60; j < My_Matrix_Image.Width; j++)
{
My_Matrix_Image.Data[i,j,0] = 0; //RED
My_Matrix_Image.Data[i,j,1] = 0; //GREEN
My_Matrix_Image.Data[i,j,2] = 0; //BLUE
}
}
Method 2
Now lets assume you do want to keep a rectangle of data. Creating 6 Loops is complex and inefficient so here is what you could do.
//Make a Blank Copy of your Image this will be automatically full of zeros
Matrix<double> My_Image_Copy = My_Image_Matrix.CopyBlank();
//Now copy the data you want to keep from your original image into you blank copy
for(int i = 40; i< 60; i++)
{
for (int j = 40; j < 60; j++)
{
My_Image_Copy.Data[i,j,0] = My_Matrix_Image.Data[i,j,0]; //RED
My_Image_Copy.Data[i,j,1] = My_Matrix_Image.Data[i,j,1]; //GREEN
My_Image_Copy.Data[i,j,2] = My_Matrix_Image.Data[i,j,2]; //BLUE
}
}
The above code will copy the centre 20x20 pixels from an image you can obviously change this to copy whole rows by using for(int i = 0; i< My_Matrix_Image.Height; i++)
Much better I'm sure you will agree.
Alternative
Now while you are using a Matrix to store you data using a Image construct makes coding a little simpler. While this may not be relevant to you it may be to others.
If you use Image or alternative to store your Image data then this can be achieved by:
Image<Gray, Byte> My_Image = new Image<Gray, byte>(openfile.FileName);
Image<Gray, Byte> My_Image_Copy = My_Image.CopyBlank();
Rectangle Store_ROI = my_image.ROI; //Only need one as both images same size
My_Image.ROI = new Rectangle(50, 50, 100, 100);
My_Image_Copy.ROI = new Rectangle(50, 50, 100, 100);
My_Image_Copy = My_Image.Copy(); //This will only copy the Region Of Interest
//Reset the Regions Of Interest so you will now operate on the whole image
My_Image.ROI = Store_ROI;
My_Image_Copy.ROI = Store_ROI;
Now this the same as Method 2 but you don't need to sort write out loops where errors can occur.
Hope this correction answers your question,
Cheers
Chris
// Rectangle's parameters
static int x = 3;
static int y = 3;
static int width = 2;
static int height = 2;
Rectangle specificArea = new Rectangle(x, y, width, height);
// Your image matrix; 20x20 just a sample
Matrix<int> imageMatrix = new Matrix<int>(20, 20);
public Matrix<int> cropMatrix()
{
// Crop a specific area from image matrix
Matrix<int> specificMatrix = imageMatrix.GetSubRect(specificArea);
// Matrix with full of zeros and same size with imageMatrix
Matrix<int> croppedMatrix = imageMatrix.CopyBlank();
for (int i = x; i < x+width; i++)
{
for (int j = y; j < y+height; j++)
{
// Set croppedMatrix with saved values
croppedMatrix[i, j] = specificMatrix[i-x, j-y];
}
}
return croppedMatrix;
}