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();
}
}
}

