我有一个 cv::Mat of double 图像,我在 0.0 和 4095.0 之间截断了它。我希望能够转换这个矩阵/创建一个基于这个 12 位矩阵的新矩阵。 (保存 0 -> 4095 个整数值所需的最小 int 大小)。我可以取出原始缓冲区,但我不确定矩阵内数据的格式。
我可以手动执行以下操作:
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);
}
}
本质上是将两个 double 值压缩为一个用于上半部分,一个用于下半部分,从中提取三个字节 (12 + 12 = 24, 24/8 = 3) 到一个 3 字节矩阵中。我不确定内存布局是否与打包的 12 位相匹配(我确实有偶数个 cols,所以除 cols/2 不是问题)而且我不确定如何确保它遵守字节顺序.
I might even be able to use a custom data type ,但如果说我制作了 Union Struct 12 位类型或其他类型,我需要确保不填充元素。
注意转换后,我不打算再在 OpenCV 中使用 12 位值,然后我需要提取原始值并将它们发送到另一个单独的进程。
最佳答案
cv::Mat 将以 8 位为单位存储数据,最少。这意味着您的 12 位值无论如何都会被填充到矩阵内部,如 Mat::elemSize1() 的返回值所证明的那样,它以字节数为单位。对于您需要做的事情,最好的选择似乎是使用一个包含 2 个值的自定义结构(结构大小也是字节填充的),然后将所有内容打包在一个 std::vector<> 中。当您的样本数量为奇数时,您将在流数据上浪费最坏的 12 位填充。
关于打包的注意事项:如果您使用类似下面的东西,如果您需要将字节从一种体系结构传输到另一种体系结构,则需要根据机器反转位大小元素的顺序。
#pragma pack(push, 1)
struct PackedSamples {
char lowA;
char highA : 4; // NOTE: the declaration of bit sized fields order is inverse when
char lowB : 4; // going from BIG_ENDIAN to SMALL_ENDIAN and vice-versa
char highB;
};
#pragma pack(pop)
这是我用来测试字节顺序的宏,我假设 Windows 在 x86/x64 上运行。 AMD 是 __BIG_ENDIAN。
#ifdef WIN32
# ifndef __BYTE_ORDER
# define __LITTLE_ENDIAN 1234
# define __BIG_ENDIAN 4321
# define __BYTE_ORDER __LITTLE_ENDIAN
# endif
#else
# include <endian.h>
#endif
所以上面的声明会变成:
#pragma pack(push, 1)
struct PackedSamples {
char lowA;
#if __BYTE_ORDER == __LITTLE_ENDIAN
char highA : 4;
char lowB : 4;
#else
char lowB : 4;
char highA : 4;
#endif
char highB;
};
#pragma pack(pop)
关于c++ - 采用 OpenCV Mat<double> 并转换为 12 位值的数组。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44529305/