CVBPy on Linux (Ubuntu 16.04)

Hi,

I am working with a Genie Nano camera and and Ubuntu 16.04 system. I would like to use the CVBpy libraries to grab and image and save it. I downloaded the .py files from a comment on this link https://forum.commonvisionblox.com/t/cvb-python-c2-camera-automation-technology/301/7. However the discussion seems to be specific to Windows, and since I could not find any page/document about how to use CVBpy on a Linux system, I am raising this question here in this forum.
Here is what I have tried to do:

  • I downloaded the cvb.zip file from a comment on the link that I have provided above.
  • I extracted the zip file and placed it in my python path.
  • Started the python3.5 prompt and tried to import cvb. However I got the following error:

Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type “help”, “copyright”, “credits” or “license” for more information.

import cvb
Traceback (most recent call last):
File “”, line 1, in
File “/home/test_user/.local/lib/python3.5/site-packages/cvb/init.py”, line 18, in
import _cvb
ImportError: No module named ‘_cvb’

I would be really grateful if you could point me to a resource or a tutorial about how I can use CVBpy on a Linux system.

Thanks and regards,
Suprateek

Hi @xenonforlife

You are most certainly missing the CVBpy modules for Ubuntu. Currently there is no setup for Linux.
If you want to try it, you should contact support@stemmer-imaging.de to get the current files and instructions for a manual setup.

Hi @Andreas,

Thank you for the reply. I did contact the team at Stemmer Imaging and was able to get the appropriate libraries and it works rather flawlessly for our test scenario. However I do have yet another question, which is related to my application.
Here is what I am trying to do:

  • Capture an image from the camera
  • Convert it to a byte stream
  • Send it to another application via MQTT
  • Receive the byte stream at the receiver application.
  • Convert the received byte stream back to the original image and save it

Somehow the conventional techniques of converting the image to a byte array and reconstructing it from the byte array are not working. I can share code snippets too if that would help. At the moment I am able to achieve this with a workaround. I am saving the captured image as a temporary image file and then I am reading this temporary image in linux as bytes and then I send it over the communication channel after applying some encoding to it. On the receivers side I decode it accordingly and then I save it at the receiver’s side too.
I would be really grateful if you could suggest me a more elegant solution which would not involve saving it temporarily at the sender’s side first.

There is a c# code example for converting a CVB image to a bitmap, perhaps you could modify that? I’ve used it before to avoid having to save an image to disk. Its been a while since I last worked with python, so no idea how much of a hassle it is to modify the code, but at least it shows the general approach to the problem.

@CvK Thank you so much for the reply, would it be possible for you to point me to that particular piece of code or where I could get access to it?

@xenonforlife
The example I refer to is located here;
%cvb%tutorial\image manager\csharp\CSIMG2Bitmap

or for sake of convenience;

