How to Get the Colour of a Pixel at X,Y Using C#

How to get the colour of a pixel at X,Y using c#?

To get a pixel color from the Screen here's code from Pinvoke.net:

  using System;
using System.Drawing;
using System.Runtime.InteropServices;

sealed class Win32
{
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);

[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);

[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

static public System.Drawing.Color GetPixelColor(int x, int y)
{
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
Color color = Color.FromArgb((int)(pixel & 0x000000FF),
(int)(pixel & 0x0000FF00) >> 8,
(int)(pixel & 0x00FF0000) >> 16);
return color;
}
}

How do I get the color of a specific pixel from a picture box?

Yes you can, but should you?

Here is the change your code needs:

Bitmap b = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.Height);
pictureBox1.DrawToBitmap(b, pictureBox1.ClientRectangle);
Color colour = b.GetPixel(X, Y);
b.Dispose();

But there is really no way around giving the PictureBox a real Image to work with somewhere if you want to do real work with it, meaning if you want to use its possibilities e.g. its SizeMode.

Simply drawing on its background is just not the same. Here is a minimal code to get a real Bitmap assigned:

public Form1()
{
InitializeComponent();
pictureBox1.Image = new Bitmap(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height);
using (Graphics graphics = Graphics.FromImage(pictureBox1.Image))
{
graphics.FillRectangle(Brushes.CadetBlue, 0, 0, 99, 99);
graphics.FillRectangle(Brushes.Beige, 66, 55, 66, 66);
graphics.FillRectangle(Brushes.Orange, 33, 44, 55, 66);
}
}

However if you really don't want to assign an Image you can make the PictureBox draw itself onto a real Bitmap. Note that you must draw the Rectangles etc in the Paint event for this to work! (Actually you must use the Paint event for other reasons as well!)

Now you can test either way e.g. with a Label and your mouse:

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (pictureBox1.Image != null)
{ // the 'real thing':
Bitmap bmp = new Bitmap(pictureBox1.Image);
Color colour = bmp.GetPixel(e.X, e.Y);
label1.Text = colour.ToString();
bmp.Dispose();
}
else
{ // just the background:
Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.Height);
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
Color colour = bmp.GetPixel(e.X, e.Y);
label1.Text += "ARGB :" + colour.ToString();
bmp.Dispose();
}
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(Brushes.DarkCyan, 0, 0, 99, 99);
e.Graphics.FillRectangle(Brushes.DarkKhaki, 66, 55, 66, 66);
e.Graphics.FillRectangle(Brushes.Wheat, 33, 44, 55, 66);
}

Find pixel coordinates by color (color picker control)

StackOverflow is designed for each post to ask and answer one coding question.

