سؤال

وهذا هو المفترض لحساب الرسم البياني للصورة 8 بت والرمادي. مع صورة نقطية اختبار 1024x770، CreateTime ينتهي في حوالي 890ms. كيف يمكنني جعل هذا الضوء (الطريق، الطريق) أسرع؟

وتحرير: أود أن أذكر أن هذا لا حساب الواقع الرسم البياني بعد، فإنه يحصل فقط القيم من الصورة النقطية. لذلك أنا حقا يجب أن يسأل، ما هو أسرع وسيلة لاسترداد كافة القيم بكسل من صورة 8 بت والرمادي؟

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; }
}
هل كانت مفيدة؟

المحلول

وخوارزمية الرسم البياني الأساسية هي شيء من هذا القبيل:

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] ]++;
   }
}

والمبالغ خوارزمية كم بكسل مع القيمة 0 لديك، كم مع قيمة = 1 وهلم جرا. والفكرة الأساسية هي استخدام قيمة بكسل حيث أن مؤشر على موقف الرسم البياني حيث سيتم الاعتماد.

ولدي نسخة واحدة من هذه الخوارزمية مكتوبة لC # باستخدام التعليمات البرمجية غير المدارة (وهو سريع) أنا لا أعرف إذا كان أسرع من الخاص بك ولكن لا تتردد في أخذه، والاختبار، وهنا هو رمز:

    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;
    }

وآمل أن أتمكن من مساعدتك.

نصائح أخرى

وأنت ترغب في استخدام طريقة Bitmap.LockBits للوصول إلى البيانات بكسل. هذا هو إشارة جيدة على العملية. أساسا، كنت بحاجة الى الذهاب الى استخدام رمز unsafe تكرار على البيانات النقطية.

وهنا نسخة / نسخة قابل للصق وظيفة جئت ث / استنادا على هذا الموضوع.

والرمز غير آمنة يتوقع نقطية ليكون Format24bppRgb، وإذا لم يكن، فإنه سوف تحويل الصورة النقطية إلى هذا الشكل وتعمل على النسخة المستنسخة.

ملاحظة أن الدعوة إلى image.Clone () سوف رمي إذا كنت تمر في صورة نقطية باستخدام تنسيق بكسل المفهرسة، مثل Format4bppIndexed.

وتحيط ~ 200MS للحصول على الرسم البياني من 9100x2048 صورة على جهاز ديف بلدي.

    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;
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top