Nadesłany przez Tomasz Lubiński, 26 września 2019 12:09
Kod przedstawiony poniżej przedstawia główną część rozwiązania problemu.Pobierz pełne rozwiązanie.
Jeżeli nie odpowiada Ci sposób formatowania kodu przez autora skorzystaj z pretty printer'a i dostosuj go automatycznie do siebie.
akcent/Form1.cs:
//Akcent kolorystyczny
//(c) 2019 by Tomasz Lubinski
//www.algorytm.org
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
namespace Akcent
{
public partial class Form1 : Form
{
/// <summary>
/// Obraz zrodlowy
/// </summary>
private Image source;
private int bytesPerPixel;
/// <summary>
/// Zainicjuj
/// </summary>
public Form1()
{
source = null;
InitializeComponent();
}
/// <summary>
/// Wczytaj obraz
/// </summary>
private void wczytaj_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "Otwórz obraz";
dlg.Filter = "pliki jpg (*.jpg)|*.jpg";
if (dlg.ShowDialog() == DialogResult.OK)
{
source = new Bitmap(dlg.OpenFile());
bytesPerPixel = Image.GetPixelFormatSize(source.PixelFormat) / 8;
picture.Image = new Bitmap(dlg.OpenFile());
picture.Height = picture.Image.Height;
picture.Width = picture.Image.Width;
this.ClientSize = new System.Drawing.Size(Math.Max(picture.Width + 32, 374), picture.Height + 155);
info.Text = "Wskaż na zdjęciu kolor do zaakcentowania";
}
dlg.Dispose();
}
/// <summary>
/// Konwertuj RGB to HSV
/// </summary>
/// <param name="hue">output H (hue) from HSV (0-359)</param>
/// <param name="sat">output S (saturation) from HSV (0-1)</param>
/// <param name="val">output V (value) from HSV (0-1)</param>
/// <param name="red">input R (red) from RGB (0-1)</param>
/// <param name="grn">input G (gree) from RGB (0-1)</param>
/// <param name="blu">input B (blue) from RGB (0-1)</param>
private void RGB2HSV(out double hue, out double sat, out double val, double red, double grn, double blu)
{
double x, f, i;
x = Math.Min(Math.Min(red, grn), blu);
val = Math.Max(Math.Max(red, grn), blu);
if (x == val)
{
hue = 0;
sat = 0;
}
else
{
f = (red == x) ? grn-blu : ((grn == x) ? blu-red : red-grn);
i = (red == x) ? 3 : ((grn == x) ? 5 : 1);
hue = (i-f/(val-x))*60 % 360;
sat = ((val-x)/val);
}
}
/// <summary>
/// Akcent kolorystyczny
/// </summary>
private void obraz_MouseDown(object sender, MouseEventArgs e)
{
//Nie rob nic jezeli obraz jest jeszcze niewczytany
if (source == null)
{
return;
}
//Sprawdz format obrazu - sprawdz czy obraz zawiera 3 kanały - RGB
if (picture.Image.PixelFormat != PixelFormat.Format24bppRgb)
{
MessageBox.Show("Nieobsługiwany format pliku!", "Bład", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//Kopiuj obrazek zrodlowy
Bitmap bitmap = (Bitmap)source.Clone();
picture.Image = bitmap;
//Pobierz wartosc wszystkich punktow obrazu
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, picture.Width, picture.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
byte[] pixelValues = new byte[Math.Abs(bmpData.Stride) * picture.Height];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, pixelValues, 0, pixelValues.Length);
//Odczytaj kolor kliknietego punktu na obrazie
double hsrc, ssrc, vsrc;
RGB2HSV(out hsrc, out ssrc, out vsrc, pixelValues[bmpData.Stride * e.Y + 3 * e.X + 2] / 255.0, pixelValues[bmpData.Stride * e.Y + 3 * e.X + 1] / 255.0, pixelValues[bmpData.Stride * e.Y + 3 * e.X] / 255.0);
//Wzynacz tolerencje
int tolerance = int.Parse(this.tolerance.Text);
double hfrom = (hsrc - (tolerance / 2) + 360) % 360;
double hto = (hsrc + (tolerance / 2)) % 360;
//Dla kolejnych punktow obrazu
for (int i = 0; i < picture.Width * picture.Height; i++)
{
//Odczytaj wartosc HSV
RGB2HSV(out hsrc, out ssrc, out vsrc, pixelValues[3 * i + 2] / 255.0, pixelValues[3 * i + 1] / 255.0, pixelValues[3 * i] / 255.0);
//jezeli wartosc koloru jest poza tolerancja to konwertuj ten punkt na odcien szarosci
if ((hfrom <= hto && (hsrc < hfrom || hsrc > hto)) || (hfrom > hto && hsrc < hfrom && hsrc > hto))
{
//Wartosci kolorow zapisane sa w kolejnosci Blue, Green, Red
byte value = (byte)(0.299 * pixelValues[3 * i + 2] +
0.587 * pixelValues[3 * i + 1] +
0.114 * pixelValues[3 * i]);
pixelValues[3 * i] = value;
pixelValues[3 * i + 1] = value;
pixelValues[3 * i + 2] = value;
}
}
//Wczytaj przetworzony obraz
System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, bmpData.Scan0, pixelValues.Length);
bitmap.UnlockBits(bmpData);
picture.Refresh();
}
}
}

