Nadesłany przez Tomasz Lubiński, 29 października 2019 21:58
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.
Stucki/Form1.cs:
//Algorytm Stucki'ego //(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 Stucki { public partial class Form1 : Form { /// <summary> /// Obraz zrodlowy /// </summary> private Image source; /// <summary> /// Przesuniecie zeby uniknac ujemnych indeksow w tablicy bledow /// </summary> private const int shift = 2; /// <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()); 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); } dlg.Dispose(); } /// <summary> /// Aproksymacja półtonowa - przetwarzenie progowe /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Simple_Click(object sender, EventArgs 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[bmpData.Stride * picture.Height]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, pixelValues, 0, pixelValues.Length); //Odczytaj wartosc progu int threshold = int.Parse(this.threshold.Text); //Dla kolejnych punktow obrazu for (int i = 0; i < pixelValues.Length / 3; i++) { //Wartosci kolorow zapisane sa w kolejnosci Blue, Green, Red //Odczytaj wartosc punktu (zamien na odcienie szarosci) byte value = (byte)(0.299 * pixelValues[3 * i + 2] + 0.587 * pixelValues[3 * i + 1] + 0.114 * pixelValues[3 * i]); if (value > threshold) { //wartosc punktu wieksza od progu - zamien na kolor bialy pixelValues[3 * i] = 255; pixelValues[3 * i + 1] = 255; pixelValues[3 * i + 2] = 255; } else { //wartosc punktu nie wieksza od progu - zamien na kolor czarny pixelValues[3 * i] = 0; pixelValues[3 * i + 1] = 0; pixelValues[3 * i + 2] = 0; } } //Wczytaj przetworzony obraz System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, bmpData.Scan0, pixelValues.Length); bitmap.UnlockBits(bmpData); picture.Refresh(); } /// <summary> /// Algorytm Stucki'ego /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Stucki_Click(object sender, EventArgs 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[bmpData.Stride * picture.Height]; System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, pixelValues, 0, pixelValues.Length); //Odczytaj wartosc progu int threshold = int.Parse(this.threshold.Text); //Utworz tablice bledow double[,] errors = new double[(bmpData.Stride / 3) + 4, picture.Height + 2]; //Dla kolejnych punktow obrazu for (int i = 0; i < pixelValues.Length / 3; i++) { int error; int x = i % (bmpData.Stride / 3); //wspolrzedna x kolejnego punktu int y = i / (bmpData.Stride / 3); //wspolrzedna y kolejnego punktu //Wartosci kolorow zapisane sa w kolejnosci Blue, Green, Red //Odczytaj wartosc punktu (zamien na odcienie szarosci) int value = (int)(0.299 * pixelValues[3 * i + 2] + 0.587 * pixelValues[3 * i + 1] + 0.114 * pixelValues[3 * i]); value += (int)errors[x + shift, y]; if (value > threshold) { //wartosc punktu wieksza od progu - zamien na kolor bialy pixelValues[3 * i] = 255; pixelValues[3 * i + 1] = 255; pixelValues[3 * i + 2] = 255; error = value - 255; } else { //wartosc punktu nie wieksza od progu - zamien na kolor czarny pixelValues[3 * i] = 0; pixelValues[3 * i + 1] = 0; pixelValues[3 * i + 2] = 0; error = value; } //rozpropaguj blad zgodnie z algorytmem Stucki'ego errors[x + 1 + shift, y] += (error * 8.0 / 42.0); errors[x + 2 + shift, y] += (error * 4.0 / 42.0); errors[x - 2 + shift, y + 1] += (error * 2.0 / 42.0); errors[x - 1 + shift, y + 1] += (error * 4.0 / 42.0); errors[x + shift, y + 1] += (error * 8.0 / 42.0); errors[x + 1 + shift, y + 1] += (error * 4.0 / 42.0); errors[x + 2 + shift, y + 1] += (error * 2.0 / 42.0); errors[x - 2 + shift, y + 2] += (error * 1.0 / 42.0); errors[x - 1 + shift, y + 2] += (error * 2.0 / 42.0); errors[x + shift, y + 2] += (error * 4.0 / 42.0); errors[x + 1 + shift, y + 2] += (error * 2.0 / 42.0); errors[x + 2 + shift, y + 2] += (error * 1.0 / 42.0); } //Wczytaj przetworzony obraz System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, bmpData.Scan0, pixelValues.Length); bitmap.UnlockBits(bmpData); picture.Refresh(); } } }