Checking if corrupt frames are delivered through CVB++

Dear Team,
I was wondering, if there is a way to a check if Corrupt frames are being delivered using CVB++.
If possible, then how do I log it ?

Thanks in advanced

Regards,
Keerthitheja S C

Hi Keerthitheja,

You can do that using the third generation acquisition GenTL stack:


#include <cvb/device_factory.hpp>
#include <cvb/global.hpp>
#include <cvb/driver/composite_stream.hpp>
#include <cvb/genapi/node_map_enumerator.hpp>
int main()
{
  try
  {
    auto infoList = Cvb::DeviceFactory::Discover(Cvb::DiscoverFlags::IgnoreVins | Cvb::DiscoverFlags::IgnoreGevFD);

    if (infoList.empty())
      throw std::runtime_error("There is no available device for this demonstration.");

    auto device = Cvb::DeviceFactory::Open(infoList[0].AccessToken(), Cvb::AcquisitionStack::GenTL);
    auto NodeMap1 = device->NodeMap("Device");
    auto Vendor = NodeMap1->Node<Cvb::StringNode>("DeviceVendorName")->Value();
    std::cout << "CameraVendor: " << Vendor << "\n";

    auto dataStream = device->Stream<Cvb::CompositeStream>();
    dataStream->Start();

    constexpr int NUM_ELEMENTS = 100000;
    constexpr auto TIMEOUT = std::chrono::milliseconds(3000);

    auto numIncomplete = 0;

    for (auto i = 0; i < NUM_ELEMENTS; i++)
    {
      Cvb::CompositePtr composite;
      Cvb::WaitStatus waitStatus;
      Cvb::NodeMapEnumerator enumerator;

      std::tie(composite, waitStatus, enumerator) = dataStream->WaitFor(TIMEOUT);

      switch (waitStatus)
      {
      default:
      {
        throw std::runtime_error("Something bad happend!");
      }
      case Cvb::WaitStatus::Ok:
      {
        break;
      }
      }
      auto vinBufferNodemap = enumerator["VinBuffer"];

      if (vinBufferNodemap->Node<Cvb::BooleanNode>("IsIncomplete")->Value())
      {
        ++numIncomplete;
      }

      std::cout << "incomplete: " << numIncomplete << "/" << i << "\n";
    }

    if (!dataStream->TryStop())
      dataStream->TryAbort();
  }
  catch (const std::exception& e)
  {
    std::cout << e.what() << std::endl;
  }
  return 0;
}

Kind regards,
Mandana

Hi,

another option is the Statistics method on the stream object:

auto corruptImages = stream->Statistics(Cvb::Driver::StreamInfo::NumBuffersCorruptOnDelivery);

Here is a list of all StreamInfos

Cheers
Thomas

Hi @rtp_derahs

I am using a Jai SW-4000Q line scan camera. The camera gives 2 streams RGB and NIR. I am using 3rd Gen Acquisition Stack to access the data. So, for accessing the individual streams, I am streaming them as composite streams. So, how do I get the statistics for both the composite streams individually. I see that the Statistics function is part of Stream Class. I don’t think it is part of the composite stream class. Is there a way to access this ?

Hi,

In this Case I would recommend to use MultiPartImage stream instead of composite stream. Then you would have a vector of streams and can get the statistics from each of them:

#include <iostream>
#include <chrono>
#include <algorithm>
#include <cvb/device_factory.hpp>
#include <cvb/image.hpp>
#include <cvb/global.hpp>
// constants
static const constexpr auto TIMEOUT = std::chrono::milliseconds(3000);
static const constexpr int NUM_ELEMENTS_TO_ACQUIRE = 10;
void PrintOutAllPartTypes(const Cvb::MultiPartImage& multiPartImage);
static std::map<Cvb::WaitStatus, const char*>
WAIT_ERROR_STATES
{
  {Cvb::WaitStatus::Timeout, "timeout"},
  {Cvb::WaitStatus::Abort, "abort"}
};
int main()
{
  try
  {
    // discover transport layers
    auto infoList = Cvb::DeviceFactory::Discover(Cvb::DiscoverFlags::IgnoreVins);
    // can't continue the demo if there's no available device:
    if (infoList.empty())
      throw std::runtime_error("There is no available device for this demonstration.");
    // instantiate the first device in the discovered list
    auto device = Cvb::DeviceFactory::Open(infoList[0].AccessToken(), Cvb::AcquisitionStack::GenTL);
    // Get all streams
    std::vector<Cvb::ImageStreamPtr> streams;
    std::generate_n(std::back_inserter(streams), device->StreamCount(), [&device, i = 0]() mutable
    {
      return device->Stream<Cvb::ImageStream>(i++);
    });
    // start the data acquisition for all streams
    for (const auto stream : streams)
    {
      stream->Start();
    }
    // acquire data
    // note: getting the data is sequential here for simplicity;
    //       concurrent wait on different streams is the more likely use case
    for (auto index = 0; index < NUM_ELEMENTS_TO_ACQUIRE; ++index)
    {
      for (auto streamIndex = 0u; streamIndex < streams.size(); ++streamIndex)
      {
        const auto stream = streams[streamIndex];
        Cvb::MultiPartImagePtr multiPartImage;
        Cvb::WaitStatus waitStatus;
        Cvb::NodeMapEnumerator enumerator;
        std::tie(multiPartImage, waitStatus, enumerator) = stream->WaitFor(TIMEOUT);
        switch (waitStatus)
        {
        default:
          std::cout << "unknown wait status\n";
        case Cvb::WaitStatus::Abort:
        case Cvb::WaitStatus::Timeout:
        {
          std::cout << "wait status not ok: " << WAIT_ERROR_STATES[waitStatus] << "\n";;
          continue;
        }
        case Cvb::WaitStatus::Ok: break;
        }
        PrintOutAllPartTypes(*multiPartImage);
        auto element1 = multiPartImage->GetPartAt(0);
        if (!Cvb::holds_alternative<Cvb::ImagePtr>(element1))
        {
          std::cout << "multi part image does not contain an image as first element\n";
          continue;
        }
        auto image = Cvb::get<Cvb::ImagePtr>(element1);
        auto linearAccess = image->Plane(0).LinearAccess();
        std::cout << "Acquired image: #" << index + 1 << ", at address " << linearAccess.BasePtr() << " from stream " << streamIndex << "\n";
      }
    }
    // synchronous stop
    for (const auto stream : streams)
    {
      stream->Stop();
    }
  }
  catch (const std::exception& error)
  {
    std::cout << error.what() << std::endl;
  }
  return 0;
}
void PrintOutAllPartTypes(const Cvb::MultiPartImage& multiPartImage)
{
  const auto numParts = multiPartImage.NumParts();
  for (auto partIndex = 0; partIndex < numParts; ++partIndex)
  {
    const auto part = multiPartImage.GetPartAt(partIndex);
    std::cout << "part ";
    if (Cvb::holds_alternative<Cvb::ImagePtr>(part))
      std::cout << part.index() + 1 << " of " << numParts << " is an image\n";
    if (Cvb::holds_alternative<Cvb::PlanePtr>(part))
      std::cout << part.index() + 1 << " is a plane\n";
    if (Cvb::holds_alternative<Cvb::PlaneEnumeratorPtr>(part))
      std::cout << part.index() + 1 << " is a plane enumerator\n";
    if (Cvb::holds_alternative<Cvb::BufferPtr>(part))
      std::cout << part.index() + 1 << " is a buffer\n";
    if (Cvb::holds_alternative<Cvb::PFNCBufferPtr>(part))
      std::cout << part.index() + 1 << " is a pfnc buffer\n";
  }
}

For more details please refer to this page: https://help.commonvisionblox.com/API/C++/gen3acq.html
Regards,
Mandana

Hi @MandanaS
thank you for the reply. I was initially using multipart image, but later I wanted to try out composite stream. If my understanding is correct, the composite stream can give images as well as point clouds. Even I don’t have point clouds, I can still use composite stream to get the images from the buffers right ?
also, the multipart image uses Image streams which does not contain the Statistics function right ?

It says it is depricated from GenTL stack as given in the below link
https://help.commonvisionblox.com/API/C++/deprecated.html#_deprecated000002

So, how do i do it in case of GenTL stack ?

Hi ,

You can still use the composite stream but this generic stream type offers a dynamic payload interpretation, composed of the other interpretable object types. For example, this object type can combine buffers holding an Image, as well as a PointCloud, at the same time. A developer should be aware of the increased complexity when using this stream type.

When you use MultiPartImage example above you can get the statistics using enumerator which ist the result of Waitfor(TIMEOUT). This way you can get statistics using GenTL stack.

      auto vinBufferNodemap = enumerator["VinBuffer"];

      if (vinBufferNodemap->Node<Cvb::BooleanNode>("IsIncomplete")->Value())
      {
        ++numIncomplete;
      }

The Class Stream is depricated and not the ImageStream class used in the above example.

1 Like

Hi @MandanaS
I am currently logging the images by checking if the images received are complete or incomplete from the below lines of code. I am running my line scanner at maximum resolution of 4096x4096. With this i see almost 40% of images being incomplete.

If you don’t mind can you explain me how the IsIncomplete flag is being set ? Is it based on mere packet loss or is it something else ?

Hi @keerthitheja,

Yes the incomplete images are the ones with packet loss.