How to Replace a RGB Value on a Texture2D on Monogame? - c#

I'm working with C# and Monogame 3.2.
I'm currently working on a 2D game, such like Starbound, and I need to have the blocks connect to each other and when not, have some fancy borders.
What I am doing is I have a texture that covers the whole 32*32 image, and a custom function named "trimImage" to trim the image so it has fancy borders.
But, I need to find a way to set a transparent pixel at a specific pixel in a Texture2D so I can make that border.
http://i.imgur.com/dvh6sI6.png
See the purple dirt, I bassicly want it to trim the image to something like that, and when other blocks are connecting to it it will connect.
Does anyone know how, or atleast a better way to do this "border" effect? Thanks.
Note: In my trim class I really do have is just some comments, nothing else.

Not sure exactly what you want your border to look like, but you can do a color replacement like this using the Texture2D.GetData() functions:
private Color TRANSPARENT = Color.Transparent;
private Color BAD_COLOR = Color.Purple;
private const int DEVIATION = 10;
public Texture2D trimImage(Texture2D texture)
{
/// Get the data from the original texture and place it in an array
Color[] colorData = new Color[texture.Width * texture.Height];
texture.GetData<Color>(colorData);
/// Loop through the array and change the RGB values you choose
for (int x = 0; x < texture.Width; x++)
{
for (int y = 0; y < texture.Height; y++)
{
Color pixel = colorData[x * texture.Height + y];
/// Check if the color is within the range
if (MathHelper.Distance(pixel.R, BAD_COLOR.R) < DEVIATION &&
MathHelper.Distance(pixel.G, BAD_COLOR.G) < DEVIATION &&
MathHelper.Distance(pixel.B, BAD_COLOR.B) < DEVIATION &&
pixel.A != 0f)
{
/// Make that color transparent
pixel = TRANSPARENT;
}
}
}
/// Put the color array into the new texture and return it
texture.SetData<Color>(colorData);
return texture;
}
Being able to make a different border is just a matter of changing loop parameters and choosing the appropriate pixels. Hope it helps

Related

Aiming for a more accurate and precise color replacer

What I'm trying to achieve:
In my program, I want to let the user enter any image, then my program resizes it then it gets all of the pixels and checks whether their color matches the color of the pixel at (0, 0). If it does match that pixel then it's going to be replaced with a hardcoded color.
The issue I'm having
My code works when I try to resize and replace the pixel colors with new ones, however when replacing the pixel colors, it usually does not replace some of the pixels, especially those that are closest to the image itself where the colors begin to diverse.
What I tried to fix the problem
I tried declaring the HEX colors as a string and whenever the C letter came, I would tell the program to remove the pixel that string. However, I found that to be very inefficient due to how often it can replace pixels that shouldn't be replaced.
My code
public class PicGen
{
public PicGen(PictureBox pictureBox)
{
Bitmap picBitmap = new(pictureBox.Image);
Bitmap resized = new(picBitmap, new(52, 52));
Color backColorBottom = resized.GetPixel(51, 0);
for (int i = 0; i < resized.Width; i++)
{
for (int j = 0; j < resized.Height; j++)
{
if (resized.GetPixel(i, j) == backColorBottom)
resized.SetPixel(i, j, Color.FromArgb(54, 57, 63));
}
}
Clipboard.SetImage(resized);
}
Example: 1 Notice how the white around the image isn't replaced like the rest of the background? ||
Original 2

I need to know what the highest and lowest pixel between two images in WPF with C#

I have the pixels of each image stored in the Col1 and Col2. How can I know which is the highest pixel and put in a third image?
My definition of highest pixel is as the "por mayor" result in this video: https://www.youtube.com/watch?v=l1_WmoiKgPg
I would also like to know how I can do it for the lowest pixel ("por mayor" in the video).
private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
WriteableBitmap imagen1bmp;
WriteableBitmap imagen2bmp;
WriteableBitmap imagencombinada;
int x, y;
imagen1bmp = (WriteableBitmap)laimagen1.Source;
imagen2bmp = (WriteableBitmap)laimagen2.Source;
for (y = 0; y < imagen1bmp.Height; y++)
{
for (x = 0; x < imagen1bmp.Width; x++)
{
//Get both colors in the pixel point
Color col1 = LeePixel(imagen1bmp, x, y);
Color col2 = LeePixel(imagen2bmp, x, y);
}
UpdateLayout();
}
UpdateLayout();
}
So the first thing to do is understanding what is the highest pixel according to your definition. From the result of the video it seems to be a comparison of the raw RGB values. So basically you select the color with the most red then if it is equal the most green then the most blue.
To get the raw value of a Color, you need to call the method toArgb. One example solution would be:
Color col3; //the color for the output image for this pixel
if(col1.toArgb()>col2.toArgb())
col3=col1;
else
col3=col2;
For the lowest color you just need to exchange col1 and col2 in the affectation.
As for the writing the output to another image you seem to have created some customs methods already with that LeePixel so I wasn't sure how to do it in a way that would fit in your program.

How to replace one set of color 'shades' with another set