(To ask a second question, please make a new post. Include in that post the essential details needed to understand that question. Link back to this question, so you don't have to repeat the information that gives additional background/context.)

Your primary question can be stated as:

Given: A color palette [see picture] generated by [see OnPaintSurface code, starting at // Draw gradient rainbow Color spectrum. How calculate (x,y) coordinates that correspond to a given color?


First, an observation. That 2D palette gives 2 of 3 color axes. You'll need a separate "saturation" slider, to allow picking of any color.

The palette you show is an approximation to an "HSV" color model.

In wiki HSL-HSV models, click on diagram at right. Your palette looks like the rectangle labeled S(HSV) = 1.

Hue + Saturation + Value.

Your ColorList should have fully Saturated colors at max Value.

Going down the screen, the palette reduces Value to near zero.


This is the beginning of an answer to that.

What is needed, is a mathematical formula that corresponds to what is drawn.

Lets look at how that rectangular image was generated.

Rename the color lists so easier to work with.
Store as fields, so can use them later. Use the original Colors from which the SkColors were generated, for easier manipulation.

    private List<Color> saturatedColors;
private List<Color> darkenedColors;
private int nColors => saturatedColors.Count;
private int maxX, maxY; // From your UI rectangle.

The top row (y=0) has saturatedColors, evenly spaced across x.

The bottom row (y=maxY) has darkenedColors, evenly spaced across x.

The pixel colors are linearly interpolated from top row to bottom row.

Goal is to find pixel closest to a given color, "Color goalColor".

Consider each tall, thin rectangle whose corners are two topColors and the corresponding two bottomColors. Goal is to find which rectangle contains goalColor, then find the pixel within that rectangle that is closest to goalColor.

The trickiest part is "comparing" colors, to decide when a color is "between" two colors. This is hard to do in RGB; convert colors to HSV to match the palette you are using. See Greg's answer - ColorToHSV.

Its easier if you make an HSV class:

using System;
using System.Collections.Generic;
using System.Linq;
// OR could use System.Drawing.Color.
using Color = Xamarin.Forms.Color;
...
public class HSV
{
#region --- static ---
public static HSV FromColor(Color color)
{
ColorToHSV(color, out double hue, out double saturation, out double value);
return new HSV(hue, saturation, value);
}

public static List<HSV> FromColors(IEnumerable<Color> colors)
{
return colors.Select(color => FromColor(color)).ToList();
}

const double Epsilon = 0.000001;

// returns Tuple<int colorIndex, double wgtB>.
public static Tuple<int, double> FindHueInColors(IList<HSV> colors, double goalHue)
{
int colorIndex;
double wgtB = 0;
// "- 1": because each iteration needs colors[colorIndex+1].
for (colorIndex = 0; colorIndex < colors.Count - 1; colorIndex++)
{
wgtB = colors[colorIndex].WgtFromHue(colors[colorIndex + 1], goalHue);
// Epsilon compensates for possible round-off error in WgtFromHue.
// To ensure the color is considered within one of the ranges.
if (wgtB >= 0 - Epsilon && wgtB < 1)
break;
}

return new Tuple<int, double>(colorIndex, wgtB);
}

// From https://stackoverflow.com/a/1626175/199364.
public static void ColorToHSV(Color color, out double hue, out double saturation, out double value)
{
int max = Math.Max(color.R, Math.Max(color.G, color.B));
int min = Math.Min(color.R, Math.Min(color.G, color.B));

hue = color.GetHue();
saturation = (max == 0) ? 0 : 1d - (1d * min / max);
value = max / 255d;
}
// From https://stackoverflow.com/a/1626175/199364.
public static Color ColorFromHSV(double hue, double saturation, double value)
{
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
double f = hue / 60 - Math.Floor(hue / 60);

value = value * 255;
int v = Convert.ToInt32(value);
int p = Convert.ToInt32(value * (1 - saturation));
int q = Convert.ToInt32(value * (1 - f * saturation));
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));

if (hi == 0)
return Color.FromArgb(255, v, t, p);
else if (hi == 1)
return Color.FromArgb(255, q, v, p);
else if (hi == 2)
return Color.FromArgb(255, p, v, t);
else if (hi == 3)
return Color.FromArgb(255, p, q, v);
else if (hi == 4)
return Color.FromArgb(255, t, p, v);
else
return Color.FromArgb(255, v, p, q);
}
#endregion

public double H { get; set; }
public double S { get; set; }
public double V { get; set; }

// c'tors
public HSV()
{
}
public HSV(double h, double s, double v)
{
H = h;
S = s;
V = v;
}

public Color ToColor()
{
return ColorFromHSV(H, S, V);
}

public HSV Lerp(HSV b, double wgtB)
{
return new HSV(
MathExt.Lerp(H, b.H, wgtB),
MathExt.Lerp(S, b.S, wgtB),
MathExt.Lerp(V, b.V, wgtB));
}

// Returns "wgtB", such that goalHue = Lerp(H, b.H, wgtB).
// If a and b have same S and V, then this is a measure of
// how far to move along segment (a, b), to reach goalHue.
public double WgtFromHue(HSV b, double goalHue)
{
return MathExt.Lerp(H, b.H, goalHue);
}
// Returns "wgtB", such that goalValue = Lerp(V, b.V, wgtB).
public double WgtFromValue(HSV b, double goalValue)
{
return MathExt.Lerp(V, b.V, goalValue);
}
}

public static class MathExt
{
public static double Lerp(double a, double b, double wgtB)
{
return a + (wgtB * (b - a));
}

// Converse of Lerp:
// returns "wgtB", such that
// result == lerp(a, b, wgtB)
public static double WgtFromResult(double a, double b, double result)
{
double denominator = b - a;

if (Math.Abs(denominator) < 0.00000001)
{
if (Math.Abs(result - a) < 0.00000001)
// Any value is "valid"; return the average.
return 0.5;

// Unsolvable - no weight can return this result.
return double.NaN;
}

double wgtB = (result - a) / denominator;
return wgtB;
}
}

Usage:

    public static class Tests {
public static void TestFindHueInColors(List<Color> saturatedColors, Color goalColor)
{
List<HSV> hsvColors = HSV.FromColors(saturatedColors);
HSV goalHSV = HSV.FromColor(goalColor);
var hueAt = HSV.FindHueInColors(hsvColors, goalHSV.H);
int colorIndex = hueAt.Item1;
double wgtB = hueAt.Item2;
// ...
}
}

This is the essence of the approach. From colorIndex, nColors, wgtB, and maxX, it is possible to calculate x. I recommend writing several test cases, to figure out how to do so.

Calculating y is much simpler. Should be possible using goalHSV.V and maxY.

As you can see, this is not trivial to code.

