Nadesłany przez Tomasz Lubiński, 18 lutego 2013 22:28
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.
retinex/Form1.cs:
//Retinex
//(c) 2013 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.Windows.Forms.DataVisualization.Charting;
using System.Drawing.Imaging;
namespace retinex
{
public partial class Form1 : Form
{
/// <summary>
/// Obraz zrodlowy i wynikowy
/// </summary>
private Image zrodlo;
private Obraz wynik;
/// <summary>
/// Zainicjuj
/// </summary>
public Form1()
{
zrodlo = 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)
{
zrodlo = new Bitmap(dlg.OpenFile());
wynik = new Obraz();
wynik.obrazWynikowy.Image = new Bitmap(dlg.OpenFile());
wynik.obrazWynikowy.Height = wynik.obrazWynikowy.Image.Height;
wynik.obrazWynikowy.Width = wynik.obrazWynikowy.Image.Width;
wynik.obrazWynikowy.Refresh();
wynik.ClientSize = new System.Drawing.Size(wynik.obrazWynikowy.Width + 24, wynik.obrazWynikowy.Height + 32);
wynik.Show();
wynik.Refresh();
}
dlg.Dispose();
}
/// <summary>
/// Zainicjuj wartosci w tabeli skal
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
wagi.Rows.Add();
wagi.Rows.Add();
wagi.Rows.Add();
wagi.Rows[0].Cells[0].Value = 0.33;
wagi.Rows[1].Cells[0].Value = 0.33;
wagi.Rows[2].Cells[0].Value = 0.34;
wagi.Rows[0].Cells[1].Value = 5;
wagi.Rows[1].Cells[1].Value = 50;
wagi.Rows[2].Cells[1].Value = 250;
}
/// <summary>
/// Wieloskalowy retinex z przywracaniem kolorow (MSR with Color Restoration)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void retinex_Click(object sender, EventArgs e)
{
//Nie rob nic wiecej jezeli obraz jest jeszcze niewczytany
if (zrodlo == null)
{
return;
}
//Pobierz wartosci alfa i beta
double alfa = Double.Parse(this.alfa.Text);
double beta = Double.Parse(this.beta.Text);
//Kopiuj obrazek zrodlowy
Bitmap bitmap = (Bitmap)zrodlo.Clone();
//Pobierz wartosc wszystkich punktow obrazu
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
byte[] original = new byte[Math.Abs(bmpData.Stride) * bitmap.Height];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, original, 0, original.Length);
//Utworz tablice z wynikiem
double[][][] retinexResult = new double[3][][];
retinexResult[0] = new double[bitmap.Height][];
retinexResult[1] = new double[bitmap.Height][];
retinexResult[2] = new double[bitmap.Height][];
for (var i = 0; i < bitmap.Height; i++)
{
retinexResult[0][i] = new double[bitmap.Width];
retinexResult[1][i] = new double[bitmap.Width];
retinexResult[2][i] = new double[bitmap.Width];
}
//dla wszystkich skal (MSR - multi scale retinex)
for (var s = 0; s < wagi.Rows.Count-1; s++)
{
byte[] blured = (byte[])original.Clone();
//Pobierz wspolczynniki do rozmywania gaussowskiego
double[] coefs = gaussian_coefs(Double.Parse(wagi.Rows[s].Cells[1].Value.ToString()));
//Rozmywaj gaussowsko w poziomie
for (int i = 0; i < bitmap.Height; i++)
{
gausssmooth(blured, i * Math.Abs(bmpData.Stride) + 0, 3, Math.Abs(bmpData.Stride) / 3, coefs);
gausssmooth(blured, i * Math.Abs(bmpData.Stride) + 1, 3, Math.Abs(bmpData.Stride) / 3, coefs);
gausssmooth(blured, i * Math.Abs(bmpData.Stride) + 2, 3, Math.Abs(bmpData.Stride) / 3, coefs);
}
//Rozmywaj gaussowsko w pionie
for (int i = 0; i < Math.Abs(bmpData.Stride) / 3; i++)
{
gausssmooth(blured, i * 3 + 0, Math.Abs(bmpData.Stride), bitmap.Height, coefs);
gausssmooth(blured, i * 3 + 1, Math.Abs(bmpData.Stride), bitmap.Height, coefs);
gausssmooth(blured, i * 3 + 2, Math.Abs(bmpData.Stride), bitmap.Height, coefs);
}
//Retinex (SSR - single scale retinex)
double weight = Double.Parse(wagi.Rows[s].Cells[0].Value.ToString());
for (var i = 0; i < bitmap.Height; i++)
{
for (var j = 0; j < bitmap.Width; j++)
{
int index = i * Math.Abs(bmpData.Stride) + j * 3;
retinexResult[0][i][j] += weight * Math.Log((original[index + 0] + 1.0) / (blured[index + 0] + 1.0));
retinexResult[1][i][j] += weight * Math.Log((original[index + 1] + 1.0) / (blured[index + 1] + 1.0));
retinexResult[2][i][j] += weight * Math.Log((original[index + 2] + 1.0) / (blured[index + 2] + 1.0));
}
}
}
//Wyszukaj wartosci najmniejszej i najwiekszej
double min = retinexResult[0][0][0];
double max = min;
for (var i = 0; i < bitmap.Height; i++)
{
for (var j = 0; j < bitmap.Width; j++)
{
if (min > retinexResult[0][i][j])
min = retinexResult[0][i][j];
else if (max < retinexResult[0][i][j])
max = retinexResult[0][i][j];
if (min > retinexResult[1][i][j])
min = retinexResult[1][i][j];
else if (max < retinexResult[1][i][j])
max = retinexResult[1][i][j];
if (min > retinexResult[2][i][j])
min = retinexResult[2][i][j];
else if (max < retinexResult[2][i][j])
max = retinexResult[2][i][j];
}
}
//Wyswietl rezultat
double range = (max - min) / 255.0;
for (var i = 0; i < bitmap.Height; i++)
{
for (var j = 0; j < bitmap.Width; j++)
{
//Przywracanie kolorow (MSRCR - multiscale retinex with color restoration)
int index = i * Math.Abs(bmpData.Stride) + j * 3;
double sum = original[index + 0] + original[index + 1] + original[index + 2] + 3.0;
double value = retinexResult[0][i][j] * beta * Math.Log(alfa * (original[index + 0] + 1.0) / sum);
value = (value - min) / range;
if (value > 255)
original[index + 0] = 255;
else if (value < 0)
original[index + 0] = 0;
else
original[index + 0] = (byte)value;
value = retinexResult[1][i][j] * beta * Math.Log(alfa * (original[index + 1] + 1.0) / sum);
value = (value - min) / range;
if (value > 255)
original[index + 1] = 255;
else if (value < 0)
original[index + 1] = 0;
else
original[index + 1] = (byte)value;
value = retinexResult[2][i][j] * beta * Math.Log(alfa * (original[index + 2] + 1.0) / sum);
value = (value - min) / range;
if (value > 255)
original[index + 2] = 255;
else if (value < 0)
original[index + 2] = 0;
else
original[index + 2] = (byte)value;
}
}
System.Runtime.InteropServices.Marshal.Copy(original, 0, bmpData.Scan0, original.Length);
bitmap.UnlockBits(bmpData);
wynik.obrazWynikowy.Image = bitmap;
}
/// <summary>
/// Papers: "Recursive Implementation of the gaussian filter.",
/// Ian T. Young , Lucas J. Van Vliet, Signal Processing 44, Elsevier 1995.
/// </summary>
/// <param name="sigma"></param>
/// <returns></returns>
private double[] gaussian_coefs(double sigma)
{
double[] result = new double[5];
double q = 0;
if (sigma >= 2.5)
q = 0.98711 * sigma - 0.96330;
else if ((sigma >= 0.5) && (sigma < 2.5))
q = 3.97156 - 4.14554 * Math.Sqrt(1.0 - 0.26891 * sigma);
else
q = 0.1147705018520355224609375;
double q2 = q * q;
double q3 = q * q2;
result[0] = (1.57825+(2.44413*q)+(1.4281 *q2)+(0.422205*q3));
result[1] = (2.44413*q)+(2.85619*q2)+(1.26661 *q3);
result[2] = -((1.4281*q2)+(1.26661 *q3));
result[3] = (0.422205*q3);
result[4] = (1.0-((result[1]+result[2]+result[3])/result[0]));
return result;
}
private void gausssmooth(byte[] img, int shift, int rowstride, int size, double[] coefs)
{
// forward pass
double[] w1 = new double[size+3];
double[] w2 = new double[size+6];
w1[0] = img[shift];
w1[1] = img[shift];
w1[2] = img[shift];
for(int i=0, n=3; i<size; i++, n++)
{
w1[n] = (coefs[4]*img[shift+i*rowstride] +
((coefs[1]*w1[n-1] +
coefs[2]*w1[n-2] +
coefs[3]*w1[n-3] ) / coefs[0]));
}
w1[size+0] = w1[size-1];
w1[size+1] = w1[size-2];
w1[size+2] = w1[size-3];
// backward pass
w2[size+0]= w1[size+0];
w2[size+1]= w1[size+1];
w2[size+2]= w1[size+2];
w2[size+3]= w1[size+2];
w2[size+4]= w1[size+2];
w2[size+5]= w1[size+2];
for(int i=size-1, n=i+3; i>=0; i--, n--)
{
w2[n] = (coefs[4]*w1[n] +
((coefs[1]*w2[n+1] +
coefs[2]*w2[n+2] +
coefs[3]*w2[n+3] ) / coefs[0]));
img[shift + i * rowstride] = (byte)w2[n];
}
}
}
}

