Lib Bridge | CVB to OpenCV

Hi @parsd ,

Can you also give an example convertion for Cvb Image to opencv cv::Mat image in C++ efficiently?

Thanks in advance.

Could you please post your code and what your problem with the conversion is? We can then try to figure out what is going wrong. You should also have a documentation being installed with CVB which will describe in detail how the conversion from a CVB image to different other image types can be done. You should find it under %CVB%doc.

Hi @usernv ,

I have currently CVB version 13.02.002 installed in my system.Could you tell me the name of the document you are mentioning,as i was unable to find the needed one.

  1. Also i am trying the c++ implementation of the above code,but its quite difficult without the header files ,may be i can attach a snippet!
  2. So here i doesnt know “var” described is like auto variable in c++ or as mentioned in the above program.
  3. " image.GetDepthType() " i dont see a function like this in the image class.

It would be great if you can provide me a working code that converts a cvb::imageptr to cv::Mat in c++.And from there may be we can discuss the errors if we come across.That would help to move forward faster i think.

1 Like

Hi @arunsid123,

we describe that for the C-API in the CVBInterop.pdf - when the download works again. So here is a solution for OpenCV and C++ (ImageToMat):

Cvb::DataType GetDataType(const cv::Mat &mat)
{
  switch(mat.depth())
  {
    default:
      throw std::logic_error("Unknown element depth");
    case CV_8U:
      return Cvb::DataType::FromNativeType<std::uint8_t>();
    case CV_8S:
      return Cvb::DataType::FromNativeType<std::int8_t>();
    case CV_16U:
      return Cvb::DataType::FromNativeType<std::uint16_t>();
    case CV_16S:
      return Cvb::DataType::FromNativeType<std::int16_t>();
    case CV_32S:
      return Cvb::DataType::FromNativeType<std::int32_t>();
    case CV_32F:
      return Cvb::DataType::FromNativeType<float>();
    case CV_64F:
      return Cvb::DataType::FromNativeType<double>();
  }
}

int GetDepth(const Image &image)
{
  if(!image.PlaneDataTypesIdentical())
    throw std::invalid_argument("Only images with the same data type per plane can be used");

  const auto dataType = image.Plane(0).DataTyp();
  if(dataType.Matches<std::uint8_t>())
    return CV_8U;
  else if(dataType.Matches<std::int8_t>())
    return CV_8S;
  else if(dataType.Matches<std::uint16_t>())
    return CV_16U;
  else if(dataType.Matches<std::int16_t>())
    return CV_16S;
  else if(dataType.Matches<std::int32_t>())
    return CV_32S;
  else if(dataType.Matches<float>())
    return CV_32F;
  else if(dataType.Matches<double>())
    return CV_64F;

  return throw std::logic_error("Data type not supported by OpenCV");
}

std::unique_ptr<Cvb::WrappedImage> WrapMat(cv::Mat &mat)
{
  if(!mat.isContinuous())
    throw std::invalid_argument("Only continuous images are supported");

  const auto numChannels = mat.channels();
  const auto dataType = GetDataType(mat);
  const auto planeStride = dataType.BytesPerPixel();
  const auto pixelStride = planeStride * numChannels;
  switch(numChannels)
  {
    default:
      throw std::logic_error("Only mono or 3 channel Mats are supported");
    case 1:
      return Cvb::WrappedImage::FromGreyPixels(mat.ptr(), 0, mat.cols, mat.rows, dataType, pixelStride, mat.step);
    case 3:
      return Cvb::WrappedImage::FromBgrPixels(mat.ptr(), 0, mat.cols, mat.rows, dataType, pixelStride, mat.step, planeStride);
  }
}

void CopyToMat(const Cvb::Image &image, cv::Mat &mat)
{
  auto wrappedImage = WrapMat(mat);
  image.Copy(*wrappedImage);
}

cv::Mat ImageToMat(const Cvb::Image &image)
{
  const auto depth = GetDepth(image);
  cv::Mat mat{image.Height(), image.Width(), CV_MAKETYPE(depth, image.PlanesCount())};
  CopyToMat(image, mat);
  return mat;
}

(Disclaimer: I didn’t write this in an IDE and only done this purely from documentation… So please tell me where I went wrong :smile:)

3 Likes
{
 path = Cvb::ExpandPath(path);
        // open a device
        auto device = Cvb::DeviceFactory::Open(path);
        auto stream = device->Stream();
        Cvb::WaitStatus res;
        Cvb::UI::ImageView view2;
        view2.setWindowIcon(QIcon(":/qttutorial.png"));
        view2.SetUploadMode(Cvb::UI::UploadMode::Viewport);
        view2.SetRenderEngine(Cvb::UI::RenderEngine::OpenGL2);
        Cvb::ImagePtr img = stream->GetSnapshot(res);

       cv::Mat imageMat = .....???

}

The conversion is necessary to convert to regular Mat OpenCV, where a lot of image based functions can be easily done.

Hi @arunsid123,
you can do the conversion with @parsd’s code (thanks for that :+1:) like so:

cv::Mat imageMat = ImageToMat(img);

You can also do most image based functions using our SDK which provides fast and reliable functions and would eliminate the need to convert between different image types which will potentially slow down you application.
Additionally to the online reference you find many examples in your CVB installation directory under

%CVB%tutorials

Thanks a lot for the code. I think the codes works as i can see the pixel values. However i face an issue related to view of image using imshow(), its not executing because of the interruption i guess.

The following is the present code,

…

void CopyToMat(const Cvb::Image &image, cv::Mat &mat)
{
    auto wrappedImage = WrapMat(mat);
    image.Copy(*wrappedImage);
}

cv::Mat ImageToMat(const Cvb::Image &image)
{
    const auto depth = GetDepth(image);
    cv::Mat mat{image.Height(), image.Width(), CV_MAKETYPE(depth, image.PlanesCount())};
    CopyToMat(image, mat);
    std::cout << "depth:" << depth << std::endl;
    return mat;
}

cv::Mat getMat(int argc, char* argv[])
{


    auto path = Cvb::InstallPath();
    path += CVB_LIT("drivers/GenICam.vin");
    auto device = Cvb::DeviceFactory::Open(path);
    auto stream = device->Stream();
    Cvb::WaitStatus res;
    Cvb::UI::ImageView view2;
    view2.setWindowIcon(QIcon(":/qttutorial.png"));
    view2.SetUploadMode(Cvb::UI::UploadMode::Viewport);
    view2.SetRenderEngine(Cvb::UI::RenderEngine::OpenGL2);
    Cvb::ImagePtr image;
    //cv::Mat test(cv::Size(1000, 100), CV_8UC3, Scalar(2));

    stream->Start();
    Cvb::ImagePtr image2;
    for (int i = 0; i < 5; ++i)
    {
	auto waitResult = stream->WaitFor(std::chrono::seconds(10));
	if (waitResult.Status == Cvb::WaitStatus::Timeout)
	    throw std::runtime_error("acquisition timeout");

	std::cout << "Acquired image... " << std::fixed << waitResult.Image->RawTimestamp() << std::endl;
	//imshow("Original Image", waitResult.Image);
	image2 =waitResult.Image;

    }
    stream->Stop();
    stream.reset();
    auto start2 = high_resolution_clock::now();
    cv::Mat imagemat = ImageToMat(*image2);
    auto stop2 = high_resolution_clock::now();

    auto duration = duration_cast<microseconds>(stop2 - start2);
    std::cout << "Time for Cvb to Mat :   "<<duration.count() << std::endl;


    return imagemat;
}

int main(int argc, char* argv[])
{
    try
    {
	QApplication app(argc, argv);
	cv::Mat temp =  getMat(argc, argv);

	cv::namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display.
	cv::imshow( "Display window", temp );
	cv::waitKey(0);

	std::cout<<"end.."<<std::endl;
	app.exec();

    }
    catch (const std::exception& error)
    {
	std::cout << error.what() << std::endl;
    }
}

But …i see the problem here that imshow() function is not able to visualize the image,i think there is an issue with the Qapplication and the loop with app.exec();,i think imshow waitKey() makes a problem here…do you have a solution for this ?

Just to make things clear,
the following code doesn’t run,and if i uncomment the lines,it could also not visualize the image by openCV. I hope this their is some conflicts between the libraries happening …or,how i can i rectify this issue?

try
{
    QApplication app(argc, argv);
    
    Cvb::UI::ImageView view;
    view.setWindowIcon(QIcon(":/qttutorial.png"));
    view.SetUploadMode(Cvb::UI::UploadMode::Viewport);
    view.SetRenderEngine(Cvb::UI::RenderEngine::OpenGL2);
    Cvb::ImagePtr image_data = 
    Cvb::Image::Load("/home/user1/Auto_brightness_project/home.jpg");
    view.Refresh(image_data);
    view.show();
    
    
    cv::Mat temp=imread("/home/user1/Auto_brightness_project/home.jpg",IMREAD_COLOR);
    
    //       cv::Mat temp =  getMat(argc, argv);
    //        cv::namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display.
    //        cv::imshow( "Display window", temp );
    //        cv::waitKey(0);
    
    std::cout<<"end.."<<std::endl;
    app.exec();
    
    
}

You can try to run a CVB example from the CVB installation (precompiled) so you know your setup should be fine. Then building the CVB example should also work and show the same result when running. You can then adapt the example with parsd’s code.

For OpenCV I cannot give you a lot of advice but it seems to me that you are overwriting your temp matrix with a nonexistent one. OpenCV should open the image with

int main( int argc, char** argv )
{
  cv::Mat temp = imread("/home/user1/Auto_brightness_project/home.jpg", CV_LOAD_IMAGE_COLOR);
  namedWindow( "Display window", WINDOW_AUTOSIZE );
  imshow( "Display window", temp);
  waitKey(0); // Wait for a keystroke in the window
  return 0;
}