The most important points:

  • Convert to HSV color space.
  • The palette is composed of tall, thin rectangles. Each rectangle has two saturated and max-value colors at the top two corners: (H1, 1.0, 1.0) and (H2, 1.0, 1.0). The bottom two corners are same hues and saturation, but small value. Perhaps (H1, 1.0, 0.01) and (H2, 1.0, 0.01). Convert your actual darkened values to HSV, to see the exact values.
  • Find which H's goalHSV is between.
  • Learn about "Linear Interpolation" ("Lerp"). In that rectangle, the top edge is a Lerp between the two saturated colors, the side edges is a Lerp from a bright color to the corresponding darkened color.

If the above math is too intense, then draw a box with just one of those rectangles. That is, make the gradient with only TWO colors in the top list. Experiment with trying to locate a color pixel within that rectangle.

IMPORTANT: There might not be a pixel that is EXACTLY the color you are starting with. Find which pixel is closest to that color.

If you aren't sure you have the "best" pixel, then read a few nearby pixels, decide which is "closest". That is, which has the smallest var error = (r2-r1)*(r2-r1) + (g2-g1)*(g2-g1) + (b2-b1)*(b2-b1);.

How can I change the color of a pixel with coordinates x and y in the image?

You need to change the image to bitmap. You can take it as a picture again after making changes. Let's see my code. It works good)
Source code: https://github.com/Nodirbek-Abdulaxadov/SetPixelColor

using System;
using System.Drawing;
using System.Windows.Forms;

namespace ColorPixel
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

OpenFileDialog ofd = new OpenFileDialog();
Color clr;

private void button1_Click(object sender, EventArgs e)
{
try
{
ofd.Filter = "jpg files(*.jpg)|*.jpg|png files(*.png)|*.png|jpeg files(*.jpeg)|*.jpeg|All Files(*.*)|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
pictureBox1.ImageLocation = ofd.FileName;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error !", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

private void button2_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
clr = colorDialog1.Color;
}

private void button3_Click(object sender, EventArgs e)
{
if (ofd.FileName is not null)
{
Bitmap image = new Bitmap(ofd.FileName);
Random random = new Random();

for (int i = 0; i < 50000; i++)
{
int X = random.Next(image.Width);
int Y = random.Next(image.Height);
image.SetPixel(X, Y, clr);
}

pictureBox2.Image = image;
}
}
}
}

Form1 visibility

How to get pixel colour in c#

  1. Capture Current Screen and hold image in 'Bitmap'
  2. Get 'Current Mouse Location'
  3. Find 'Current Mouse Location' Pixel on 'Bitmap'
  4. Get Color on Pixel with this code

    'Bitmap'.GetPixel( 'MouseLocation'.X, 'MouseLocation'.Y);

How to Change Pixel Color of an Image in C#.NET

Here is the Solution I have done with Pixels.

Attaching the source code so one can try the exact and get the result.

I have sample images of 128x128 (Width x Height).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
//using System.Globalization;

namespace colorchange
{
class Program
{
static void Main(string[] args)
{
try
{
Bitmap bmp = null;
//The Source Directory in debug\bin\Big\
string[] files = Directory.GetFiles("Big\\");
foreach (string filename in files)
{
bmp = (Bitmap)Image.FromFile(filename);
bmp = ChangeColor(bmp);
string[] spliter = filename.Split('\\');
//Destination Directory debug\bin\BigGreen\
bmp.Save("BigGreen\\" + spliter[1]);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static Bitmap ChangeColor(Bitmap scrBitmap)
{
//You can change your new color here. Red,Green,LawnGreen any..
Color newColor = Color.Red;
Color actualColor;
//make an empty bitmap the same size as scrBitmap
Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height);
for (int i = 0; i < scrBitmap.Width; i++)
{
for (int j = 0; j < scrBitmap.Height; j++)
{
//get the pixel from the scrBitmap image
actualColor = scrBitmap.GetPixel(i, j);
// > 150 because.. Images edges can be of low pixel colr. if we set all pixel color to new then there will be no smoothness left.
if (actualColor.A > 150)
newBitmap.SetPixel(i, j, newColor);
else
newBitmap.SetPixel(i, j, actualColor);
}
}
return newBitmap;
}
}
}

//Below is the sample image and different results by applying different color
Sample Image

Code modifications will be highly appreciated.

get pixel color in instance

using System;
using System.Drawing;
using System.Runtime.InteropServices;

sealed class Win32
{
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);

[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);

[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

static public System.Drawing.Color GetPixelColor(int x, int y)
{
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
Color color = Color.FromArgb((int)(pixel & 0x000000FF),
(int)(pixel & 0x0000FF00) >> 8,
(int)(pixel & 0x00FF0000) >> 16);
return color;
}
}

Using this, you can then do:

public static class ControlExts
{
public static Color GetPixelColor(this Control c, int x, int y)
{
var screenCoords = c.PointToScreen(new Point(x, y));
return Win32.GetPixelColor(screenCoords.X, screenCoords.Y);
}
}

So, in your case you can do:

var desiredColor = myForm.GetPixelColor(10,10);


Related Topics



Leave a reply



Submit