c# सी#इमेज फिल्टर समानांतर। इसके लिए अधिक समय लगता है



image visual-studio (3)

यहाँ कोड है कि यह तेजी से इसके धीमे एक सिंगल के कारण बनाने के लिए कोई रास्ता नहीं है

public Bitmap pSetInvert(Bitmap _currentBitmap)
    {
        Bitmap temp = (Bitmap)_currentBitmap;
        Bitmap bmap = (Bitmap)temp.Clone();
        Color c;
        Parallel.For(0, bmap.Width, i =>
        {
            lock (bmap)
            {
                for (int j = 0; j < bmap.Height; j++)
                {
                    c = bmap.GetPixel(i, j);
                    bmap.SetPixel(i, j, Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));
                } 
            }
        });
        return (Bitmap)bmap.Clone();
    }

Parallel.For में lock । इसके लिए कोड को एकल-थ्रेडेड लूप के मुकाबले धीमी गति से चलने का कारण हो रहा है। लॉक केवल एक धागे को एक समय में उपयोगी कार्य करने की सुविधा देता है, लॉक प्राप्त करने की अतिरिक्त लागत के साथ।

इसके अतिरिक्त, GetPixel और SetPixel बहुत धीमा हैं उन्हें धागा-सुरक्षित होने की भी गारंटी नहीं दी जाती है, जो संभवतः आप अमान्यऑपरेशन अपवाद को क्यों प्राप्त कर रहे हैं

इस प्रकार के किसी भी सार्वजनिक स्थिर (विजुअल बेसिक में साझा) थ्रेड सुरक्षित हैं किसी भी उदाहरण के सदस्यों को धागा सुरक्षित होने की गारंटी नहीं है

http://msdn.microsoft.com/en-us/library/System.Drawing.Bitmap(v=vs.110).aspx

लिहाज योग्य बिटमैप पर बजाय एक नज़र डालें हालांकि वर्ग WPF के साथ पेश किया गया था, आप इसे विभिन्न वातावरणों से उपयोग कर सकते हैं। मैंने हाल ही में इसे एक कंसोल एप्लिकेशन में उपयोग किया है लिखने योग्य बिटमैप एक मानक बिटमैप में परिवर्तित किया जा सकता है यदि आवश्यक हो, या ".bmp" फ़ाइल में लिखा हो।

वैकल्पिक रूप से, आप सीधे बिटमैप बफर तक पहुंचने के लिए असुरक्षित कोड का उपयोग कर सकते हैं

यदि आप की आवश्यकता है, तो आप लिखने योग्य बिटमैप या बिटमैप बफर के लिए असुरक्षित पहुंच के लिए कई थ्रेड का उपयोग कर सकते हैं क्योंकि आप सीधे मेमोरी पढ़ रहे हैं / लिख रहे हैं।


यहां आपके फ़िल्टर रूटीन के दो संस्करण हैं जो आप के साथ खेल सकते हैं। वे एक PictureBox की छवि लेते हैं और फिल्टर के माध्यम से चलाने के बाद उसे दूसरे PictureBox

  • पहला LockBits का उपयोग करता है और मेरी मशीन पर 40 सेकंड में एक सीए 400x400 छवि के लिए 10.000 (!) लूप कर सकता है।
  • दूसरा Parallel.For का उपयोग करता है। LockBits अतिरिक्त और यहां 35 सेकंड में एक ही काम करता है।

बेशक ये समय ओवरहेड (और हो सकता है कि गूंगे कीड़े के कारण) से बहुत प्रभावित हैं। लेकिन वास्तव में, Lockbits का उपयोग करना गति की कुंजी है क्योंकि 'गणना' करने के लिए बहुत कम है, समानांतरता प्रबंधन ही अधिकांश कोर समय को खाती है ..

using System.Runtime.InteropServices;
// ..


public void filter1()
{
    if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
    Bitmap bmp = new Bitmap(pictureBox1.Image);

    Size s1 = bmp.Size;
    PixelFormat fmt1 = bmp.PixelFormat;

    Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
    BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, fmt1);
    byte bpp = 4;  // <<-------------------set to 3 for 24bbp !!

    int size1 = bmpData.Stride * bmpData.Height;
    byte[] data = new byte[size1];
    Marshal.Copy(bmpData.Scan0, data, 0, size1);

    for (int y = 0; y < s1.Height; y++)
    {
        for (int x = 0; x < s1.Width; x++)
        {
            int index = y * bmpData.Stride + x * bpp;

            data[index + 0] = (byte) (255 - data[index + 0]);  // Blue
            data[index + 1] = (byte) (255 - data[index + 1]);  // Green
            data[index + 2] = (byte) (255 - data[index + 2]);  // Red
            data[index + 3] = 255;   // Alpha, comment out for 24 bpp!
        }
    }

    Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
    bmp.UnlockBits(bmpData);

    pictureBox2.Image = bmp;

}


