【问题标题】:Taking OpenCV Mat<doube> and converting to array of 12bit values.采用 OpenCV Mat<double> 并转换为 12 位值数组。
【发布时间】:2017-11-15 16:37:43
【问题描述】:

我有一个 cv::Mat 的双打图像,已在 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);
    }
}

本质上是将两个双精度值压缩为一个用于上半部分,一个用于下半部分,从中提取三个字节(12 + 12 = 24, 24/8 = 3)到一个 3 字节矩阵中。我不确定内存布局是否与打包的 12 位匹配(我确实有偶数列,所以除以 cols/2 不是问题)而且我不确定如何确保这符合字节序.

I might even be able to use a custom data type,但是如果说我制作了 Union Struct 12 位类型或其他东西,我需要确保元素没有被填充。

注意转换后,我不再打算在 OpenCV 中使用 12 位值,然后我需要提取原始值并将它们发送到另一个单独的进程。

【问题讨论】:

    标签: c++ opencv matrix type-conversion bit-packing


    【解决方案1】:

    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)
    

    【讨论】:

    • 我可能最终会接受这个答案,但直到稍后我才需要实现它,我现在会支持它。
    • 为什么不struct PackedSamples { int A : 12; int B : 12 };?如果(目标)字节顺序是大端,你不需要写{char highA; char highB : 4; char lowA : 4; char lowB; }吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 2012-10-19
    • 1970-01-01
    相关资源
    最近更新 更多