用于转换许多元素的 dec2bin 函数的更快版本?

Posted

技术标签:

【中文标题】用于转换许多元素的 dec2bin 函数的更快版本?【英文标题】:Faster version of dec2bin function for converting many elements? 【发布时间】:2010-12-05 09:25:33 【问题描述】:

我正在读取一个位图文件并将 每个从 0 到 255 的 RGB 值转换为二进制。

因此,一个 240 x 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++ 中进行转换。这是可取的吗?

谢谢。

【问题讨论】:

我不明白。在位图文件中,值已经是二进制的。您的具体需求是什么? 我希望它在 0 和 1 中,因为我将在 matlab 中对其进行调制。虽然 0 和 1 的值是两倍。 【参考方案1】:

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

【讨论】:

@Amro - 这真的很优雅。唯一要添加的可能是最终的 reshape(binI,240,320,8) 以获得与原始图像相同大小的答案.. 非常好。如果您像我在选项 #2 中那样使用 BITGET,我认为您可以进一步加快查找表的计算速度:lookupTable = zeros(256,8,'uint8'); for i = 1:8, lookupTable(:,i) = bitget(0:255,9-i); end ...如果您展开上述循环,甚至更快: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 的建议(选项#2)。构建表花费了大约 0.00061011 秒【参考方案2】:

选项 #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 的矢量化解决方案

可以创建一个矢量化解决方案,您可以循环遍历每个 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-D (n-by-m) 或 3-D (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:我添加的矢量化选项比第一个选项快很多。在我的机器上,一个 240×320 uint8 矩阵的处理时间平均不到 0.01 秒!【参考方案3】:

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

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

等等……

【讨论】:

【参考方案4】:

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

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

【讨论】:

以上是关于用于转换许多元素的 dec2bin 函数的更快版本?的主要内容,如果未能解决你的问题,请参考以下文章

在Excel中如何将十进制转换成二进制

excel表中如何将大于512的十进制转成二进制

求excel十进制转换二进制公式,能转换32位二进制?例如1007566779转换成二进制

排序向量查找的更快版本 (MATLAB)

matlab中位操作倒序函数bitrevorder怎么用?

在 pdo 准备好的语句中执行多插入或许多不同的插入更好/更快吗?