用于转换许多元素的 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 函数的更快版本?的主要内容,如果未能解决你的问题,请参考以下文章