0

I am trying to compose cv::Mat image from std::basic_string<char> but the composed image is empty. Below is the code snippet:

std::basic_string<char> color_pixels = color_frame.data();
cv::Mat image(cv::Size(color_frame.width(), color_frame.height()),
              CV_8UC4,
              &color_pixels,
              cv::Mat::AUTO_STEP);

Before proceeding further, I wanted to verify the data. Hence I checked width, height etc and found correct.

std::cout << "width:" << color_frame.width() <<
          ", height:" << color_frame.height() << 
          ", length:" <<  color_pixels.length() << std::endl;
width:1920, height:1080, length:8294400 // 1920 * 1080 * 4 = 8294400

I found a similar question here and tried to implement in my code as follows:

cv::Mat image(cv::Size(color_frame.width(), color_frame.height()),
              CV_8UC4,
              color_pixels.data(),
              cv::Mat::AUTO_STEP);

Unfortunately, it is throwing following error:

error: invalid conversion from ‘const void*’ to ‘void*’

How to compose cv::Mat Image from std::basic_string? Any workaround, please?

ravi
  • 6,140
  • 18
  • 77
  • 154
  • Why do you put the image data into a `string` in the first place? I mean, there appear to be other more suitable options, even a `std::vector` would be more convenient... – Dan Mašek Dec 19 '17 at 18:28
  • 1
    @DanMašek: I tried `std::vector color_pixels = color_frame.data()` and got `error: conversion from ‘const string {aka const std::basic_string}’ to non-scalar type ‘std::vector’ requested`. To be more precise, `color_frame.data()` is refering to [bytes](https://developers.google.com/protocol-buffers/docs/proto?csw=1#scalar) in [Protocol Buffers](https://developers.google.com/protocol-buffers/). – ravi Dec 20 '17 at 02:58

2 Answers2

1

color_pixels.data() is a const value.

http://en.cppreference.com/w/cpp/string/basic_string/data

Oscar de Leeuw
  • 126
  • 2
  • 6
  • Please see the reference which I liked to the question. How does your answer solve the question? – ravi Dec 19 '17 at 08:02
  • If you checked the reference I linked you could see you can use c++17 to get a non-const reference to the data. Else create a vector of `unsigned char` from the string data and use the vector, a method that's clearly explained in the reference you linked. Else you can `const_cast` the `string::data` http://en.cppreference.com/w/cpp/language/const_cast – Oscar de Leeuw Dec 19 '17 at 08:24
  • Thank you very much. casting is easy. – ravi Dec 19 '17 at 09:32
1

In C++, void* can be used to represent a pointer to some unspecified, valid memory address (internally, this will be either passed to some low-level API, like C memcpy, or casted to some meaningful type according to the given interface contract). IMHO, this is seldom if ever necessary in the modern C++ type system (and function dealing with memory can use std::byte now), but C++ libraries using it sadly still exist.

Anyway, coming back to your question, you can implicitly convert any pointer to void*, but you cannot implictly cast-away constness. You need const_cast for that:

cv::Mat image(cv::Size(color_frame.width(), color_frame.height()),
              CV_8UC4,
              const_cast<char*>(color_pixels.data()),
              cv::Mat::AUTO_STEP);

A few caveats:

  • in >=C++11, if color_pixels were originally const, any attempt to modify color_pixels data via image will result in undefined behaviour.

  • in C++<=03, data() were not required to point to the original string characters, so any modification attempt would be UB in that case.

  • invoking color_pixels modifiers invalidating its content will make invoking most image methods UB as well.

Massimiliano Janes
  • 5,524
  • 1
  • 10
  • 22
  • Thank you very much for the nice explanation. I am using `C++11` and it works like a charm. However, I do have one small question. I realized that I need to flip the data using `cv::flip(image, image, 1)` to get the exact image. Why so? Any idea? – ravi Dec 19 '17 at 09:31
  • 1
    @RaviJoshi a cv::Mat is just a matrix, it has no notion of 'up' and 'down'; what goes 'up' depends on both the end drawing coordinate system and the original data row ordering (and it's usually more complex than that, you can have padding, multiple color planes, different formats, different transfer functions, etc ... ). – Massimiliano Janes Dec 19 '17 at 10:09