Aggiunta o sottrazione di colore da un’immagine in una pictureBox utilizzando C #

Mi piacerebbe imparare come codificare alcune modifiche di base all’immagine in Visual Studio. Sto usando openFileDialog per caricare un’immagine in un pictureBox. Ho trovato alcuni cicli su Internet che sono progettati per convertire il colore su base pixel per pixel, ma per vari motivi (che differiscono con ogni esempio di codice) nessuno funziona. Qual è il modo corretto per aggiungere (o sottrarre da), ad esempio, il valore rosso, per cambiare la tinta di un’immagine in una pictureBox? Sto usando C #.

Grazie

EDIT: Ecco un esempio di qualcosa che è almeno un punto di partenza:

Bitmap bmp = (Bitmap)Bitmap.FromFile(pictureBox1.ImageLocation); for (int x = 0; x < bmp.Width; x++) { for (int y = 0; y < bmp.Height; y++) { bmp.GetPixel(x, y); bmp.SetPixel(x, y, Color.FromArgb(128, 0, 128)); } } pictureBox1.Image = bmp; MessageBox.Show("Done"); 

Questo mi consente di ottenere l’immagine pixel per pixel e di cambiare il colore, in questo caso, in viola. Certo, non è quello che voglio fare. Quello che voglio fare è ottenere il valore RGB originale di ciascun pixel e aumentare o diminuire i valori. In altre parole, esegui una correzione del colore molto semplice.

Come ottengo l’RGB corrente di ciascun pixel e impostare l’RGB del nuovo pixel?

Ho anche visto questo pubblicato come un esempio. Il problema è che non vedo come usare ModifyHue:

  var bmp = new Bitmap(pictureBox1.ImageLocation); for (int x = 0; x < bmp.Width; x++) { for (int y = 0; y < bmp.Height; y++) { Color oldColor = bmp.GetPixel(x, y); Color newColor = ModifyHue(oldColor); bmp.SetPixel(x, y, newColor); } } pictureBox1.Image = bmp; 

Mi rendo conto che avrei dovuto inviare dei campioni di codice la prima volta. Grazie

Questo è un esempio dell’utilizzo di Getpixel e SetPixel .

Per (molto) i risultati dei filtri più veloci guardano in Lockbits e anche nell’uso di ColorMatrix

 private void button2_Click(object sender, EventArgs e) { // we pull the bitmap from the image Bitmap bmp = (Bitmap) pictureBox1.Image; // we change some picels for (int y = 100; y < bmp.Height; y++) for (int x = 100; x < bmp.Width; x++) { Color c = bmp.GetPixel(x, y); bmp.SetPixel(x, y, Color.FromArgb(255, 255, cG, cB)); } // we need to re-assign the changed bitmap pictureBox1.Image = (Bitmap) bmp; } 

inserisci la descrizione dell'immagine quiinserisci la descrizione dell'immagine qui

Aggiornare:

Il codice sopra è un'introduzione molto semplice. È semplice ma anche molto lento e non è molto flessibile.

Ecco una versione che è sia molto veloce e molto più flessibile:

 private void button3_Click(object sender, EventArgs e) { // pick one of our filter methods ModifyHue hueChanger = new ModifyHue(MaxChannel); // we pull the bitmap from the image Bitmap bmp = (Bitmap)pictureBox1.Image; Size s = bmp.Size; PixelFormat fmt = bmp.PixelFormat; // we need the bit depth and we assume either 32bppArgb or 24bppRgb ! byte bpp = (byte)(fmt == PixelFormat.Format32bppArgb ? 4 : 3); // lock the bits and prepare the loop Rectangle rect = new Rectangle(Point.Empty, s); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, fmt); int size1 = bmpData.Stride * bmpData.Height; byte[] data = new byte[size1]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, size1); // loops for (int y = 0; y < s.Height; y++) { for (int x = 0; x < s.Width; x++) { // calculate the index int index = y * bmpData.Stride + x * bpp; // get the color Color c = Color.FromArgb( bpp == 4 ?data[index + 3]: 255 , data[index + 2], data[index + 1], data[index]); // process it c = hueChanger(c, 2); // set the channels from the new color data[index + 0] = cB; data[index + 1] = cG; data[index + 2] = cR; if (bpp == 4) data[index + 3] = cA; } } System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length); bmp.UnlockBits(bmpData); // we need to re-assign the changed bitmap pictureBox1.Image = (Bitmap)bmp; } 

Il codice precedente chiama un delegate :

 public delegate Color ModifyHue(Color c, int ch); 

E il delegate è impostato per chiamare una semplice funzione di filtro:

 public Color MaxChannel(Color c, int channel) { if (channel == 1) return Color.FromArgb(255, 255, cG, cB); if (channel == 2) return Color.FromArgb(255, cR, 255, cB); if (channel == 3) return Color.FromArgb(255, cR, cG, 255); else return c; } 

Ed ecco un altro che cambia un Color in grigio

 public Color ToGreyscale(Color c, int dummy) { byte val = (byte) ( (cR * 0.299f + cG * 0.587f + cB *0.114f) ) ; return Color.FromArgb(255, val, val,val); } 

Nota che tutti i metodi che vogliamo chiamare tramite un delegate devono avere la stessa signature . Quindi ToGreyscale prende anche un integer come secondo parametro, anche se non lo usa ..

Si noti inoltre che è ansible limitare i valori di inizio e fine del ciclo di LockBits proprio come nel semplice esempio precedente per ottenere il secondo screenshot.