将许多元素转换为二进制的更快版本的dec2bin函数是什么?

8
我正在读取一个位图文件,并将范围从0到255的每个RGB值转换为二进制。
因此,240x320位图将有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++中进行转换。这样做是否可行?

谢谢。


我不明白。在位图文件中,数值已经是二进制的了。你确切的需求是什么? - mouviciel
我希望它是0和1,因为我将在Matlab中对其进行调制。尽管0和1的值是双重的。 - HH.
4个回答

10

更快的方法是使用查找表。由于您知道所有的值都是介于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 

3
@Amro - 非常优雅。唯一需要补充的是最后加上reshape(binI,240,320,8),以获得与原始图像相同大小的答案。 - mtrw
1
非常好。我认为如果您像我在选项#2中那样使用BITGET来加速查找表的计算,您甚至可以更快地完成它:lookupTable = zeros(256,8,'uint8'); for i = 1:8, lookupTable(:,i) = bitget(0:255,9-i); end - gnovice
1
如果展开上面的循环,甚至可以更快:v = (0:255)'; lookupTable = [bitget(v,8) bitget(v,7) bitget(v,6) bitget(v,5) bitget(v,4) bitget(v,3) bitget(v,2) bitget(v,1)]; 我得到了大约0.0002秒的运行时间。 - gnovice
我刚刚添加了gnovice的建议(选项#2). 构建表格大约花费了0.00061011秒。 - Amro

4

选项1:循环遍历每个像素并使用BITGET

您可以循环遍历图像中的每个像素(或RGB值),并使用BITGET获取一个由0和1组成的向量。以下是使用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的向量化解决方案

可以创建一个向量化的解决方案,您可以在循环中遍历每个位(bit)而不是每个像素(pixel),每次通过循环对整个图像矩阵执行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-by-m)或3维(n-by-m-by-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.7秒。谢谢!!! - HH.
@HH:我添加的向量化选项比第一个选项快得多。在我的机器上,一个240x320的uint8矩阵平均只需要不到0.01秒就可以处理完毕! - gnovice

0

你不能直接使用 bitand 获取位吗?

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

等等...


0

这种问题(对大型数组执行逐元素操作,因为Matlab的内置代码太慢)有时需要在Java中找到解决方案,因为Matlab运行在JRE上,并且转换/传递数组参数通常是一个相当快速的操作。

gnovice的解决方案听起来适合您,但如果您遇到无法在纯Matlab中解决的情况,并且您精通Java,请考虑编写自定义JAR文件。这很容易。(比尝试将C ++与Matlab接口要容易得多!)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接