Using GDI+ I've made a heatmap bmp and I'd like to superimpose it on top of my bmp map. I've saved the two bmps to disk, and they look good, I just need a way to put them together. Is there any way to do this, perhaps using the Graphics object? How is transparency/alpa involved?
I'm very new to GDI programming so please be as specific as possible.
OK - here's an answer. At some point I need to learn how GDI+ works...
I couldn't get around the transarency issues, but this works. It just copies the non-white pixels from the overlay to the map:
for (int x = 0; x < map.Width; x++)
for (int y = 0; y < map.Height; y++) {
Color c = overlay.GetPixel(x, y);
if ((c.A != 255) || (c.B != 255) || (c.G != 255) || (c.R != 255))
map.SetPixel(x, y, c);
This should do the job...
At the moment the Image you want to superimpose onto the main image will be located in the top left corner of the main Image, hence the new Point(0,0). However you could change this to locate the image anywhere you want.
void SuperimposeImage()
{
//load both images
Image mainImage = Bitmap.FromFile("PathOfImageGoesHere");
Image imposeImage = Bitmap.FromFile("PathOfImageGoesHere");
//create graphics from main image
using (Graphics g = Graphics.FromImage(mainImage))
{
//draw other image on top of main Image
g.DrawImage(imposeImage, new Point(0, 0));
//save new image
mainImage.Save("OutputFileName");
}
}
Related
I'm trying to generate a custom Bitmap through code at a very small size and display it to a PictureBox, upscaled to fit said PictureBox. I am using the graphics object to do this in order to use NearestNeighbor interpolation to upscale single pixels perfectly.
I'm using the graphics object of a temporary default image that is in the PictureBoxs "Image" component on Form.Load, which is sized to be the perfect width and height to maintain the correct aspect ratio from the original Bitmap.
Here is the relevant code:
private void Form1_Load(object sender, EventArgs e)
{
bmp = new Bitmap(16, 9, PixelFormat.Format24bppRgb);
rnd = new Random();
GenerateImage();
}
private void GenerateImage()
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
int num = rnd.Next(2);
if (num == 0)
{
bmp.SetPixel(x, y, Color.White);
}
else
{
bmp.SetPixel(x, y, Color.Gold);
}
}
}
Bitmap image = new Bitmap(picOutput.Image);
grp = Graphics.FromImage(image);
grp.InterpolationMode = InterpolationMode.NearestNeighbor;
grp.DrawImage(
bmp,
new Rectangle(0, 0, image.Width, image.Height),
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel
);
grp.Dispose();
picOutput.Image = image;
}
The problem is that the Bitmap seems to be drawn incorrectly. About half a pixel from the original Bitmap is cut off on the left and top edges of the Bitmap when displayed through the PictureBox, and that roughly half a pixel shows up as the original default image on the right and bottom edges. It's almost like the Bitmap was offset up and to the left while being drawn by the graphics object, it doesn't perfectly cover up the original default image like it was supposed to.
My first thought was the PictureBoxs SizeMode, which is still set to "Normal," but none of them change the problem at all. Here is a picture of the problem. The black edges on the right and bottom are part of the temporary default image (the image I used graphics from), which is completely black and covers the entire PictureBox area.
Can anyone offer some insight?
As user Jimi pointed out in a comment, grp.PixelOffsetMode = PixelOffsetMode.Half from this post solved the issue.
What is the proper wax to give a PNG image a colored background. as shown in the example below:
A PNG Image with different levels of opacity and transparent background:
A PNG image with a background color applied:
The question is to reproduce a new Image from the old one with a specified color.
The second part is how to add a color overlay to a PNG Image. perhaps replace the white with the new color.
This is the example PNG I have:
And this is the example PNG I want to get:
Correct me if I am wrong .. but this might be a possibility to use a grayscale image instead of a PNG with an alpha channel
Bitmap colorBitmap(Color forGroundColor, Color backGroundColor, Bitmap bmpGrayScale)
{
Size size = bmpGrayScale.Size;
Bitmap applyForgroundColor= new Bitmap(size.Width, size.Height);
Rectangle rect1 = new Rectangle(Point.Empty, bmpGrayScale.Size);
using (Graphics G1 = Graphics.FromImage(applyForgroundColor) )
{
G1.Clear(forGroundColor);
G1.DrawImageUnscaledAndClipped(applyForgroundColor, rect1);
}
for (int y = 0; y < size.Height; y++)
for (int x = 0; x < size.Width; x++)
{
Color c1 = applyForgroundColor.GetPixel(x, y);
Color c2 = bmpGrayScale.GetPixel(x, y);
applyForgroundColor.SetPixel(x, y, Color.FromArgb((int)(255 * c2.GetBrightness()), c1 ) );
}
Bitmap applyBackgroundColor= new Bitmap(size.Width, size.Height);
Rectangle rect2 = new Rectangle(Point.Empty, bmpGrayScale.Size);
using (Graphics G2 = Graphics.FromImage(applyBackgroundColor) )
{
G2.Clear(backGroundColor);
G2.DrawImageUnscaledAndClipped(applyForgroundColor, rect2);
}
return applyBackgroundColor;
}
I'm wondering if that's possible:
I got a c# application with something like a display consisting of about 11000 circles drawn on the Form.
What I want to achieve is to be able to draw text on that display, but not using the "real" pixels, but using the circles (rectangles) drawn on the form as pixels.
Edit 1:
When drawing text in c#, you would i.e. use something like Graphics.DrawString(...), giving the method a rectangle (so coordinates) in which the text should be drawn in. That text then is drawn in that rectangle using the screen pixels. What I want to do is draw text as well but not using the screen pixels but my custom pixels of which my display consists.
Edit 2
Method used to draw the circles on the Form; Circles is a list consisting of Circle objects, where circleRectangle returns the coordinates in which the circle should be drawn and Filled tells the method if the circle should be filled or not.
public void DrawCircles(Graphics g)
{
graphics = g;
graphics.SmoothingMode =System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Pen pen = new Pen(Color.Black, penthickness);
SolidBrush brush = new SolidBrush(Color.White);
for (int j = 0; j < Circles.Count;j++ )
{
graphics.DrawEllipse(pen, Circles[j].CircleRectangle);
if (Circles[j].Filled)
brush.Color = fillColor;
else
brush.Color = Color.White;
graphics.FillEllipse(brush, Circles[j].CircleRectangle);
}
}
Is this possible and if yes, how would I do that?
You could write on an invisible BitMap with the DrawText method and then scan the bitmap's pixels and turn the corresponding circles on.
Did that last week with the cells of DataGridView. Real easy.
Here is some code:
public void drawText(string text, Font drawFont)
{
Bitmap bmp = new Bitmap(canvasWidth, canvasHeight);
Graphics G = Graphics.FromImage(bmp);
SolidBrush brush = new SolidBrush(paintColor);
Point point = new Point( yourOriginX, yourOriginY );
G.DrawString(text, drawFont, brush, point);
for (int x = 0; x < canvasWidth; x++)
for (int y = 0; y < canvasHeight; y++)
{
Color pix = bmp.GetPixel(x, y);
setCell(x, y, pix); //< -- set your custom pixels here!
}
bmp.Dispose();
brush.Dispose();
G.Dispose();
}
Edit: You would use your dimensions and your origin for the DrawString, of course
For example, I have pic 1 and pic 2, they are same dimensions except pic 2 has a square in the top left corner. How can I compare the two pictures get the location of each pixel thats colour has changed and then draw to each pixel? Thanks.
I've been playing with images recently, and this is what I've been doing:
using System.Drawing;
using System.Drawing.Imaging;
// Open your two pictures as Bitmaps
Bitmap im1 = (Bitmap)Bitmap.FromFile("file1.bmp");
Bitmap im2 = (Bitmap)Bitmap.FromFile("file2.bmp");
// Assuming they're the same size, loop through all the pixels
for (int y = 0; y < im1.Height; y++)
{
for (int x = 0; x < im1.Width; x++)
{
// Get the color of the current pixel in each bitmap
Color color1 = im1.GetPixel(x, y);
Color color2 = im2.GetPixel(x, y);
// Check if they're the same
if (color1 != color2)
{
// If not, generate a color...
Color myRed = Color.FromArgb(255, 0, 0);
// .. and set the pixel in one of the bitmaps
im1.SetPixel(x, y, myRed);
}
}
}
// Save the updated bitmap to a new file
im1.Save("newfile.bmp", ImageFormat.Bmp);
This might not be exactly what you want to do, but hopefully should give you some ideas on how to get started.
I am trying to process an image for finding out red color regions in it. I scan pixels and if they are found to be ENOUGH red, they are converted to black, otherwise white.
To speed up the process, I skip certain pixels, and need to draw blocks of black or white at their place. I am using this function but it seems to be wrong somewhere. The image I get in the end is completely blank.
public void ProcessFrame( ref Bitmap image )
{
int skip = 10;
Graphics g = Graphics.FromImage(System.Drawing.Image.FromHbitmap(image.GetHbitmap()));
SolidBrush black = new SolidBrush(Color.Black);
SolidBrush white = new SolidBrush(Color.White);
for (int i = 0; i < image.Width; i=i+skip)
{
for (int j = 0; j < image.Height; j = j + skip)
{
Color cl = image.GetPixel(i, j);
if (cl.R > (cl.G * 2) && cl.R > (cl.B * 2))
{
g.FillRectangle(black, new Rectangle(i, j, skip, skip));
}
else
{
g.FillRectangle(white, new Rectangle(i, j, skip, skip));
}
}
}
}
Can you point out the mistake, OR any other better method to achieve what I aim for?
By blank, do you mean white?
I don't know your image, but if (cl.R > (cl.G * 2) && cl.R > (cl.B * 2)) is not a good test for redness. #010000 passes that test, but is basically black. And, #ffaaaa looks red, but won't pass.
If you had a very dark image, lots of pixels might pass that test that aren't very red. With a light image, lots of red pixels won't pass.
Probably the best way is to convert the color the HSL, and then use values of H(ue) that are in the red zone, but only if S(aturation) and L(uminance) are sufficiently bright and non-gray (over a threshhold to not just be black or gray).
Try to use:
Graphics g = Graphics.FromImage(image);
Then consider other replies to improve your color testing.
You didn't show where image is created, but this code will draw into a bitmap:
var bmp = new Bitmap(200,200);
using (g = Graphics.FromImage(bmp))
{
g.FillEllipse(Brushes.Red, 10, 10, 50, 50);
}
Note that you need to call Graphics.Dispose (or use using) before using the image.
Also note that using GetPixel for image processing will be very slow. Use low-level memory access (Bitmap.LockBits) or try some image processing library for .NET (like AForge).