I'm looking for a 'magic' function that will take an image and return a copy but with one set of color shades replaced with another set.
e.g. I have a picture of a Red fish: It has various greyscales and Black and White but is essentially various shades of red. I would like to pass it to this 'magic' function and tell it to change its Color.Red shades to equivalent Color.Yellow shades and so on. Just simple (rainbow) colors would be sufficient.
I have seen many code snippets here and on the internet but they seem to concentrate on replacing a single color with another or using a threshold, which works well enough interactively but isn't quite magic enough.
The images I want to apply this to are not photographs or anything too complicated, just icons or simple sprites and the like. (I'm just bored of creating copies in an image editor!)
Anyone have anything like this?
You can accomplish this using the FromAhsb() as displayed in Oliver's answer at Image hue modification in C# (or any other function which lets you create colors from HSB values). Using this function you can easily change the hue of images as following:
var image = new Bitmap("D:\\fish.png"); // location of your image
var color = Color.Red; //The color in the hue you want to change the image.
for (var x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
Color originalColor = image.GetPixel(x, y);
Color changedColor = FromAhsb(originalColor.A, color.GetHue(), originalColor.GetSaturation(), originalColor.GetBrightness());
image.SetPixel(x,y, changedColor);
}
}
image.Save("D:\\new_fish.png", System.Drawing.Imaging.ImageFormat.Png); // location of your new image
This produces the following result:
From
to

Optimization of per-pixel collision

I'm been developing my own physics engine for a school project and recently I encountered a problem: Per pixel collisions on big sprites make my FPS drop A LOT.
Here's my pixel collision code. Before entering the following code I'm using Intersects() to see if their bounding boxes collided.
private bool PerPixelCollision(IObject a, IObject b)
{
Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
a.Texture.GetData(bitsA);
Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
b.Texture.GetData(bitsB);
// Calculate the intersecting rectangle
int x1 = Math.Max(a.Bounds.X, b.Bounds.X);
int x2 = Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width);
int y1 = Math.Max(a.Bounds.Y, b.Bounds.Y);
int y2 = Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height);
Color c;
Color d;
// For each single pixel in the intersecting rectangle
for (int y = y1; y < y2; ++y)
{
for (int x = x1; x < x2; ++x)
{
// Get the color from each texture
c = bitsA[(x - a.Bounds.X) + (y - a.Bounds.Y) * a.Texture.Width];
d = bitsB[(x - b.Bounds.X) + (y - b.Bounds.Y) * b.Texture.Width];
if (c.A != 0 && d.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
{
return true;
}
}
}
// If no collision occurred by now, we're clear.
return false;
}
In the example I'm using to test I'm dropping 4 sprites in another sprite that represents the floor (736x79). When I change the sprite that represents the floor to a bigger sprite (3600x270) the FPS drops. I know the problem is in the pixel collision because I'm using a profiler.
Does anyone have any idea on how to optimize the collision?
P.S.: Sorry if I wasn't clear enough about my problem. My english is not so good.
EDIT: The first problem was solved by using the solution provided by #pinckerman but I found another one related to pixel collision detection.
When a sprite collide with a the transparent part of a texture, we get the part that intersected and check all the pixels of that part. The problem is: When the transparent part is big enough to cover the whole sprite, I check the whole texture of that sprite (currently using 50x50 textures which is 2500 pixels). Is there any way to not check the whole texture?
Thanks
I'm pretty sure that your FPS drop so much because you're doing
Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
a.Texture.GetData(bitsA);
Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
b.Texture.GetData(bitsB);
at the beginning of your method.
I suppose you call your PerPixelCollision every Update loop and creating and coping millions of values every game cycle it's not a very efficient thing to do.
A big sprite creates a huge Color[] array: the bigger are your arrays, the slower will be this method.
EDIT:
For your second problem, I think that, if you don't know beforehand where is the transparent area of your "big" texture, you have to check the whole sprite anyway.
If your sprite it's not too big that's not a big waste of performance.
PS: I see that you get the intersecting Rectangle on your own, maybe you could find useful this method.

c# getPixel not sellecting all pixels

I have a problem with getting the pixels from an image. I load a image, select a pixel from the image and retrieve it's color and then i generate a matrix indexMatrix[bitmap_height][bitmap_width] which contains 1 or 0 depending if the [x,y] color of the bitmap is the same as the color selected. The problem is that the program doesn't select all the pixels although it should. It only retrieves a part of them ( i am sure the pixels 'forgotten' are the same color as the selected color )
The wierd thing is that if i run my program for the new image ( the one constructed from the matrix ) it returns the same image ( as it should ) but i can't figure out how to fix the problem.
Please Help!!!
Regards,
Alex Badescu
and some code from my project :
bitmap declaration:
m_Bitmap = (Bitmap)Bitmap.FromFile(openFileDialog.FileName, false);
Here i calculate the matrix:
int bitmapWidth = m_Bitmap.Width;
int bitmapHeight = m_Bitmap.Height;
indexMatrix = new int[bitmapHeight][];
if (imageIsLoaded && colorIsSelected)
{
for (int i = 0; i < bitmapHeight; i++)
{
indexMatrix[i] = new int[bitmapWidth];
for (int j = 0; j < bitmapWidth; j++)
{
Color temp = m_Bitmap.GetPixel(j, i);
if (temp == selectedColor)
indexMatrix[i][j] = 1;
else indexMatrix[i][j] = 0;
}
}
MessageBox.Show("matrix generated succesfully");
}
matrixIsCalculated = true;
}
There is no obvious failure mode here. Other than that the pixel isn't actually a match with the color. Being off by, say, only one in the Color.B value for example. You cannot see this with the unaided eye.
These kind of very subtle color changes are quite common when the image was resized. An interpolation filter alters the color subtly, even if not strictly needed. Another failure mode is using a compressed image format like JPEG, the compression algorithm changes colors.

Categories

Resources