Menu

Grabbing images in separate thread (barcode scanner)

column
2018-11-10
2018-11-11
  • column

    column - 2018-11-10

    Hello,

    Trying to build 2D barcode scanner on basis of DxSnap project. According to my algorythm after entering in "detect" mode I'm planning to take many pictures while focuse immage an pass them to process for Zxing library. I was planning to make bitmap grabbing and 2D barcode extracing from picture in separate thread but got proble in more simplefied task. I can't grab many pictures in cycle:

        private void button2_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
    
            for (int i = 0; i < 10; i++)
            {
                // Release any previous buffer
                if (m_ip != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(m_ip);
                    m_ip = IntPtr.Zero;
                }
                // capture image
                m_ip = cam.Click();
                Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
    
                // If the image is upsidedown
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                //pictureBox1.Image = b;
                Console.WriteLine("click done");
            }
            Cursor.Current = Cursors.Default;
        }
    

    During second cycle I have exception "Timeout waiting to get picture".

    If I add sleep line in cycle System.Threading.Thread.Sleep(1000); it solves the problem. But why I should add it?

    In case I run picture taking in separate thread I have xception "Specified cast is not valid"
    in catch block of sample DxSnap Capture class:

        public IntPtr Click()
        {
            int hr;
    
            // get ready to wait for new image
            m_PictureReady.Reset();
            m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);
    
            try
            {
                m_WantOne = true;
    
                // If we are using a still pin, ask for a picture
                if (m_VidControl != null)
                {
                    // Tell the camera to send an image
                    hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
    
                    DsError.ThrowExceptionForHR(hr);
                }
    
                // Start waiting
                if (!m_PictureReady.WaitOne(90000, false))
                {
                    throw new Exception("Timeout waiting to get picture");
                }
            }
            catch
            {
                Marshal.FreeCoTaskMem(m_ipBuffer);
                m_ipBuffer = IntPtr.Zero;
                throw;
            }
    
            // Got one
            return m_ipBuffer;
        }
    

    Calling side code:

         public async Task<Result> doDetect()
        {
    
                        var barcodeReader = new BarcodeReader();
    
                        Result t = await Task.Factory.StartNew<Result>( () => 
                        {
                            int i = 0;
                            Result barcodeResult = null;
                            while (barcodeResult == null && i<300 )
                            {
                                i++;
    
                                Bitmap pic = photo();
                                System.Threading.Thread.Sleep(1000);
                                if (pic != null)
                                {
                                    barcodeResult = barcodeReader.Decode(pic);
                                                                    }
                                else
                                {
                                    log.Error("no immage to parse");
    
                                }
                            }
    
                            if (barcodeResult != null)
                            {
    
                                // output results to console
                                log.Info($"Decoded barcode text: {barcodeResult?.Text}");
                                log.Info($"Barcode format: {barcodeResult?.BarcodeFormat}");
                                return barcodeResult;
                            }
                            else
                            {
                                log.Info("barcodeResult not detected");
    
                            }
    
                            return barcodeResult;
    
                        });
    
            if (t != null)
            {
                log.InfoFormat("detect done result={0}", t.Text );
    
            }
            else
            {
                log.InfoFormat("detect done result={0}", "empty");
    
            }
    
            return t;
    
        }
    
        public Bitmap photo()
        {
            log.Info("photo...");
            if (m_ip != IntPtr.Zero)
            {
                Marshal.FreeCoTaskMem(m_ip);
                m_ip = IntPtr.Zero;
            }
    
            // capture image
            m_ip = cam.Click();
            Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
    
            // If the image is upsidedown
            b.RotateFlip(RotateFlipType.RotateNoneFlipY);
            return b;
        }
    

    How to deal in case I need to proceed it in separate thread?

     

    Last edit: column 2018-11-10
  • snarfle

    snarfle - 2018-11-11

    The code DxSnap uses to signal that an image is needed and to return that image is (in retrospect) pretty bad. I was younger then.

    Part of your problem might be that m_WantOne might not get updated the way you expect. You could try marking it as volatile. Might help.

    As for threading, the problem comes from creating objects in one thread and trying to use them in another. There are ways to do this (see MTAThread), but that can lead to other problems. Better is to create and access all the DS objects from the same thread. Note that the pointer sent back from Click is just a pointer to memory (ie NOT a DS object) and can cross threads just fine.

     

Log in to post a comment.