I have an cv::Mat of doubles image that I've truncated between 0.0 and 4095.0. I want to be able to convert this matrix/create a new matrix based on this one that is 12bit. (smallest int size needed to hold 0 -> 4095 integer values). I can just get the raw buffer out, however I'm not sure the format of the data inside the matrix.
Manually I could do the following:
cv::Mat new_matrix(/*type CV_8UC3, size (matrix.rows, matrix.cols/2)*/);
for(int i = 0; i < matrix.rows; ++i){
for(int j = 0; j < matrix.cols; ++j){
std::uint16_t upper_half = static_cast<std::uint16_t>(matrix.at<double>(j*2,i));
std::uint16_t lower_half = static_cast<std::uint16_t>(matrix.at<double>(j*2+1,i));
std::uint8_t first_byte = static_cast<std::uint8_t>(upper_half>>4);
std::uint8_t second_byte = static_cast<std::uint8_t>(upper_half<<4) | static_cast<std::uint8_t>(lower_half << 12 >> 12);
std::uint8_t third_byte = static_cast<std::uint8_t>(lower_half>>4);
new_matrix.at<cv::Vec3B>(j, i) = cv::Vec3b(first_byte, second_byte, third_byte);
}
}
which is essentially compressing two double values to one for upper half, one for lower, extracting three bytes out of it (12 + 12 = 24, 24/8 = 3) into a 3 byte matrix. I'm unsure if the memory layout will match that of packed 12 bits however (I do have an even number of cols, so dividing cols/2 isn't a problem) and I'm not sure how to make sure this obeys endianess.
I might even be able to use a custom data type, but I would need to make sure that the elements are not padded if say I made a Union Struct 12bit type or something.
Note after the conversion, I'm not intending to use the 12bit values in OpenCV anymore, I then need to extract the raw values and they get sent to another separate process.