Artentus schrieb:
@diylab
Ihr habts mit .Net geschafft, solche Ergebnisse bei 100 Pixel Radius zu erreichen?
Moin,
ja - aber nur mit dem STACKBLUR (der Code wurde weiter oben schon einmal gepostet).
Hier meine Klasse:
C-Quellcode
- using System;
- using System.Diagnostics;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Runtime.InteropServices;
- namespace BlurTest
- {
- public class ImageTools
- {
- /// <summary>
- /// Load image without leaving the file locked
- /// </summary>
- /// <param name="fileName">Source path</param>
- /// <returns>Image from stream</returns>
- public static Image LoadBitmap(string fileName)
- {
- using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
- return Image.FromStream(stream);
- }
- /// <summary>
- /// Save blurred bitmap
- /// </summary>
- /// <param name="SourceImage">Source bitmap</param>
- /// <param name="filePath">Target path</param>
- public static void SaveBlur(Bitmap SourceImage, string filePath)
- {
- SourceImage.Save(filePath);
- }
- /// <summary>
- /// Stackblur
- /// </summary>
- /// <param name="SourceImage">Source bitmap</param>
- /// <param name="BlurRadius">Blur radius</param>
- public static Bitmap FastBlur(Bitmap SourceImage, int BlurRadius)
- {
- if (BlurRadius > 0)
- {
- // Start stopwatch
- Stopwatch watch = Stopwatch.StartNew();
- var rct = new Rectangle(0, 0, SourceImage.Width, SourceImage.Height);
- var dest = new int[rct.Width * rct.Height];
- var source = new int[rct.Width * rct.Height];
- var bits = SourceImage.LockBits(rct, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
- Marshal.Copy(bits.Scan0, source, 0, source.Length);
- SourceImage.UnlockBits(bits);
- int w = rct.Width;
- int h = rct.Height;
- int wm = w - 1;
- int hm = h - 1;
- int wh = w * h;
- int div = BlurRadius + BlurRadius + 1;
- var r = new int[wh];
- var g = new int[wh];
- var b = new int[wh];
- int rsum, gsum, bsum, x, y, i, p1, p2, yi;
- var vmin = new int[max(w, h)];
- var vmax = new int[max(w, h)];
- var dv = new int[256 * div];
- for (i = 0; i < 256 * div; i++)
- {
- dv[i] = (i / div);
- }
- int yw = yi = 0;
- for (y = 0; y < h; y++)
- { // blur horizontal
- rsum = gsum = bsum = 0;
- for (i = -BlurRadius; i <= BlurRadius; i++)
- {
- int p = source[yi + min(wm, max(i, 0))];
- rsum += (p & 0xff0000) >> 16;
- gsum += (p & 0x00ff00) >> 8;
- bsum += p & 0x0000ff;
- }
- for (x = 0; x < w; x++)
- {
- r[yi] = dv[rsum];
- g[yi] = dv[gsum];
- b[yi] = dv[bsum];
- if (y == 0)
- {
- vmin[x] = min(x + BlurRadius + 1, wm);
- vmax[x] = max(x - BlurRadius, 0);
- }
- p1 = source[yw + vmin[x]];
- p2 = source[yw + vmax[x]];
- rsum += ((p1 & 0xff0000) - (p2 & 0xff0000)) >> 16;
- gsum += ((p1 & 0x00ff00) - (p2 & 0x00ff00)) >> 8;
- bsum += (p1 & 0x0000ff) - (p2 & 0x0000ff);
- yi++;
- }
- yw += w;
- }
- for (x = 0; x < w; x++)
- { // blur vertical
- rsum = gsum = bsum = 0;
- int yp = -BlurRadius * w;
- for (i = -BlurRadius; i <= BlurRadius; i++)
- {
- yi = max(0, yp) + x;
- rsum += r[yi];
- gsum += g[yi];
- bsum += b[yi];
- yp += w;
- }
- yi = x;
- for (y = 0; y < h; y++)
- {
- dest[yi] = (int)(0xff000000u | (uint)(dv[rsum] << 16) | (uint)(dv[gsum] << 8) | (uint)dv[bsum]);
- if (x == 0)
- {
- vmin[y] = min(y + BlurRadius + 1, hm) * w;
- vmax[y] = max(y - BlurRadius, 0) * w;
- }
- p1 = x + vmin[y];
- p2 = x + vmax[y];
- rsum += r[p1] - r[p2];
- gsum += g[p1] - g[p2];
- bsum += b[p1] - b[p2];
- yi += w;
- }
- }
- // copy back to image
- var bits2 = SourceImage.LockBits(rct, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
- Marshal.Copy(dest, 0, bits2.Scan0, dest.Length);
- SourceImage.UnlockBits(bits);
- // Stop stopwatch
- watch.Stop();
- Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " ms");
- return SourceImage;
- }
- else
- {
- return null;
- }
- }
- private static int min(int a, int b) { return Math.Min(a, b); }
- private static int max(int a, int b) { return Math.Max(a, b); }
- }
- }
Und der Aufruf:
VB.NET-Quellcode
Da komme ich wie gesagt bei 130px Radius auf 3 Sekunden für das erste Bild und 1,7 Sekunden für zweite Bild.
Ich habe zum Test die Stoppuhr quick and dirty einfach in die Methode geballert.
Ich bin mir sicher, wenn Du da wieder hand anlegst und das Marshalcopy rausschmeist und die Hauptschleifen für vertikal und horizontal parallelisierst, kommen wir auf min. 1/4 der Gesamtzeit!
Hat auch beim Sharpen echt Wunder bewirkt (danke nochmals).
Allein kriege ich das aber nicht hin - da verknoten sich meine Synapsen ..
Aber das Resultat bei 130px ist für meine Begriffe prima.
LG,
Bruno