Более быстрая версия функции dec2bin для преобразования многих элементов? - PullRequest
8 голосов
/ 09 октября 2009

Я читаю файл растрового изображения и преобразую каждое значений RGB в диапазоне от 0 до 255 в двоичный файл.

Таким образом, растровое изображение размером 240 на 320 будет иметь 230400 значений RGB для преобразования. Первоначальная функция dec2bin была слишком медленной, поэтому я написал свою собственную, поскольку знаю, что мое значение всегда будет в диапазоне от 0 до 255.

Но через 230400 значений все равно потребуется ок. 6 секунд на моей машине, и одноцветное растровое изображение займет около 2,3 секунды.

Есть ли способ ускорить процесс до 1 секунды или даже лучше 0,5 секунды, поскольку каждая мс считается для моего приложения?

Вот мой код:

function s = dec2bin_2(input)

if input == 255
    s = [1;1;1;1;1;1;1;1];
    return;
end

s = [0;0;0;0;0;0;0;0];

if input == 0
    return;
end

if input >= 128
    input = input - 128;
    s(1) = 1;
    if input == 0
        return;
    end
end

if input >= 64
    input = input - 64;
    s(2) = 1;
    if input == 0
        return;
    end
end

if input >= 32
    input = input - 32;
    s(3) = 1;
    if input == 0
        return;
    end
end

if input >= 16
    input = input - 16;
    s(4) = 1;
    if input == 0
        return;
    end
end

if input >= 8
    input = input - 8;
    s(5) = 1;
    if input == 0
        return;
    end
end

if input >= 4
    input = input - 4;
    s(6) = 1;
    if input == 0
        return;
    end
end

if input >= 2
    input = input - 2;
    s(7) = 1;
    if input == 0
        return;
    else
        s(8) = 1;
    end
end
end

Я думал, что если я не смогу сделать это в MATLAB, тогда, возможно, я сделаю преобразование в C ++. Желательно ли это?

Спасибо.

Ответы [ 4 ]

10 голосов
/ 09 октября 2009

Еще более быстрый способ - использовать справочные таблицы. Поскольку вы знаете, что все значения являются интенсивностями от 0 до 255, вы создаете двоичный эквивалент каждого для ускорения процесса.

% build table (computed once) [using gnovice option#1]
lookupTable = cell2mat(arrayfun(@(i)bitget([0:255]',9-i),1:8,'UniformOutput',0));

% random' image
I = randi(256, [240 320])-1;

% decimal to binary conversion
binI = lookupTable(I(:)+1,:);

На моей машине это заняло в среднем 0,0036329 секунд (только преобразование). Обратите внимание, что в таблице поиска почти нет места:

>> whos lookupTable
  Name               Size            Bytes  Class    Attributes
  lookupTable      256x8              2048  uint8 
4 голосов
/ 09 октября 2009

Вариант № 1: зацикливание на каждом пикселе и использование BITGET

Вы можете зациклить каждый пиксель (или значение RGB) на своем изображении и использовать BITGET , чтобы получить вектор нулей и единиц. Вот пример того, как использовать BITGET:

>> bitget(uint8(127),8:-1:1)  % Get bits 8 through 1 for a uint8 value

ans =

    0    1    1    1    1    1    1    1

Вариант № 2: Векторизованное решение с BITGET

Можно создать векторизованное решение, в котором вы зациклились бы над каждым битом вместо каждого пикселя , выполняя операцию BITGET для всей матрицы изображения каждый раз через цикл. Ниже приведена одна из таких реализаций:

function B = get_bits(A,N)
  % Gets the N lowest bits from each element of A
  B = zeros([size(A) 0]);
  nDims = ndims(A)+1;
  for iBit = N:-1:1
    B = cat(nDims,B,bitget(A,iBit));
  end
end

Если матрица A имеет размеры 2-мерный (n-на-м) или 3-мерный (n-на-м-на-p), матрица B будет на один размер больше. Дополнительное измерение будет иметь размер N с самым старшим битом в индексе 1. Вы можете либо индексировать это измерение, чтобы получить значение бита, либо преобразовать B в более легко визуализируемую форму. Вот пример использования:

>> A = uint8([126 128; 127 129]);  % A 2-by-2 matrix of uint8 values
>> B = get_bits(A,8);              % B is a 2-by-2-by-8 matrix
>> B(:,:,1)                        % Get bit 8 for each value in A

ans =

     0     1
     0     1

>> reshape(B,4,8)                  % Reshape B into a 4-by-8 matrix

ans =

     0     1     1     1     1     1     1     0
     0     1     1     1     1     1     1     1
     1     0     0     0     0     0     0     0
     1     0     0     0     0     0     0     1
0 голосов
/ 11 октября 2009

Проблема такого рода (выполнение операции для каждого элемента в большом массиве, поскольку встроенный код Matlab слишком медленный) иногда требует решения в Java, поскольку Matlab работает на JRE, а преобразование / передача аргументов массива обычно довольно быстрая операция.

Решение gnovice звучит так, как будто оно работает для вас, но если вы столкнулись с ситуацией, которую вы не можете решить в чистом Matlab, и вы владеете Java, подумайте о написании собственного файла JAR. Это довольно легко. (ну, намного проще, чем пытаться связать C ++ с Matlab!)

0 голосов
/ 09 октября 2009

Разве вы не можете использовать bitand, чтобы получить биты напрямую?

s(0) = 256 bitand input
s(1) = 128 bitand input
s(2) = 64 bitand input

и т.д ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...