Взять OpenCV Mat‹doube› и преобразовать в массив 12-битных значений.

У меня есть изображение cv::Mat of doubles, которое я обрезал между 0,0 и 4095,0. Я хочу иметь возможность преобразовать эту матрицу/создать новую матрицу на основе этой 12-битной. (наименьший размер int, необходимый для хранения 0 -> 4095 целочисленных значений). Я могу просто получить необработанный буфер, однако я не уверен в формате данных внутри матрицы.

Вручную я мог бы сделать следующее:

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 бит (у меня четное число столбцов, поэтому деление столбцов/2 не является проблемой), и я не уверен, как убедиться, что это подчиняется порядку байтов. .

Я мог бы даже использовать пользовательский тип данных, но мне нужно убедиться, что элементы не дополняются, если, скажем, я создал 12-битный тип Union Struct или что-то в этом роде.

Обратите внимание, что после преобразования я больше не собираюсь использовать 12-битные значения в OpenCV, затем мне нужно извлечь необработанные значения, и они будут отправлены в другой отдельный процесс.


person Krupip    schedule 13.06.2017    source источник


Ответы (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)
person Michaël Roy    schedule 13.06.2017
comment
Я, вероятно, в конечном итоге приму этот ответ, но мне не нужно будет реализовывать это позже, я пока проголосую за это. - person Krupip; 19.06.2017
comment
Почему не struct PackedSamples { int A : 12; int B : 12 };? И если бы (целевой) порядок байтов был с обратным порядком байтов, разве вам не нужно было бы писать {char highA; char highB : 4; char lowA : 4; char lowB; }? - person chtz; 19.07.2017