Frage

Dies soll das Histogramm eines 8-Bit-Graustufenbild berechnen. Mit einem 1024x770 Test Bitmap, endet bei etwa 890ms Create auf. Wie kann ich diese unterwegs (Art und Weise, Art und Weise) schneller?

EDIT: Ich sollte erwähnen, dass dies tatsächlich nicht das Histogramm berechnen noch, es wird nur die Werte aus dem Bitmap. Also habe ich wirklich fragen soll, was der schnellste Weg ist, alle Pixelwerte von einem 8-Bit-Graustufen-Bild abgerufen werden?

public class Histogram {

    private static int[,] values;

    public Histogram(Bitmap b) {
        var sw = Stopwatch.StartNew();
        values = new int[b.Width, b.Height];

        for (int w = 0; w < b.Width; ++w) {
            for (int h = 0; h < b.Height; ++h) {
                values[w, h] = b.GetPixel(w, h).R;
            }
        }

        sw.Stop();
        CreateTime = (sw.ElapsedTicks /
            (double)Stopwatch.Frequency) * 1000;
    }

    public double CreateTime { get; set; }
}
War es hilfreich?

Lösung

Der Grund Histogramm-Algorithmus ist so etwas wie:

int[] hist = new hist[256];
//at this point dont forget to initialize your vector with 0s.

for(int i = 0; i < height; ++i)
{
   for(int j = 0 ; j < widthl ++j)
   {
        hist[ image[i,j] ]++;
   }
}

Die Algorithmus Summe, wie viele Pixel mit dem Wert 0 Sie haben, wie viele mit dem Wert = 1 und so weiter. Die Grundidee ist es, den Pixelwert als Index für die Position des Histogramms zu verwenden, wo Sie zählen werden.

Ich habe eine Version dieses Algorithmus für C # nicht verwaltetem Code geschrieben (was schnell ist) Ich weiß nicht, ob als Ihr schneller ist, aber fühlen Sie sich frei und Test zu nehmen, hier ist der Code:

    public void Histogram(double[] histogram, Rectangle roi)
    {
        BitmapData data = Util.SetImageToProcess(image, roi);

        if (image.PixelFormat != PixelFormat.Format8bppIndexed)
            return;

        if (histogram.Length < Util.GrayLevels)
            return;

        histogram.Initialize();
        int width = data.Width;
        int height = data.Height;
        int offset = data.Stride - width;

        unsafe
        {
            byte* ptr = (byte*)data.Scan0;

            for (int y = 0; y < height; ++y)
            {
                for (int x = 0; x < width; ++x, ++ptr)
                    histogram[ptr[0]]++;

                ptr += offset;
            }
        }
        image.UnlockBits(data);         
    }

    static public BitmapData SetImageToProcess(Bitmap image, Rectangle roi)
    {
        if (image != null)
            return image.LockBits(
                roi,
                ImageLockMode.ReadWrite,
                image.PixelFormat);

        return null;
    }

Ich hoffe ich konnte dir helfen.

Andere Tipps

Sie wollen die Bitmap.LockBits Methode verwenden, um die Pixeldaten zuzugreifen. Diese ist eine gute Referenz auf den Prozess. Im Wesentlichen, Sie gehen zu müssen unsafe Code verwenden, um iterieren die Bitmap-Daten.

Hier ist eine Kopie / verpastbarem Version der Funktion I w habe kommen / basiert auf auf diesen Thread.

Der unsichere Code erwartet, dass die Bitmap Format24bppRgb zu sein, und wenn es nicht ist, wird es die Bitmap in dieses Format und arbeitet auf der geklonte Version konvertieren.

Beachten Sie, dass der Aufruf von image.Clone () wird ausgelöst, wenn Sie in einem Bitmap mit einem indiziertes Pixelformat, wie Format4bppIndexed passieren.

nimmt ~ 200ms ein Histogramm aus einem Bild 9100x2048 auf meiner Dev-Maschine zu erhalten.

    private long[] GetHistogram(Bitmap image)
    {
        var histogram = new long[256];

        bool imageWasCloned = false;

        if (image.PixelFormat != PixelFormat.Format24bppRgb)
        {
            //the unsafe code expects Format24bppRgb, so convert the image...
            image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), PixelFormat.Format24bppRgb);
            imageWasCloned = true;
        }

        BitmapData bmd = null;
        try
        {
            bmd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly,
                                 PixelFormat.Format24bppRgb);

            const int pixelSize = 3; //pixels are 3 bytes each w/ Format24bppRgb

            //For info on locking the bitmap bits and finding the 
            //pixels using unsafe code, see http://www.bobpowell.net/lockingbits.htm
            int height = bmd.Height;
            int width = bmd.Width;
            int rowPadding = bmd.Stride - (width * pixelSize);
            unsafe
            {
                byte* pixelPtr = (byte*)bmd.Scan0;//starts on the first row
                for (int y = 0; y < height; ++y)
                {
                    for (int x = 0; x < width; ++x)
                    {
                        histogram[(pixelPtr[0] + pixelPtr[1] + pixelPtr[2]) / 3]++;
                        pixelPtr += pixelSize;//advance to next pixel in the row
                    }
                    pixelPtr += rowPadding;//advance ptr to the next pixel row by skipping the padding @ the end of each row.
                }
            }
        }
        finally
        {
            if (bmd != null)
                image.UnlockBits(bmd);
            if (imageWasCloned)
                image.Dispose();
        }

        return histogram;
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top