In questo esempio di codice, vedremo come tramite il linguaggio di programmazione C#, in ambiente Windows Application applicheremo un effetto olio ad un’immagine a colori, il tutto come mostrato nella figura precedente.
Tramite le classi presenti nel framework .Net 9, in particolare nello spazio dei nomi System.Drawing, applicheremo tale effetto, senza utilizzare componenti di terze parti.
Nel progetto Windows Application, in alto sopra ad ogni dichiarazione, inseriamo lo spazio dei nomi per la gestione della grafica.
Di seguito il frammento di codice delle suddette operazioni.
C#
using System.Drawing.Imaging;
Si crea una funzione, che effettua un ciclo tra i vari pixel del file immagine, ed applicherà l’effetto olio, in base a parametri che vengono passati alla funzione.
Nella funzione sono riportati i vari commenti a titolo informativo del codice.
C#
public static Bitmap EffettoOlio(Bitmap immagineOriginale, int effettoPennello, int effettoLivelloIntensita)
{
if
(immagineOriginale == null)
{
throw new ArgumentNullException(nameof(immagineOriginale), "L'immagine originale non
può essere null.");
}
if
(effettoPennello < 1)
{
throw new ArgumentOutOfRangeException(nameof(effettoPennello),
"Il raggio deve
essere almeno 1.");
}
if
(effettoLivelloIntensita < 1)
{
throw new ArgumentOutOfRangeException(nameof(effettoLivelloIntensita),
"I livelli di
intensità devono essere almeno 1.");
}
Bitmap immagineConEffettoOlio = new Bitmap(immagineOriginale.Width,
immagineOriginale.Height);
//Effettua il ciclo su ogni pixel dell'immagine
for (int y = 0; y < immagineOriginale.Height; y++)
{
for (int x = 0; x
< immagineOriginale.Width; x++)
{
// Array per contare le occorrenze di ogni livello
di intensità
// e per sommare i componenti R, G, B per ogni
livello.
int[] intensityCount = new int[effettoLivelloIntensita];
int[] avgR = new int[effettoLivelloIntensita];
int[] avgG = new int[effettoLivelloIntensita];
int[] avgB = new int[effettoLivelloIntensita];
//Effettua
il ciclo sul vicinato (quadrato) definito dal raggio attorno al pixel corrente
for (int fy = -effettoPennello; fy <=
effettoPennello; fy++)
{
for (int fx = -effettoPennello; fx <=
effettoPennello; fx++)
{
int currentX = x + fx;
int currentY = y + fy;
// Controlla che il pixel del
vicinato sia all'interno dei bordi dell'immagine
if (currentX >= 0 && currentX < immagineOriginale.Width
&&
currentY >= 0
&& currentY < immagineOriginale.Height)
{
Color pixelColor =
immagineOriginale.GetPixel(currentX, currentY);
// Calcola l'intensità del pixel
(media semplice di R, G, B)
int intensity = (pixelColor.R + pixelColor.G +
pixelColor.B) / 3;
// Mappa l'intensità a uno dei
livelli definiti (quantizzazione)
int currentIntensityLevel = (int)Math.Floor((double)intensity * effettoLivelloIntensita / 256);
// Assicurati che il livello non
superi l'indice massimo
if (currentIntensityLevel >= effettoLivelloIntensita)
currentIntensityLevel = effettoLivelloIntensita - 1;
// Incrementa il conteggio per questo
livello di intensità
intensityCount[currentIntensityLevel]++;
// Somma i componenti R, G, B per
questo livello
avgR[currentIntensityLevel] += pixelColor.R;
avgG[currentIntensityLevel] += pixelColor.G;
avgB[currentIntensityLevel] += pixelColor.B;
}
}
}
// Trova il livello di intensità più dominante
(quello con il conteggio più alto)
int maxCount = 0;
int dominantIntensityLevel = 0;
for (int i = 0; i < effettoLivelloIntensita; i++)
{
if (intensityCount[i] >
maxCount)
{
maxCount =
intensityCount[i];
dominantIntensityLevel =
i;
}
}
// Calcola il colore medio per il livello di
intensità dominante
Color newColor;
if (maxCount > 0)
{
int finalR =
avgR[dominantIntensityLevel] / maxCount;
int finalG =
avgG[dominantIntensityLevel] / maxCount;
int finalB =
avgB[dominantIntensityLevel] / maxCount;
newColor = Color.FromArgb(finalR, finalG,
finalB);
}
else
{
// Caso di fallback, se per qualche motivo non ci
sono pixel nel vicinato (es. immagine 1x1 e raggio grande)
newColor =
immagineOriginale.GetPixel(x, y);
}
// Imposta il colore del pixel nell'immagine di
output
immagineConEffettoOlio.SetPixel(x,
y, newColor);
}
}
return immagineConEffettoOlio;
}
Infine si riporta il codice da eseguire nell’evento click di un pulsante, per creare l’immagine richiamando la funzione creata in precedenza.
C#
private void
BtnEffettoOlio_Click(object sender, EventArgs e)
{
string immagineOriginale = "C:\\varie\\faro.jpg";
string immagineNuovaOlio = "C:\\varie\\faroOlio2.jpg";
int
effettoPennello = 3; //Imposta
la "dimensione del pennello". Valori più grandi = effetto più
astratto.
int
effettoLivelloIntensita = 20; // Controlla la quantizzazione del colore. Meno livelli = blocchi di
colore più distinti.
try
{
using (Bitmap originalImage = new Bitmap(immagineOriginale))
{
// Applica l'effetto pittura ad olio
using (Bitmap oilPaintedImage =
EffettoOlio(originalImage, effettoPennello, effettoLivelloIntensita))
{
// Salva l'immagine modificata in
formato JPEG
oilPaintedImage.Save(immagineNuovaOlio, ImageFormat.Jpeg);
MessageBox.Show($"Effetto pittura ad olio applicato e salvato
in '{immagineNuovaOlio}'");
}
}
}
catch (System.IO.FileNotFoundException)
{
MessageBox.Show($"Errore:
Il file '{immagineOriginale}' non è stato trovato.
Assicurati che il percorso sia corretto.");
}
catch (Exception ex)
{
MessageBox.Show($"Si
è verificato un errore: {ex.Message}");
}
}

Le opere pubblicate in questo blog sono sotto la licenza Creative Commons. Attribuzione- No commerciale e no derivate.
Nessun commento:
Posta un commento