algorytm.org

Implementacja w C#

Baza Wiedzy
wersja offline serwisu przeznaczona na urządzenia z systemem Android
Darowizny
darowiznaWspomóż rozwój serwisu
Nagłówki RSS
Artykuły
Implementacje
Komentarze
Forum
Bookmarki






Sonda
Implementacji w jakim języku programowania poszukujesz?

Tilt-Shift - efekt makiety - Implementacja w C#
Ocena użytkownikóww: *****  / 0
SłabyŚwietny
Nadesłany przez Tomasz Lubiński, 06 czerwca 2012 16:30
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.

tilt_shift/tilt_shift/Form1.cs:
//Tilt Shift
//(c) 2012 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 tilt_shift
{
    public partial class Form1 : Form
    {

        /// <summary>
        /// Obraz zrodlowy
        /// </summary>
        private Image zrodlo;
        private int bytesPerPixel;

        /// <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|pliki png (*.png)|*.png|wszystkie pliki (*.*)|*.*";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                zrodlo = new Bitmap(dlg.OpenFile());
                bytesPerPixel = Image.GetPixelFormatSize(zrodlo.PixelFormat) / 8;

                obraz.Image = new Bitmap(dlg.OpenFile());
                obraz.Height = obraz.Image.Height;
                obraz.Width = obraz.Image.Width;
                this.ClientSize = new System.Drawing.Size(Math.Max(obraz.Width + 32, 374), obraz.Height + 155);
                info.Text = "Wskaż na zdjęciu środek obszaru 'in-focus'";
            }
            dlg.Dispose();
        }

        /// <summary>
        /// Utworz tablice ze wspolczynnikami do rozmycia Gaussowskiego
        /// </summary>
        /// <param name="factor">wspolczynnik rozmycia</param>
        /// <param name="width">maksymalna wielkosc tablicy</param>
        /// <returns>tablica ze wspolczynnikami do rozmycia Gaussowskiego</returns>
        private double[] gaussianArray(double factor, int width)
        {
            double[] result = new double[width];
	        for (var i=0; i<width; i++)
	        {
                result[i] = (1 / (Math.Sqrt(2.0 * Math.PI) * factor)) * Math.Exp(-(i * i) / (2.0 * factor * factor));
                if (result[i] < 0.003)
		        {
                    double[] subArray = new double[i];
                    for (int j = 0; j < i; j++)
                    {
                        subArray[j] = result[j];
                    }
                    return subArray;
		        }
        	}
	        return result;
        }

        /// <summary>
        /// Rozmyj pixel w poziomie
        /// </summary>
        /// <param name="y">indeks linii do rozmycia</param>
        /// <param name="blurArray">tablica wspolczynnikow rozmycia</param>
        /// <param name="pixelValues">tablica z wartosciami pikseli</param>
        /// <param name="stride">szerokosc linii danych z pikselami</param>
        /// <param name="width">szerokosc obrazu</param>
        private void blurHorizontal(int y, double[] blurArray, byte[] pixelValues, int stride, int width)
        {
            double[] pixelBytes = new double[bytesPerPixel];
            for (var x = 0; x < width; x++)
            {
                int index = y * stride + x * bytesPerPixel;
                for (int i = 0; i < bytesPerPixel; i++)
                {
                    pixelBytes[i] = pixelValues[index + i] * blurArray[0];
                }
                double sum = blurArray[0];
                for (var k = 1; k < blurArray.Length; k++)
                {
                    if (x + k >= width)
                    {
                        index = y * stride + (x + k + 1 - width) * bytesPerPixel;
                    }
                    else
                    {
                        index = y * stride + (x + k) * bytesPerPixel;
                    }
                    for (int i = 0; i < bytesPerPixel; i++)
                    {
                        pixelBytes[i] += pixelValues[index + i] * blurArray[k];
                    }
                    if (x - k < 0)
                    {
                        index = y * stride + Math.Abs(x - k) * bytesPerPixel;
                    }
                    else
                    {
                        index = y * stride + (x - k) * bytesPerPixel;
                    }
                    for (int i = 0; i < bytesPerPixel; i++)
                    {
                        pixelBytes[i] += pixelValues[index + i] * blurArray[k];
                    }
                    sum += 2 * blurArray[k];
                }
                index = y * stride + x * bytesPerPixel;
                for (int i = 0; i < bytesPerPixel; i++)
                {
                    pixelValues[index + i] = (byte)(pixelBytes[i] / sum);
                }
            }
        }

        /// <summary>
        /// Rozmyj pixel w pionie
        /// </summary>
        /// <param name="y">indeks linii do rozmycia</param>
        /// <param name="blurArray">tablica wspolczynnikow rozmycia</param>
        /// <param name="pixelValues">tablica z wartosciami pikseli</param>
        /// <param name="stride">szerokosc linii danych z pikselami</param>
        /// <param name="width">szerokosc obrazu</param>
        private void blurVertical(int y, double[] blurArray, byte[] pixelValues, int stride, int width, int height)
        {
            double[] pixelBytes = new double[bytesPerPixel];
            for (var x = 0; x < width; x++)
            {
                int index = y * stride + x * bytesPerPixel;
                for (int i = 0; i < bytesPerPixel; i++)
                {
                    pixelBytes[i] = pixelValues[index + i] * blurArray[0];
                }
                double sum = blurArray[0];
                for (var k = 1; k < blurArray.Length; k++)
                {
                    if (y + k >= height)
                    {
                        index = (y + k + 1 - height) * stride + x * bytesPerPixel;
                    }
                    else
                    {
                        index = (y + k) * stride + x * bytesPerPixel;
                    }
                    for (int i = 0; i < bytesPerPixel; i++)
                    {
                        pixelBytes[i] += pixelValues[index + i] * blurArray[k];
                    }
                    if (y - k < 0)
                    {
                        index = Math.Abs(y - k) * stride + x * bytesPerPixel;
                    }
                    else
                    {
                        index = (y - k) * stride + x * bytesPerPixel;
                    }
                    for (int i = 0; i < bytesPerPixel; i++)
                    {
                        pixelBytes[i] += pixelValues[index + i] * blurArray[k];
                    }
                    sum += 2 * blurArray[k];
                }
                index = y * stride + x * bytesPerPixel;
                for (int i = 0; i < bytesPerPixel; i++)
                {
                    pixelValues[index + i] = (byte)(pixelBytes[i] / sum);
                }
            }
        }

        /// <summary>
        /// Efekt Tilt-Shift
        /// </summary>
        private void obraz_MouseDown(object sender, MouseEventArgs e)
        {
            //Nie rob nic jezeli obraz jest jeszcze niewczytany
            if (zrodlo == null)
            {
                return;
            }

            //Kopiuj obrazek zrodlowy
            Bitmap bitmap = (Bitmap)zrodlo.Clone();
            obraz.Image = bitmap;
    
            //Pobierz liczbe bajtow na punkt obrazu
            int bytesPerPixel = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8;
            double[] pixelBytes = new double[bytesPerPixel];

            //Pobierz wartosc wszystkich punktow obrazu
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, obraz.Width, obraz.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
            byte[] pixelValues = new byte[Math.Abs(bmpData.Stride) * obraz.Height];
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, pixelValues, 0, pixelValues.Length);

            //Dane obszarów
            int width = obraz.Width;
            int height = obraz.Height;
            int inFocusHeight = int.Parse(this.inFocusHeight.Text);
            int outFocusStartTop = Math.Max(e.Y - inFocusHeight / 2, 0);
            int outFocusStartDown = Math.Min(e.Y + inFocusHeight / 2, height);
            double outFocusHeight = e.Y > height / 2 ? outFocusStartTop : (height - outFocusStartDown);
            double outFocusBlur = double.Parse(blur.Text) - 0.1;

            //Rozmyj w poziomie obraz nad obszarem ostrym
            for (int y=0; y<outFocusStartTop; y++)
	        {
		        double factor = (outFocusStartTop-y)/outFocusHeight;
                double[] blurArray = gaussianArray(factor * outFocusBlur + 0.1, width);
                blurHorizontal(y, blurArray, pixelValues, bmpData.Stride, width);
	        }

            //Rozmyj w poziomie obraz pod obszarem ostrym
            for (int y = outFocusStartDown; y < height; y++)
            {
                double factor = (y - outFocusStartDown) / outFocusHeight;
                double[] blurArray = gaussianArray(factor * outFocusBlur + 0.1, width);
                blurHorizontal(y, blurArray, pixelValues, bmpData.Stride, width);
            }

            //Rozmyj w pionie obraz nad obszarem ostrym
            for (int y = 0; y < outFocusStartTop; y++)
            {
                double factor = (outFocusStartTop - y) / outFocusHeight;
                double[] blurArray = gaussianArray(factor * outFocusBlur + 0.1, width);
                blurVertical(y, blurArray, pixelValues, bmpData.Stride, width, height);
            }

            //Rozmyj w pionie obraz pod obszarem ostrym
            for (int y = outFocusStartDown; y < height; y++)
            {
                double factor = (y - outFocusStartDown) / outFocusHeight;
                double[] blurArray = gaussianArray(factor * outFocusBlur + 0.1, width);
                blurVertical(y, blurArray, pixelValues, bmpData.Stride, width, height);
            }

            System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, bmpData.Scan0, pixelValues.Length);
            bitmap.UnlockBits(bmpData);
        }
    }
}
Dodaj komentarz