упаковка битов в массив байтов в Matlab

в Matlab я пытаюсь упаковать беззнаковые целые числа произвольной длины в битах (например, массив 3-битных целых чисел) в массив uint8. Учитывая совет здесь, я могу сгенерировать код, который работает для «маленьких» массивов (скажем, 10 000 элементов), но занимает всю память для больших массивов (например, 16 миллионов элементов). Код, который я использую, приведен ниже, он заимствован из предыдущих сообщений:

function x_bytes = stuff_bits(x, n)
    r = dec2bin(x,n);                 % bitstring for each uint in x
    s = reshape(r',[],1);             % one continuous string of bits
    t = reshape(str2num(s),8,[])';    % array of 8-bit numbers (stuffed)
    u = t*(2.^(size(t,2)-1:-1:0))';   % array of bytes representing all the bits stuffed together
    x_bytes = uint8(u);              % should be compressed byte stream
end

Я понимаю, что беру uint, конвертирую его в строку, а затем конвертирую обратно в бит; Я также читал, что dec2bin не очень эффективен.

Когда я пробую это с элементами 16mil (на 64-битной системе Windows с 8 ГБ памяти), вся память потребляется. Мля. Итак, я перебираю подразделы, и на выполнение элементов размером 16 мил требуется около 10 минут. Итак, что-то очень неэффективно.

У кого-нибудь есть лучший способ сгенерировать битовые строки, такие как BitArray в Python?

Благодарность,


person rocketman    schedule 23.01.2013    source источник
comment
Итак, вы начинаете с массива x десятичных чисел, и вы хотите преобразовать каждое из них в двоичное число постоянной длины (3 бита), а затем вы хотите сжать все 3-битные числа в последовательность битов и затем разделите его на uint8s? так x=[6 2 5 4] -> [110,010,101,100] -> [110010101100] ->[00001100,10101100] -> [12,172]? Или я не понимаю вопроса?   -  person user1860611    schedule 24.01.2013
comment
Кроме того, вы конвертируете t в 8 очень больших чисел, а не в набор 8-битных чисел. Попробуйте u=(2.^(7:-1:0))*t;   -  person user1860611    schedule 24.01.2013


Ответы (2)


Кажется, это похоже на этот и этот < / а>

На первом предлагалось использовать dec2bitvec внутри цикла for. Вам может хватить этого (хотя медленно).

Второй предлагает создать таблицу поиска с помощью bitget, а затем использовать ее (вместо использования dec2bit или dec2bitvec)

Вы можете попробовать использовать что-то «посередине».

B = 3; % Number of bits per int.
A = randi(7, 16000000, 1); % 16M random elements between 1 and 7 (3bits).

tic
% get each group of bits in a column of K.
K = cell2mat(arrayfun(@(bit)bitget(A, B+1-bit), 1:B, 'UniformOutput', 0))';
% reshape to have them in 8 packs
K = reshape(K, [8, numel(K)/8])';
% get the uint8 vec.
U = K*(2.^(size(K,2)-1:-1:0))';
toc

У меня прошло 3,5 секунды. (Win8 64 бита, i5 4 ГБ оперативной памяти)

Вместо создания таблицы поиска этот код создает матрицу (K) с битовыми значениями каждого целого числа (хранится в столбцах), изменяет ее форму (для создания значения 8bin), а затем использует ту же математику, что и раньше, для создания uint8 вектор.

person Mikhail    schedule 23.01.2013
comment
отличное решение - спасибо. Преобразование в строку и обратно должно было убить процесс. Ваше решение хранит все в двоичном виде. Поскольку у меня нет фиксированного количества битов во входном массиве (иногда у меня есть 3-битные числа, иногда 5-битные, иногда 12-битные), мне нужно было что-то обобщенное. - person rocketman; 24.01.2013
comment
@rocketman Я только что заметил, что это будет работать, только если общее количество бит делится на 8 (например, 3 бита * 16M элементов) из-за функции изменения формы. Чтобы он работал в любом случае, вам может потребоваться преобразовать его в вектор (1 x N), а затем добавить несколько бит в левой части перед изменением формы. - person Mikhail; 24.01.2013
comment
да - я согласен, что это работает только для B * numel (A) / 8, но это легко обеспечить. Приложение предназначено для уникального алгоритма сжатия данных изображения. Резко увеличена скорость ... с 450 секунд до 0,23 секунды. Большое спасибо! - person rocketman; 24.01.2013

Это код, который я создал для преобразования матрицы битов в числа длиной n бит:

function [ uD10 ] = bits_to_n_bit_integers( A, n)
%bits_to_n_bit_integersTurns vector matrix of bits in A into a vector matrix of 
%n bits long numbers. 
%B is 1 for a bit matrix
%   Detailed explanation goes here

B = 1;
% get each group of bits in a column of K.
K = cell2mat(arrayfun(@(bit)bitget(A, B+1-bit), 1:B, 'UniformOutput', 0))';
%make sure there is multiple of B
K = K(:);
while ~(mod(numel(K),n) == 0)
    K = [0;K];
end
K = K(:);
% reshape to have them in 8 packs
K = reshape(K, [n, numel(K)/n])';
% get the uint8 vec.
UD = K*(2.^(size(K,2)-1:-1:0))';

uD10=bi2de(K);

end

:)

person bonapart3    schedule 17.12.2014