public void filter2()
{
    if (pictureBox2.Image != null) pictureBox2.Image.Dispose();

    Bitmap bmp1 = new Bitmap(pictureBox1.Image);
    Size s1 = bmp1.Size;
    Bitmap bmp2 = new Bitmap(s1.Width, s1.Height);

    PixelFormat fmt1 = bmp1.PixelFormat;

    Rectangle rect = new Rectangle(0, 0, s1.Width, s1.Height);
    BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadOnly, fmt1);
    BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.WriteOnly, fmt1);
    byte bpp = 4;  // set to 3 for 24bbp !!

    int size1 = bmpData1.Stride * bmpData1.Height;
    byte[] data1 = new byte[size1];
    byte[] data2 = new byte[size1];
    Marshal.Copy(bmpData1.Scan0, data1, 0, size1);
    Marshal.Copy(bmpData2.Scan0, data2, 0, size1);

    int degreeOfParallelism = Environment.ProcessorCount - 1;
    var options = new ParallelOptions();
    options.MaxDegreeOfParallelism = degreeOfParallelism;

     Parallel.For(0, bmp1.Width, options, y =>
     {
        {
           for (int x = 0; x < s1.Width; x++)
           {
                 int index = y * bmpData1.Stride + x * bpp;

                 data2[index + 0] = (byte)(255 - data1[index + 0]);  // Blue
                 data2[index + 1] = (byte)(255 - data1[index + 1]);  // Green
                 data2[index + 2] = (byte)(255 - data1[index + 2]);  // Red
                 data2[index + 3] = 255;   // Alpha, comment out for 24 bpp!
           }
        }
    });
    Marshal.Copy(data2, 0, bmpData2.Scan0, data2.Length);
    bmp1.UnlockBits(bmpData1);
    bmp2.UnlockBits(bmpData2);

    pictureBox2.Image = bmp2;
}

ध्यान दें कि सामान्य फिल्टर फिल्टर के लिए दूसरे बिटमैप पर काम करने के लिए दूसरे फ़िल्टर की नियमित आवश्यकता है। यह सरल उलटा फ़िल्टर वास्तव में इसकी आवश्यकता नहीं है, लेकिन एक बार जब आप ऐसे चीजें लिखते हैं जो पड़ोसी पिक्सल का उपयोग करते हैं जैसे कि .ga blur फ़िल्टर आप करते हैं ..

चैनल बाइट्स के आदेश को भी ध्यान दें!


lock का उपयोग करके आप अपने कोड का समानांतर भाग बनाकर काम कर रहे हैं, ठीक उसी तरह सिंक्रनाइज़ेशन ओवरहेड के साथ एक थ्रेड एप्लिकेशन की तरह, ताकि यह वास्तव में धीमा हो।

यहां एक सहायक वर्ग है जो सीधे बिटमैप डेटा का उपयोग करता है और आप समवर्ती रूप से छवि को हेरफेर कर सकते हैं।

फास्ट इमेज हेल्पर क्लास:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace ImageManipulation
{
    class FastImage : IDisposable
    {
        private Bitmap _buffer;
        private byte[] _rawData;
        private GCHandle _rawHandle;
        private int _formatSize;
        private int _width;
        private int _height;

        public int Width
        {
            get { return _width; }
        }

        public int Height
        {
            get { return _height; }
        }

        public byte[] GetRawData()
        {
            return _rawData;
        }

        public byte this[int index]
        {
            get { return _rawData[index]; }
            set { _rawData[index] = value; }
        }

        public Color this[int x, int y]
        {
            get
            {
                return GetPixel(x, y);
            }
            set
            {
                SetPixel(x, y, value);
            }
        }

        public Color GetPixel(int x, int y)
        {
            var offset = y*_width*_formatSize;
            offset += x*_formatSize;
            return Color.FromArgb(_rawData[offset + 3], _rawData[offset + 2], _rawData[offset + 1], _rawData[offset]);
        }

        public void SetPixel(int x, int y, Color value)
        {
            var offset = y*_width*_formatSize;
            offset += x*_formatSize;

            _rawData[offset] = value.B;
            _rawData[offset + 1] = value.G;
            _rawData[offset + 2] = value.R;
            _rawData[offset + 3] = value.A;

        }

        private FastImage() { }

        public static FastImage Create(Image source)
        {
            var image = new FastImage();

            var bmpSource = new Bitmap(source);
            var bmpData = bmpSource.LockBits(new Rectangle(0, 0, source.Width, source.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmpSource.PixelFormat);

            image._width = source.Width;
            image._height = source.Height;

            image._formatSize = 4;
            var stride = bmpSource.Width * image._formatSize;
            image._rawData = new byte[stride * bmpSource.Height];
            image._rawHandle = GCHandle.Alloc(image._rawData, GCHandleType.Pinned);
            var pointer = Marshal.UnsafeAddrOfPinnedArrayElement(image._rawData, 0);
            image._buffer = new Bitmap(bmpSource.Width, bmpSource.Height, stride, PixelFormat.Format32bppArgb /*bmpSource.PixelFormat*/, pointer);
            bmpSource.UnlockBits(bmpData);

            var graphics = Graphics.FromImage(image._buffer);

            graphics.DrawImageUnscaledAndClipped(bmpSource, new Rectangle(0, 0, source.Width, source.Height));
            graphics.Dispose();

            return image;
        }

        public void Dispose()
        {
            _rawHandle.Free();
            _buffer.Dispose();
        }

        public void Save(Stream stream)
        {
            _buffer.Save(stream, ImageFormat.Bmp);
        }

        public Bitmap ToBitmap()
        {
            return (Bitmap)_buffer.Clone();
        }
    }
}

और यहां आपका कोड FastImage क्लास का उपयोग कर FastImage :

 public Bitmap pSetInvert(Bitmap _currentBitmap)
        {
            using (var bmap = FastImage.Create(_currentBitmap))
            {
                Parallel.For(0, bmap.Width, i =>
                {
                    for (int j = 0; j < bmap.Height; j++)
                    {
                        var c = bmap.GetPixel(i, j);
                        bmap.SetPixel(i, j, Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B));

                    }
                });
                return bmap.ToBitmap();
            }
        }




filter