private unsafe bool CopyIMGbitsToBitmap(Cvb.Image.IMG img, ref Bitmap bm)
    {
      // check image and bitmap
      if ((!Cvb.Image.IsImage(img)) || (bm == null))
        return false;

      // get image info (function supports mono and color images, each plane @8bit per pixel)
      int nWidth      = Cvb.Image.ImageWidth(img);
      int nHeight     = Cvb.Image.ImageHeight(img);
      int nDimension  = Cvb.Image.ImageDimension(img);

      // check image geometry
      if ((bm.Width != nWidth) || (bm.Height != nHeight))
        return false;

      // prepare linear image access
      IntPtr[] pBase    = new IntPtr[3];
      int[] xInc        = new int[3];
      int[] yInc        = new int[3];
      // prepare non-linear image access (through the VPAT)
      IntPtr[] addrVPAT = new IntPtr[3];
      Cvb.Image.VPAEntry*[] pVPAT = new Cvb.Image.VPAEntry*[3];
      
      // flag to indicate wether the image data is linear or not
      bool bIsLinear = true;
      for (int i = 0; i < nDimension; i++)
      {
        // verify the datatype
        if (Cvb.Image.ImageDatatype(img, i) != 8)
          return false;
        // try to get linear access to the image data
        if (!Cvb.Utilities.GetLinearAccess(img, i, out pBase[i], out xInc[i], out yInc[i]))
          bIsLinear = false;
      }
      switch (nDimension)
      {
        case 1:
          {
            // lock the bitmap
            Rectangle   rc      = new Rectangle(0, 0, nWidth, nHeight);
            BitmapData  bmData  = bm.LockBits(rc, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
            // the pointer to the bitmap bits
            byte* pDst = (byte*)bmData.Scan0;

            // the linear case
            if (bIsLinear)
            {
              for (int y = 0; y < nHeight; y++)
              {
                // the pointer to the start of line y of the IMG
                byte* pSrc = (byte*)pBase[0] + y * yInc[0];
                for (int x = 0; x < nWidth; x++)
                {
                  // inc. bitmap pointer
                  *(pDst++) = *pSrc;
                  // inc. IMG pointer
                  pSrc += xInc[0];
                }
                // jump to the stride
                for (int k = 0; k < bmData.Stride - bmData.Width; k++)
                  pDst++;
              }
            }
            // the confused VPAT case (e.g. unsorted multitap linescan)
            else
            {
              // get VPAT access to the image data
              Cvb.Image.GetImageVPA(img, 0, out pBase[0], out addrVPAT[0]);
              // a pointer to the VPAT
              pVPAT[0] = (Cvb.Image.VPAEntry*)addrVPAT[0].ToPointer();
              for (int y = 0; y < nHeight; y++)
              {
                // a pointer to the start of the line
                byte* pImageLine = (byte*)pBase[0] + pVPAT[0][y].YEntry.ToInt64();
                for (int x = 0; x < nWidth; x++)
                {
                  // copy the pixel
                  *(pDst++) = *(pImageLine + pVPAT[0][x].XEntry.ToInt64());
                }
                // jump to the stride
                for (int k = 0; k < bmData.Stride - bmData.Width; k++)
                  pDst++;
              }
            }
            // unlock the bitmap bits
            bm.UnlockBits(bmData);
            return true;
          }
        case 3:
          {
            // lock the bitmap
            Rectangle   rc      = new Rectangle(0, 0, nWidth, nHeight);
            BitmapData  bmData  = bm.LockBits(rc, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            // the pointer to the bitmap bits
            byte* pDst = (byte*)bmData.Scan0;

            // the linear case
            if (bIsLinear)
            {
              // the pointers to the start of the lines of the IMG
              byte*[] pSrc = new byte*[3];
              for (int y = 0; y < nHeight; y++)
              {
                // init the pointers to the start of line y of the IMG
                for (int k = 0; k < 3; k++)
                  pSrc[k] = (byte*)pBase[k] + y * yInc[k];
                for (int x = 0; x < nWidth; x++)
                {
                  // copy the rgb (bgr) pixel
#if BGR
                  *(pDst++) = *pSrc[2];
                  *(pDst++) = *pSrc[1];
                  *(pDst++) = *pSrc[0];
#else
                  *(pDst++) = *pSrc[0];
                  *(pDst++) = *pSrc[1];
                  *(pDst++) = *pSrc[2];
#endif
                  // inc. IMG pointers
                  for (int k = 0; k < 3; k++)
                    pSrc[k] += xInc[k];
                }
                // jump to the stride
                for (int k = 0; k < bmData.Stride - bmData.Width * 3; k++)
                  pDst++;
              }
            }
            // the confused VPAT case (e.g. unsorted multitap linescan)
            else
            {
              // get VPAT access to the image data
              for (int k = 0; k < 3; k++)
              {
                Cvb.Image.GetImageVPA(img, k, out pBase[k], out addrVPAT[k]);
                // a pointer to the VPAT
                pVPAT[k] = (Cvb.Image.VPAEntry*)addrVPAT[k].ToPointer();
              }
              // the pointers to the start of the lines of the IMG
              byte*[] pSrc = new byte*[3];
              for (int y = 0; y < nHeight; y++)
              {
                // init the pointer to the start of line y of the IMG
                for (int k = 0; k < 3; k++)
                  pSrc[k] = (byte*)pBase[k] + pVPAT[k][y].YEntry.ToInt64();
                for (int x = 0; x < nWidth; x++)
                {
                  // copy the rgb (bgr) pixel
#if BGR
                  *(pDst++) = *(pSrc[2] + pVPAT[2][x].XEntry.ToInt64());
                  *(pDst++) = *(pSrc[1] + pVPAT[1][x].XEntry.ToInt64());
                  *(pDst++) = *(pSrc[0] + pVPAT[0][x].XEntry.ToInt64());
#else
                  *(pDst++) = *(pSrc[0] + pVPAT[0][x].XEntry);
                  *(pDst++) = *(pSrc[1] + pVPAT[1][x].XEntry);
                  *(pDst++) = *(pSrc[2] + pVPAT[2][x].XEntry);
#endif
                }
                // jump to the stride
                for (int k = 0; k < bmData.Stride - bmData.Width * 3; k++)
                  pDst++;
              }
            }
            // unlock the bitmap bits
            bm.UnlockBits(bmData);
            return true;
          }
        default:
          {
            return false;
          }
      }
    }

and the other function:

private unsafe Bitmap CvbImageToBitmap(Cvb.Image.IMG img, out bool RecquiresCopy)
    {
      // init flag indicating that the data has to be copied to the bitmap
      RecquiresCopy = true;
      // check image
      if (!Cvb.Image.IsImage(img))
        return null;

      // get image info (supporting mono and color images)
      int nWidth      = Cvb.Image.ImageWidth(img);
      int nHeight     = Cvb.Image.ImageHeight(img);
      int nDimension  = Cvb.Image.ImageDimension(img);
            
      // check the datatype (supporting so far only 8bit for each plane)
      for (int i = 0; i < nDimension; i++)
      {
        if (Cvb.Image.ImageDatatype(img, i) != 8)
          return null;
      }

      switch (nDimension)
      {
        case 1:
          {
            // the new bitmap
            Bitmap  bm    = null;
            IntPtr  pBase = IntPtr.Zero;
            long    xInc  = -1;
            long    yInc = -1;
            // try to get linear access to plane 0
            Cvb.Utilities.GetLinearAccess(img, 0, out pBase, out xInc, out yInc);
            // we might use the image data without copying the data if the alignment matches
            if (((int)yInc == nWidth) && ((int)xInc == 1))
            {
              // the y-pitch
              int stride = nWidth * (int)xInc;
              // create the bitmap directly from the pointer to the image data
              bm = new Bitmap(nWidth, nHeight, stride, PixelFormat.Format8bppIndexed, pBase);
              // this will not require data to be copied
              RecquiresCopy = false;
            }
            else
            {
              // create a linear bitmap
              bm = new Bitmap(nWidth, nHeight, PixelFormat.Format8bppIndexed);
              // copy the data
              CopyIMGbitsToBitmap(img, ref bm);
            }
            // the palette
            ColorPalette pal = bm.Palette;
            // rewrite the palette
            for (int i = 0; i < bm.Palette.Entries.Length; i++)
              pal.Entries[i] = Color.FromArgb(i, i, i);
            // apply it
            bm.Palette = pal;
            return bm;
          }

        case 3:
          {
            // create a linear bitmap
            Bitmap bm = new Bitmap(nWidth, nHeight, PixelFormat.Format24bppRgb);
            // copy the data
            CopyIMGbitsToBitmap(img, ref bm);
            return bm;
          }
        default:
          {
            return null;
          }
      }
    }
1 Like

@CvK thanks for the code…I will try to port it to python. Thanks a lot!

Just as a side note: your solution with cvb.as_array to get the numpy array is the best and inteded solution for your use case.

Also the example from @CvK is for the C-style API. With CVB .Net you can simply call .ToBitmap (from the Stemmer.Cvb.Extensions.dll), to achieve the same goal. This is one of the examples we try to make your life easier. :slight_smile:

Ooh! I should definitely check out the new .net API :slight_smile: hadn’t gotten around to it yet.

Hi @parsd,

Thanks for the reply. I indeed got the idea from @c.hartmann , however unfortunately I ran into runtime errors as I have outlined in another post (Failed to create Numpy Array CVBPy Linux). I am yet to ascertain if it is a bug or if I am doing something wrong. Hoping that it would be clarified by an expert soon :slight_smile:

Thanks for the interest

I looks like a bug – as advertised the new wrappers are still in beta phase and thus we currently do most of our testing on the Windows platform. We are working on better integration and system tests for the drivers.

So I am sorry for your inconvenience and we say thank you for using the new APIs. I hope you like the feel of it. We are working on your issues and you can expect an update in the following days.

sounds great! Glad I could contribute in some way too :slight_smile: I really do like the feel of it. My work is not affected as I did find a workaround. Although I would like to make it more efficient. Thanks again. Hoping to hear from you soon :slight_smile:

@parsd I did finally solve it using the cvb.as_array method, as it now works in the newest library.
Here is how I packed and sent it:

Sender’s side:

try:
    image_numpyArray = cvb.as_array(image)
    pickled_image = pickle.dumps(image_numpyArray, protocol=0)
    pickledImageEncoded_base64bytes = base64.b64encode(pickled_image)
    pickledImageEncoded_string = pickledImageEncoded_base64bytes.decode('utf-8')

except Exception as ex:
   print(ex)

imagePacket ={"id":"id_1","payload": pickledImageEncoded_string}
jsonPacketOut = json.dumps(imagePacket)

Then I sent the jsonPacketOut over the network

On the receiver’s side:

        jsonPacketIn = msg.payload.decode('utf-8')
        imagePacketIn = json.loads(jsonPacketIn)
        
        rcvdPickledImageEncoded_string = imagePacketIn["payload"]
        rcvdPickledImageEncoded_base64bytes = bytes(rcvdPickledImageEncoded_string,'utf-8')
        rcvdPickledImagebytes = base64.b64decode(rcvdPickledImageEncoded_base64bytes)

        rcvdImgNumpyArray = pickle.loads(rcvdPickledImagebytes)
        rcvdWrappedImage = cvb.WrappedImage.from_buffer(rcvdImgNumpyArray)
        rcvdWrappedImage.save(str(imagePacketIn["id"])+".bmp")
2 Likes

Hi @xenonforlife,

thank you for sharing.
This is quite interesting.

Just another update : it doesn’t need to be packed in a json (in my case it was a project requirement for interoperability), however if all applications involved are python based then directly sending the Pickled packet is sufficient and reduces the execution time by around 50%