using System; using System.IO; using System.Windows; using System.Windows.Input; using System.Windows.Controls; using System.Windows.Media.Imaging; using System.Windows.Media; using FluxJpeg.Core; using FluxJpeg.Core.Encoder; namespace BV2_ESA_Festenberg { public partial class MainPage : UserControl { WriteableBitmap i0w; WriteableBitmap i1w; WriteableBitmap i2w; WriteableBitmap i3wt; WriteableBitmap i3w; WriteableBitmap i4w; WriteableBitmap i5w; WriteableBitmap i5wo; WriteableBitmap i5wl; int iSize; int iWidth; int iHeight; Boolean isReady = false; public MainPage() { InitializeComponent(); // default bild laden loadImage("/Images/emma.JPG"); } private void loadImage(String quelle) { isReady = false; Uri uri = new Uri(quelle, UriKind.Relative); BitmapImage bild = new BitmapImage(); bild.CreateOptions = BitmapCreateOptions.None; bild.ImageOpened += ImageOpened; bild.UriSource = uri; } private void ImageOpened(object sender, RoutedEventArgs e) { BitmapImage bild = (BitmapImage)sender; // Daten und leere Bilder für die Tabs bereitstellen i0w = new WriteableBitmap(bild); i5w = new WriteableBitmap(bild); iWidth = i0w.PixelWidth; iHeight = i0w.PixelHeight; iSize = iWidth * iHeight; i1w = new WriteableBitmap(iWidth, iHeight); // alle Steuerelemente auf Ausgangszustand rotGewicht.Text = "0"; rotSlider.Value = 0; gruenGewicht.Text = "0"; gruenSlider.Value = 0; blauGewicht.Text = "0"; blauSlider.Value = 0; tiefpass.SelectedIndex = 0; tiefpassGewichtName.Text = "1"; tiefpassGewichtSlider.Value = 1; hochpass.SelectedIndex = 0; schwelleName.Text = "128"; schwelleSlider.Value = 128; schwelleCheck.IsChecked = false; konturBildCheck.IsChecked = false; // Tab Original mit neuem Bild anzeigen i0w.Invalidate(); i0.Source = i0w; // Signal für fertige Bereitstellung aller Sourcen isReady = true; // restliche Tabs füllen aendereFarbe(); filtern(); schwelle(); // 1. Reg anzeigen zeigeTab(0); } // Tab aufrufen private void zeigeTab(int index) { if (tabControl1 != null) { tabControl1.SelectedIndex = index; border1.Background = null; border2.Background = null; border3.Background = null; border4.Background = null; border5.Background = null; konturAuffordLabel.Foreground = new SolidColorBrush(Color.FromArgb(255,0,0,0)); switch(index) { case 0: border1.Background = new SolidColorBrush(Color.FromArgb(128, 192, 192, 192)); break; case 1: border2.Background = new SolidColorBrush(Color.FromArgb(128, 192, 192, 192)); break; case 2: border3.Background = new SolidColorBrush(Color.FromArgb(128, 192, 192, 192)); break; case 3: border4.Background = new SolidColorBrush(Color.FromArgb(128, 192, 192, 192)); break; case 4: border5.Background = new SolidColorBrush(Color.FromArgb(128, 192, 192, 192)); konturAuffordLabel.Foreground = new SolidColorBrush(Color.FromArgb(255, 200, 20, 20)); break; } } } private void loadEigenesBild(object sender, RoutedEventArgs e) { OpenFileDialog loadImage = new OpenFileDialog(); loadImage.Filter = "nur JPEG-Bilder ( *.jpg, *jpeg)|*.jpg;*.jpeg"; loadImage.FilterIndex = 1; loadImage.Multiselect = false; bool? userClickedOK = loadImage.ShowDialog(); if (userClickedOK == true) { Stream stream = loadImage.File.OpenRead(); BitmapImage eigenesBild = new BitmapImage(); eigenesBild.SetSource(stream); stream.Close(); ImageOpened(eigenesBild, e); demoImage.SelectedIndex = 5; } } private void changeDemoImage(object sender, SelectionChangedEventArgs e) { if (demoImage != null) { switch (demoImage.SelectedIndex) { case 0: loadImage("/Images/emma.JPG"); break; case 1: loadImage("/Images/mia.JPG"); break; case 2: loadImage("/Images/jonas.JPG"); break; case 3: loadImage("/Images/sara.JPG"); break; case 4: loadImage("/Images/antje.JPG"); break; } } } // Farbe ändern private void aendereFarbeEvent(object sender, RoutedPropertyChangedEventArgs e) { if (isReady) { int rGew = (int)rotSlider.Value; int gGew = (int)gruenSlider.Value; int bGew = (int)blauSlider.Value; rotGewicht.Text = rGew.ToString(); gruenGewicht.Text = gGew.ToString(); blauGewicht.Text = bGew.ToString(); aendereFarbe(); } } private void aendereFarbe() { zeigeTab(1); LayoutRoot.Cursor = Cursors.Wait; i2w = new WriteableBitmap(iWidth, iHeight); for (int i = 0; i < iSize; i++) { //Farbwerte extrahieren int r = (i0w.Pixels[i] >> 16) & 255; int g = (i0w.Pixels[i] >> 8) & 255; int b = (i0w.Pixels[i] >> 0) & 255; //Farbwerte verändern und begrenzen r = r + (int)rotSlider.Value; if (r > 255) r = 255; if (r < 0) r = 0; g = g + (int)gruenSlider.Value; if (g > 255) g = 255; if (g < 0) g = 0; b = b + (int)blauSlider.Value; if (b > 255) b = 255; if (b < 0) b = 0; // geänderte Pixel in neues Bild i1w.Pixels[i] = -16777216 | r << 16 | g << 8 | b; // Grauwerte berechnen + bereitstellen int gr = (r + g + b) / 3; i2w.Pixels[i] = -16777216 | gr << 16 | gr << 8 | gr; } // anzeigen auf Register "2. Farbe" i1.Source = i1w; LayoutRoot.Cursor = Cursors.Arrow; } // filtern private void filternSliderEvent(object sender, RoutedPropertyChangedEventArgs e) { if (isReady) { int fGew = (int)tiefpassGewichtSlider.Value; tiefpassGewichtName.Text = fGew.ToString(); filtern(); zeigeTab(2); } } private void filternComboEvent(object sender, SelectionChangedEventArgs e) { filtern(); zeigeTab(2); } private void aktualisiereFilterBild(object sender, RoutedEventArgs e) { filtern(); zeigeTab(2); } private void filtern() { if (isReady) { aendereFarbe(); i3w = new WriteableBitmap(iWidth, iHeight); i3wt = new WriteableBitmap(iWidth, iHeight); LayoutRoot.Cursor = Cursors.Wait; // Tiefpass switch (tiefpass.SelectedIndex) { case 0: // kein Tiefpass i3wt=i2w; break; case 1: // 3x3 Tiefpass berechneTiefpass(3, (int)tiefpassGewichtSlider.Value); break; case 2: // 5x5 Tiefpass berechneTiefpass(5, (int)tiefpassGewichtSlider.Value); break; case 3: // 7x7 Tiefpass berechneTiefpass(7, (int)tiefpassGewichtSlider.Value); break; case 4: // 9x9 Tiefpass berechneTiefpass(9, (int)tiefpassGewichtSlider.Value); break; case 5: // 11x11Tiefpass berechneTiefpass(11, (int)tiefpassGewichtSlider.Value); break; case 6: // 13x13 Tiefpass berechneTiefpass(13, (int)tiefpassGewichtSlider.Value); break; } // Hochpass switch (hochpass.SelectedIndex) { case 0: // kein Hochpass i3w = i3wt; break; case 1: // Prewitt berechneHochpass(1,1,1); break; case 2: // Sobel berechneHochpass(1, 2, 1); break; case 3: berechneHochpass(2, 4, 2); break; } i2w.Invalidate(); i2.Source = i3w; schwelle(); LayoutRoot.Cursor = Cursors.Arrow; } } // N für Matrixbreite, G für Mittengewicht, Rückgabe in i3wt (global --> Hilfsbild als Eingang für den Hochpass) private void berechneTiefpass(int N, int G) { int Nh = N / 2; int divisor; int sum; for (int i = 0; i < iSize; i++) { sum = 0; divisor = G; for (int n = -Nh; n <= Nh; n++) { for (int m = -Nh; m <= Nh; m++) { int p = i + n * iWidth + m; if (n == 0 && m == 0) sum += (i2w.Pixels[i] & 255) * G; // Mittengewicht if (p < (Nh * iWidth) || p > ((iHeight - Nh) * iWidth) || (p % iWidth) < Nh || (iWidth - (p % iWidth)) <= Nh) continue; // Randbehandlung else { sum += i2w.Pixels[p] & 255; divisor++; } } } int gr = sum/divisor; i3wt.Pixels[i] = -16777216 | gr << 16 | gr << 8 | gr; } } private void berechneHochpass(int a1, int a2, int a3) { int rand = 255; int sumLinks; int sumRechts; int sumOben; int sumUnten; int diff; int divisor = a1 + a2 + a3; for (int i = 0; i < iSize; i++) { // Rand ignorieren und auf "rand" setzen if (i < iWidth || i > ((iHeight - 1) * iWidth) || (i % iWidth) == 0 || (iWidth - (i % iWidth)) == 1) { i3w.Pixels[i] = -16777216 | rand << 16 | rand << 8 | rand; continue; } // Balken mit Gewicht summieren sumLinks = (i3wt.Pixels[i - iWidth - 1] & 255) * a1 + (i3wt.Pixels[i - 1] & 255) * a2 + (i3wt.Pixels[i + iWidth - 1] & 255) * a3; sumRechts = (i3wt.Pixels[i - iWidth + 1] & 255) * a1 + (i3wt.Pixels[i + 1] & 255) * a2 + (i3wt.Pixels[i + iWidth + 1] & 255) * a3; sumOben = (i3wt.Pixels[i - iWidth - 1] & 255) * a1 + (i3wt.Pixels[i - iWidth] & 255) * a2 + (i3wt.Pixels[i - iWidth + 1] & 255) * a3; sumUnten = (i3wt.Pixels[i + iWidth - 1] & 255) * a1 + (i3wt.Pixels[i + iWidth] & 255) * a2 + (i3wt.Pixels[i + iWidth + 1] & 255) * a3; // Differenz bilden, begrenzen und ausgeben Double diff_v = sumLinks - sumRechts; Double diff_h = sumOben - sumUnten; diff = Convert.ToInt32(Math.Sqrt(diff_h * diff_h + diff_v * diff_v)); if (diff > 255) diff = 255; i3w.Pixels[i] = -16777216 | diff << 16 | diff << 8 | diff; } } // schwelle private void schwelleSliderEvent(object sender, RoutedPropertyChangedEventArgs e) { if (schwelleName != null && schwelleSlider != null) { int schw = (int)schwelleSlider.Value; schwelleName.Text = schw.ToString(); schwelle(); zeigeTab(3); } } private void schwelleCheckEvent(object sender, RoutedEventArgs e) { schwelle(); zeigeTab(3); } private void aktualisiereSchwellenBild(object sender, RoutedEventArgs e) { schwelle(); zeigeTab(3); } private void schwelle() { if (isReady) { i4w = new WriteableBitmap(iWidth, iHeight); LayoutRoot.Cursor = Cursors.Wait; bool invert = (bool)schwelleCheck.IsChecked; for (int i = 0; i < iSize; i++) { int sw = 0; int gr = i3w.Pixels[i] & 255; if (!invert && gr < (int)schwelleSlider.Value) sw = 255; if ( invert && gr > (int)schwelleSlider.Value) sw = 255; i4w.Pixels[i] = -16777216 | sw << 16 | sw << 8 | sw; } i3.Source = i4w; i4.Source = i4w; i5.Source = i0w; LayoutRoot.Cursor = Cursors.Arrow; } } // kontur (Ausgangsbild steht in iw4, iw5 für sw-Bild zum anklicken, iw5o Originalbild private void konturMausEvent (object sender, MouseButtonEventArgs e) { schwelle(); i5w = new WriteableBitmap((BitmapSource)i4w); i5wo = new WriteableBitmap((BitmapSource)i0w); i5wl = new WriteableBitmap(iWidth, iHeight); // Klickpunkt auf Originalbild umrechnen double x = ((double)iWidth / (double)i4.ActualWidth) * e.GetPosition(i4).X ; double y = ((double)iHeight / (double)i4.ActualHeight) * e.GetPosition(i4).Y; int klick = iWidth * (int)y + (int)x; if (klick < 0) klick = 0; if (klick > iSize) klick = iSize - 2; zeigeTab(4); // Vorder-/Hintergrund bestimmen int vor; int hinter; int wo = i4w.Pixels[klick]&255; if (wo == 0) { vor = 0; hinter = 255; } else { vor = 255; hinter = 0; } // Rand auf Hintergrund setzen for (int i = 0; i < iSize; i++) { if (i < iWidth || i > ((iHeight - 1) * iWidth) || (i % iWidth) == 0 || (iWidth - (i % iWidth)) == 1) { if (klick == i) return; // bei Klick auf Rand abbrechen i4w.Pixels[i] = -16777216 | hinter << 16 | hinter << 8 | hinter; continue; } } // Startpunkt suchen while ((i4w.Pixels[klick - 1] & 255) != hinter) { klick--; } // kontur verfolgen int start = klick+iWidth; int chain = klick+iWidth; Char last_crack = 's'; do { if (konturNachbarCombo.SelectedIndex==0) // 4er-Nachbarschaft { switch (last_crack) { case 'e': if ((i4w.Pixels[chain - iWidth] & 255) == hinter) goto n; if ((i4w.Pixels[chain] & 255) == hinter) goto e; goto s; case 's': if ((i4w.Pixels[chain] & 255) == hinter) goto e; if ((i4w.Pixels[chain-1] & 255) == hinter) goto s; goto w; case 'w': if ((i4w.Pixels[chain - 1] & 255) == hinter) goto s; if ((i4w.Pixels[chain - iWidth - 1] & 255) == hinter) goto w; goto n; case 'n': if ((i4w.Pixels[chain - iWidth-1] & 255) == hinter) goto w; if ((i4w.Pixels[chain - iWidth] & 255) == hinter) goto n; goto e; } } else // 8er-Nachbarschaft { switch (last_crack) { case 'e': if ((i4w.Pixels[chain] & 255) == vor) goto s; if ((i4w.Pixels[chain - iWidth] & 255) == vor) goto e; goto n; case 's': if ((i4w.Pixels[chain - 1] & 255) == vor) goto w; if ((i4w.Pixels[chain] & 255) == vor) goto s; goto e; case 'w': if ((i4w.Pixels[chain - iWidth - 1] & 255) == vor) goto n; if ((i4w.Pixels[chain - 1] & 255) == vor) goto w; goto s; case 'n': if ((i4w.Pixels[chain - iWidth] & 255) == vor) goto e; if ((i4w.Pixels[chain - iWidth - 1] & 255) == vor) goto n; goto w; } } e: last_crack = 'e'; i5w.Pixels[chain] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wo.Pixels[chain] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wl.Pixels[chain] = -16777216 | 255 << 16 | 0 << 8 | 0; chain++; continue; s: last_crack = 's'; i5w.Pixels[chain - 1] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wo.Pixels[chain - 1] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wl.Pixels[chain - 1] = -16777216 | 255 << 16 | 0 << 8 | 0; chain += iWidth; continue; w: last_crack = 'w'; i5w.Pixels[chain - iWidth - 1] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wo.Pixels[chain - iWidth - 1] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wl.Pixels[chain - iWidth -1] = -16777216 | 255 << 16 | 0 << 8 | 0; chain--; continue; n: last_crack = 'n'; i5w.Pixels[chain - iWidth] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wo.Pixels[chain - iWidth] = -16777216 | 255 << 16 | 0 << 8 | 0; i5wl.Pixels[chain - iWidth] = -16777216 | 255 << 16 | 0 << 8 | 0; chain -= iWidth; continue; } while (start != chain); // Ergebnisse anzeigen i4.Source = i5w; bool ohneBild = (bool)konturBildCheck.IsChecked; if (ohneBild) i5.Source = i5wl; else i5.Source = i5wo; } private void zeigeKonturTab(object sender, MouseEventArgs e) { zeigeTab(4); } private void chainComboEvent(object sender, SelectionChangedEventArgs e) { schwelle(); zeigeTab(4); } private void konturEvent(object sender, RoutedEventArgs e) { zeigeTab(4); bool ohneBild = (bool)konturBildCheck.IsChecked; if (ohneBild) i5.Source = i5wl; else i5.Source = i5wo; } private void konturTabEvent(object sender, RoutedEventArgs e) { schwelle(); zeigeTab(4); } private void zeigeFarbbild(object sender, RoutedEventArgs e) { zeigeTab(1); } private void zeigeOriginal(object sender, RoutedEventArgs e) { zeigeTab(0); } private void zeigeFilterTab(object sender, MouseEventArgs e) { zeigeTab(2); } private void zeigeSchwellenTab(object sender, MouseEventArgs e) { zeigeTab(3); } private void zeigeFarbTab(object sender, MouseEventArgs e) { zeigeTab(1); } private void zeigeOriginalTab(object sender, MouseEventArgs e) { zeigeTab(0); } private void speicherErgebnis(object sender, RoutedEventArgs e) { SaveFileDialog saveImage = new SaveFileDialog(); saveImage.DefaultExt = ".jpg"; saveImage.Filter = "bitte Endung .jpg bei Filenamen eingeben|*.jpg;*.jpeg;"; //saveImage.Filter = "nur JPEG-Bilder ( *.jpg)|*.jpg;"; bool? dialogResult = saveImage.ShowDialog(); if (dialogResult == true) { using (Stream fs = saveImage.OpenFile()) { switch (speichernCombo.SelectedIndex) { case 0: EncodeJpeg(i5wo, fs); break; case 1: EncodeJpeg(i5wl, fs); break; case 2: EncodeJpeg(i5w, fs); break; case 3: EncodeJpeg(i2w, fs); break; case 4: EncodeJpeg(i3w, fs); break; case 5: EncodeJpeg(i4w, fs); break; } } } } // --> http://kodierer.blogspot.com/2009/11/convert-encode-and-decode-silverlight.html // --> FJCore-Ressourcen: http://fjcore.googlecode.com/svn/trunk/ public static void EncodeJpeg(WriteableBitmap bmp, Stream destinationStream) { // Init buffer in FluxJpeg format int w = bmp.PixelWidth; int h = bmp.PixelHeight; int[] p = bmp.Pixels; byte[][,] pixelsForJpeg = new byte[3][,]; // RGB colors pixelsForJpeg[0] = new byte[w, h]; pixelsForJpeg[1] = new byte[w, h]; pixelsForJpeg[2] = new byte[w, h]; // Copy WriteableBitmap data into buffer for FluxJpeg int i = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int color = p[i++]; pixelsForJpeg[0][x, y] = (byte)(color >> 16); // R pixelsForJpeg[1][x, y] = (byte)(color >> 8); // G pixelsForJpeg[2][x, y] = (byte)(color); // B } } // Encode Image as JPEG using the FluxJpeg library // and write to destination stream FluxJpeg.Core.ColorModel cm = new ColorModel { colorspace = ColorSpace.RGB }; FluxJpeg.Core.Image jpegImage = new FluxJpeg.Core.Image(cm, pixelsForJpeg); JpegEncoder encoder = new JpegEncoder(jpegImage, 95, destinationStream); encoder.Encode(); } } }