2012-08-28 12 views
5

मैं लॉकबिट का उपयोग करके अपनी छवि पहचान वर्ग को बढ़ाने की कोशिश कर रहा हूं, फिर भी यह कोड के साथ समस्याएं पैदा करता है और इस प्रकार यह नहीं चलता है। मैं छवि पहचान को तेज़ करने के लिए एक ही समय में लॉकबिट्स और गेटपीक्सल का उपयोग करने के बारे में कैसे जा सकता हूं, या कोई मुझे एक विकल्प दिखा सकता है जो उतना तेज़ है?लॉकबिट के साथ छवि प्रसंस्करण, getpixel के विकल्प?

कोड:

static IntPtr Iptr = IntPtr.Zero; 
    static BitmapData bitmapData = null; 
    static public byte[] Pixels { get; set; } 
    static public int Depth { get; private set; } 
    static public int Width { get; private set; } 
    static public int Height { get; private set; } 

    static public void LockBits(Bitmap source) 

    { 
      // Get width and height of bitmap 
      Width = source.Width; 
      Height = source.Height; 

      // get total locked pixels count 
      int PixelCount = Width * Height; 

      // Create rectangle to lock 
      Rectangle rect = new Rectangle(0, 0, Width, Height); 

      // get source bitmap pixel format size 
      Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat); 


      // Lock bitmap and return bitmap data 
      bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, 
             source.PixelFormat); 

      // create byte array to copy pixel values 
      int step = Depth/8; 
      Pixels = new byte[PixelCount * step]; 
      Iptr = bitmapData.Scan0; 

      // Copy data from pointer to array 
      Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); 

    } 


    static public bool SimilarColors(int R1, int G1, int B1, int R2, int G2, int B2, int Tolerance) 
    { 
     bool returnValue = true; 
     if (Math.Abs(R1 - R2) > Tolerance || Math.Abs(G1 - G2) > Tolerance || Math.Abs(B1 - B2) > Tolerance) 
     { 
      returnValue = false; 
     } 
     return returnValue; 
    } 


    public bool findImage(Bitmap small, Bitmap large, out Point location) 
    { 
     unsafe 
     { 
      LockBits(small); 
      LockBits(large); 
      //Loop through large images width 
      for (int largeX = 0; largeX < large.Width; largeX++) 
      { 
       //And height 
       for (int largeY = 0; largeY < large.Height; largeY++) 
       { 
        //Loop through the small width 
        for (int smallX = 0; smallX < small.Width; smallX++) 
        { 
         //And height 
         for (int smallY = 0; smallY < small.Height; smallY++) 
         { 
          //Get current pixels for both image 
          Color currentSmall = small.GetPixel(smallX, smallY); 
          Color currentLarge = large.GetPixel(largeX + smallX, largeY + smallY); 
          //If they dont match (i.e. the image is not there) 

          if (!colorsMatch(currentSmall, currentLarge)) 
           //Goto the next pixel in the large image 

           goto nextLoop; 
         } 
        } 
        //If all the pixels match up, then return true and change Point location to the top left co-ordinates where it was found 
        location = new Point(largeX, largeY); 
        return true; 
       //Go to next pixel on large image 
       nextLoop: 
        continue; 
       } 
      } 
      //Return false if image is not found, and set an empty point 
      location = Point.Empty; 
      return false; 
     } 
    } 
+0

आपकी लॉकबिट विधि बेकार है ... यह पिक्सेल को बाइट सरणी में कॉपी करती है, लेकिन आप कभी भी उस सरणी का उपयोग नहीं करते हैं –

+4

लॉकबिट्स का उपयोग करने का बिंदु ** GetPixel का उपयोग करके ** रोकना ** है। –

उत्तर

1

ठीक है, जहां शुरू करने के लिए। बेहतर आप समझते हैं कि आप लॉक बिट्स के साथ क्या कर रहे हैं। सबसे पहले यह सुनिश्चित करें कि आप अपने बाइट सरणी को ओवरराइट नहीं करते हैं।

LockBits(small);    
LockBits(large); 

दूसरी कॉल सब पहली कॉल करता है की वजह से अपनी छवि को ताला लगा है और वह अच्छा के बाद से आप इसे फिर से अनलॉक नहीं करता नहीं है। तो छवि का प्रतिनिधित्व करने वाला एक और बाइट सरणी जोड़ें। आप इस

LockBits(small, true);    
LockBits(large, false); 

की तरह कुछ करते हैं और बदल सकते हैं अपने Lockbits विधि

static public void LockBits(Bitmap source, bool flag)       
{ 
... 
Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); 

if(flag) 
    PixelsSmall=Pixels; 
else 
    PixelsLarge=Pixels; 
} 

जहां PixelsLarge और PixelsSmall वैश्विक हैं और पिक्सल उन 2 अपनी छवि को शामिल नहीं है। अब आपको इसकी तुलना करनी है। अब आपको प्रत्येक "बाइट्स सेट" की तुलना करना है, इसलिए आपको पिक्सेलफॉर्मेट को जानना होगा। क्या यह 32 बी/पिक्स 24 या केवल 8 (एआरजीबी, आरजीबी, ग्रेस्केल) आइएआरजी छवियों को लेते हैं। इस मामले में एक सेट में 4 बाइट्स (= 32/8) शामिल होंगे, मुझे आदेश के बारे में निश्चित नहीं है लेकिन मुझे लगता है कि एक सेट का क्रम एबीजीआर या बीजीआरए है।

