Before I go re-invent the wheel, does anyone have a function to convert a 3-channel OpenCV cv::Mat to JUCE’s Image?
Example function that manipulates a OpenCV cv::Mat object and returns a JUCE Image object:
Image convert_opencv_mat_to_juce_image()
{
const std::string filename = "samples/data/HappyFish.jpg";
const int desired_width = 320;
const int desired_height = 200;
// read in an example image, either colour or greyscale to ensure
// we can handle both when converting a cv::Mat to a JUCE Image
cv::Mat original = cv::imread(filename, cv::IMREAD_COLOR); // cv::IMREAD_GRAYSCALE
// resize the image to the final dimensions we'll need (see size defined at top of function)
cv::Mat resized;
cv::resize(original, resized, cv::Size(desired_width, desired_height), 0, 0, cv::INTER_AREA);
// if the image has 1 channel we'll convert it to greyscale RGB
// if the image has 3 channels (RGB) then all is good,
// (anything else will cause this function to throw)
cv::Mat source;
switch (resized.channels())
{
case 1:
cv::cvtColor(resized, source, cv::COLOR_GRAY2BGR);
break;
case 3:
source = resized; // nothing to do, use the image as-is
break;
default:
throw std::logic_error("cv::Mat has an unexpected number of channels (" + std::to_string(resized.channels()) + ")");
}
// create a JUCE Image the exact same size as the OpenCV mat we're using as our source
Image image(Image::RGB, source.cols, source.rows, false);
// iterate through each row of the image, copying the entire row as a series of consecutive bytes
const size_t number_of_bytes_to_copy = 3 * source.cols; // times 3 since each pixel contains 3 bytes (RGB)
Image::BitmapData bitmap_data(image, 0, 0, source.cols, source.rows, Image::BitmapData::ReadWriteMode::writeOnly);
for (int row_index = 0; row_index < source.rows; row_index ++)
{
uint8_t * src_ptr = source.ptr(row_index);
uint8_t * dst_ptr = bitmap_data.getLinePointer(row_index);
std::memcpy(dst_ptr, src_ptr, number_of_bytes_to_copy);
}
return image;
}
I’m running on Intel/AMD aka little-endian hardware. If your specific hardware uses a different format for byte ordering between OpenCV and JUCE, then I think inserting this line after the switch
block will resolve the red-blue channel swap:
cv::cvtColor(source, source, cv::COLOR_BGR2RGB); // BGR -> RGB
5 Likes