Working with 3D-Cameras of Automation Technology in CVB

SPLIT DATA CHANNELS (DCs)

With AT’s 3D cameras multiple different image data can be obtained and transmitted to the host. This can be either images including the range information, intensity information or laser thickness information. All output channels can be selected individually and in combinations. Every DC is saved in a new image row, resulting in multi information images which must be split on the host side afterwards if multiple DCs are enabled.

For detailed information regarding the data channel assignment DC0-DC2 please take a look into the manufacturer’s sensor manual.

The following two functions demonstrate an example way (C#) to split an image consisting of multiple DCs into its sub-images, depending on its bit depth.

Split 8Bit Image
private static Boolean Split8BitImage(Cvb.Image.IMG cameraImg, ref Cvb.Image.IMG[] singleImages)
{
   // Define variables
   int numSingleImages = singleImages.GetLength(0);
   IntPtr baseIn;
   int xIncIn, yIncIn;
   int imageWidth, imageHeight;

   imageWidth = Cvb.Image.ImageWidth(cameraImg);
   imageHeight = Cvb.Image.ImageHeight(cameraImg);

   // Images might not have a multiple of lines of the requested images
   if (imageHeight % numSingleImages != 0)
     imageHeight = imageHeight / numSingleImages;

   // Get linear access to the base image
   Cvb.Utilities.GetLinearAccess(cameraImg, 0, out baseIn, out xIncIn, out yIncIn);

   // Init a pointer array for every image
   IntPtr[] baseOut = new IntPtr[numSingleImages];

   // Prepare variables
   int xIncOut, yIncOut;
   xIncOut = yIncOut = 0;

   // Create the images and get access
   for (int i = 0; i < numSingleImages; i++)
   {
     // 8 bit images
     Cvb.Image.CreateGenericImageDT(1, imageWidth, imageHeight / numSingleImages, 8, out singleImages[i]);
     Cvb.Utilities.GetLinearAccess(singleImages[i], 0, out baseOut[i], out xIncOut, out yIncOut);
   }

   // split data
   unsafe
   {
     char* grayval;
     char* pixel;

     for (int y = 0; y < imageHeight; y++)
     {
       for (int x = 0; x < imageWidth; x++)
       {
         grayval = (char*)((int)baseIn + x * xIncIn + y * yIncIn);
         // Assign correct address to pixel
         pixel = (char*)((int)baseOut[y % numSingleImages] + x * xIncOut + (y / numSingleImages) * yIncOut);
         // Write value of grayval to pixel address
         *((char*)pixel) = (char)*grayval;
       }
     }
   }
   return true;
}
Split 16Bit Image
private static Boolean Split16BitImage(Cvb.Image.IMG cameraImg, ref Cvb.Image.IMG[] singleImages)
{      
  // Define variables
  int numSingleImages = singleImages.GetLength(0);
  IntPtr baseIn;
  int xIncIn, yIncIn;
  int imageWidth, imageHeight;

  imageWidth = Cvb.Image.ImageWidth(cameraImg);
  imageHeight = Cvb.Image.ImageHeight(cameraImg);
  
  // Images might not have a multiple of lines of the requested images
  if (imageHeight % numSingleImages != 0)
	imageHeight = imageHeight / numSingleImages;

  // Get linear access to the base image
  Cvb.Utilities.GetLinearAccess(cameraImg, 0, out baseIn, out xIncIn, out yIncIn);

  // Init a pointer array for every image
  IntPtr[] baseOut = new IntPtr[numSingleImages];

  // Prepare variables
  int xIncOut, yIncOut;
  xIncOut = yIncOut = 0;

  // Create the images and get access
  for (int i = 0; i < numSingleImages; i++)
  {
	// For 16 bit images
	Cvb.Image.CreateGenericImageDT(1, imageWidth, imageHeight / numSingleImages, 16, out singleImages[i]);
	Cvb.Utilities.GetLinearAccess(singleImages[i], 0, out baseOut[i], out xIncOut, out yIncOut);
  }

  // split data
  unsafe
  {
	// For 16 bit images
	ushort* grayval;
	ushort* pixel;

	for (int y = 0; y < imageHeight; y++)
	{
	  for (int x = 0; x < imageWidth; x++)
	  {
		// grayval is the address of the pixel holding the value we want to access
		grayval = (ushort*)((int)baseIn + x * xIncIn + y * yIncIn);
		// Assign correct address to pixel
		pixel = (ushort*)((int)baseOut[y % numSingleImages] + x * xIncOut + (y / numSingleImages) * yIncOut);
		// Write value of grayval to pixel address
		*((ushort*)pixel) = (ushort)*grayval;
	  }
	}
  }
  return true;
}

Please notice, that these functions require previous knowledge about the selected number of DCs. This information can be determined by a GenICam query on the value of the specific features (EnableDC0-DC2).

2 Likes