उम्मीद है कि यह आपकी मदद कर सकता है। यदि आपको सही पिक्सेल की तुलना करने का तरीका पता नहीं है तो फिर से पूछें। आह और अनलॉक बिट्स कमांड का उपयोग करना न भूलें।

4

आप छवि प्रसंस्करण के लिए getPixel() पर भरोसा नहीं करना चाहते हैं; पॉइंट वैल्यू (उदा। माउसओवर पर) प्राप्त करने के लिए कभी-कभार कॉल करना ठीक है, लेकिन आम तौर पर छवि मेमोरी में छवि प्रसंस्करण करना या कुछ 2 डी सरणी में करना आवश्यक है जिसे आप आवश्यकतानुसार बिटमैप में परिवर्तित कर सकते हैं।

प्रारंभ करने के लिए, आप एक विधि लिखने का प्रयास कर सकते हैं जो लॉकबिट/अनलॉक बिट्स का उपयोग करके उस सरणी को निकालने के लिए उपयोग कर सकता है जो कुशलतापूर्वक सुविधाजनक है। एक बार जब आप सरणी में हेरफेर कर लेंगे, तो आप इसे एक अलग लॉकबिट/अनलॉक बिट्स फ़ंक्शन का उपयोग करके बिटमैप पर वापस लिख सकते हैं।

यहां कुछ नमूना कोड है जो मैंने पहले उपयोग किया था। पहला फ़ंक्शन बिटमैप से मानों की 1 डी सरणी देता है। चूंकि आप बिटमैप की चौड़ाई को जानते हैं, इसलिए आप आगे बढ़ने के लिए इस 1 डी सरणी को 2 डी सरणी में परिवर्तित कर सकते हैं। एक बार जब आप प्रसंस्करण कर लेंगे, तो आप दूसरे फ़ंक्शन को (संशोधित) 1 डी सरणी को फिर से बिटमैप में परिवर्तित करने के लिए कॉल कर सकते हैं।

public static byte[] Array1DFromBitmap(Bitmap bmp){ 
    if (bmp == null) throw new NullReferenceException("Bitmap is null"); 

    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
    BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); 
    IntPtr ptr = data.Scan0; 

    //declare an array to hold the bytes of the bitmap 
    int numBytes = data.Stride * bmp.Height; 
    byte[] bytes = new byte[numBytes]; 

    //copy the RGB values into the array 
    System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, numBytes); 

    bmp.UnlockBits(data); 

    return bytes;   
} 

public static Bitmap BitmapFromArray1D(byte[] bytes, int width, int height) 
{ 
    Bitmap grayBmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); 
    Rectangle grayRect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height); 
    BitmapData grayData = grayBmp.LockBits(grayRect, ImageLockMode.ReadWrite, grayBmp.PixelFormat); 
    IntPtr grayPtr = grayData.Scan0; 

    int grayBytes = grayData.Stride * grayBmp.Height; 
    ColorPalette pal = grayBmp.Palette; 

    for (int g = 0; g < 256; g++){ 
     pal.Entries[g] = Color.FromArgb(g, g, g); 
    } 

    grayBmp.Palette = pal; 

    System.Runtime.InteropServices.Marshal.Copy(bytes, 0, grayPtr, grayBytes); 

    grayBmp.UnlockBits(grayData); 
    return grayBmp; 
} 

इन विधियों बिटमैप पिक्सेल प्रारूप है कि आप के लिए काम नहीं कर सकता के बारे में मान्यताओं करता है, लेकिन मुझे उम्मीद है कि सामान्य विचार स्पष्ट है: ताकि आप लिख सकते हैं उपयोग LockBits/UnlockBits एक बिटमैप से बाइट्स की एक सरणी को निकालने के लिए और आसानी से एल्गोरिदम डीबग करें, और उसके बाद फिर से बिटमैप में सरणी लिखने के लिए लॉकबिट/अनलॉक बिट्स का उपयोग करें।

पोर्टेबिलिटी के लिए, मैं अनुशंसा करता हूं कि आपकी विधियां विधियों के भीतर वैश्विक चरों में हेरफेर करने के बजाए वांछित डेटा प्रकार लौटाएं।

यदि आप getPixel() का उपयोग कर रहे हैं, तो उपरोक्त वर्णित सरणी में/से कनवर्ट करना कोडिंग प्रयास के छोटे निवेश के लिए आपके कोड को काफी तेज़ कर सकता है।

+1

आपने मुझे कम से कम कई सिरदर्द बचाए, धन्यवाद एक टन। –

+0

हालांकि आपको लक्ष्य बाइट्स की तरफ से जांच करनी चाहिए, और प्रति पंक्ति कॉपी करें। आखिरकार, एक नई वस्तु पर जो आपके द्वारा प्राप्त 8-बिट डेटा से भिन्न हो सकता है। और यदि 'Array1DFromBitmap' डेटा को बिल्कुल चौड़ाई तक कॉम्पैक्ट नहीं करता है, तो उसे निश्चित रूप से उस आउटपुट को आउटपुट करना चाहिए, या डेटा को सही ढंग से संसाधित नहीं किया जा सकता है। – Nyerguds

संबंधित मुद्दे