Image Saving Time Considerations

Hi,
just a small code example to compare different file saving times with CVB.

Code is in the attachments. (it makes some assumptions about pixelformats, which may not be true in your case.

Results are in std::chrono::microseconds (taken with a pinch of doubt about accuracy)

CMakeList.txt (may not work without changes on Linux):

cmake_minimum_required(VERSION 3.5)
project(saveTest)

set (CMAKE_CXX_STANDARD 17)

#find CVB
file(TO_CMAKE_PATH "$ENV{CVB}/cmake" CVB_MODULE_PATH)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CVB_MODULE_PATH}")
find_package(CVB REQUIRED)

add_executable(saveTest main.cpp ${SOURCES} ${HEADERS})

target_link_libraries(saveTest CVB::CVCDriver CVB::CVCUtilities)

if(UNIX)
  target_link_libraries(saveTest pthread)
endif()

main.cpp:

#include <iostream>
#include <chrono>
#include <fstream>

#include <cvb/device_factory.hpp>
#include <cvb/utilities/system_info.hpp>
#include <cvb/driver/stream.hpp>

void dumpRawImage(Cvb::Image& image, const std::string& filename)
{
  // warning these tests are not complete
  if (image.PlanesCount() != 1)
    throw std::runtime_error("single plane images only");

  const auto linAccess = image.Plane(0).LinearAccess();

  if (linAccess.XInc() < 1 || linAccess.YInc() < 1)
    throw std::runtime_error("weird increments found");

  const auto size = image.Height() * linAccess.YInc();
  const auto basePtr = reinterpret_cast<char*>(linAccess.BasePtr());

  const auto flags = std::ios::out | std::ios::binary;

  auto file = std::fstream(filename, flags);

  if (!file.good())
    throw std::runtime_error("failed to open file");

  file.write(basePtr, size);
  file.close();
}

template<typename Callable>
long long measureTime(Callable c)
{
  // warning: high_resolution does not mean high_accuracy!
  auto before = std::chrono::high_resolution_clock::now();
  c();
  auto after = std::chrono::high_resolution_clock::now();
  return std::chrono::duration_cast<std::chrono::microseconds>(after - before).count();
}

void saveImage(Cvb::Image& image)
{
  static int index = 0;
  auto prefix = "C:\\temp\\" + std::to_string(index++);

  // raw
  auto msRaw = measureTime([&image, &prefix] {dumpRawImage(image, prefix + ".raw"); });

  // the usual suspects
  auto msJpg = measureTime([&image, &prefix] {image.Save(prefix + ".jpg"); });
  auto msTif = measureTime([&image, &prefix] {image.Save(prefix + ".tiff"); });
  auto msPng = measureTime([&image, &prefix] {image.Save(prefix + ".png"); });
  auto msBmp = measureTime([&image, &prefix] {image.Save(prefix + ".bmp"); });


  std::cout << "jpg: " << msJpg << " | tif: " << msTif << " | png: " << msPng << " | bmp: " << msBmp << " | raw: " << msRaw << "\n";
}

int main(int argc, char* argv[])
{
  const int NUM_IMAGES = 20;

  auto flags = Cvb::DiscoverFlags::IgnoreVins;
#ifdef WIN32
  flags = flags | Cvb::DiscoverFlags::IgnoreGevSD;
#endif

  const auto timeout = std::chrono::seconds(10);

  try
  {
    // find all cams
    auto tokens = Cvb::DeviceFactory::Discover(flags);

    // open/test all cams serially
    for (auto& token : tokens)
    {
      token.SetParameter("NumBuffer", std::to_string(NUM_IMAGES + 1)); // (too) large Ringbuffer, we only care about image saving time.
      token.SetParameter("PixelFormat", "1"); // Enforce MONO8

      auto device = Cvb::DeviceFactory::Open(token.AccessToken());
      auto stream = device->Stream();
      stream->Start();

      for (int i = 0; i < NUM_IMAGES; ++i)
      {
        auto waitResult = stream->WaitFor(timeout);
        if (waitResult.Status == Cvb::WaitStatus::Timeout)
          throw std::runtime_error("acquisition timeout");

        saveImage(*waitResult.Image);
      }

      stream->Stop();
    }
  }
  catch (const std::exception& error)
  {
    std::cout << "something went wrong: " << error.what() << std::endl;
  }
}
1 Like

Different image size and slightly different question, but still one additional data point: https://forum.commonvisionblox.com/t/different-performance-when-saving-different-formats/252/4

I also enforce MONO8, which might be bad for some formats.