Faster version of dec2bin function for converting many elements? - matlab

I am reading a bitmap file and converting each of the RGB values ranging from 0 to 255 to binary.
So a 240 by 320 bitmap will have 230400 RGB values to convert. The original dec2bin function was too slow, so I wrote my own as I know my value will always be between 0 to 255.
But going through 230400 values will still take approx. 6sec on my machine, and a single colour bitmap will take about 2.3sec.
Is there anyway to speed things up to be under 1sec or even better 0.5sec, as every msec counts for my application?
Here is my code:
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
I was thinking if I'm not able to do it in MATLAB then maybe I'll do the conversion in C++. Is this advisable?
Thanks.

An even faster way is to use lookup tables. Since you know all the values are intensities between 0 and 255, you construct the binary equivalent of each to speed up the process.
% 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,:);
On my machine, it took on average 0.0036329 seconds (only the conversion). Note the lookup table has almost no space overhead:
>> whos lookupTable
Name Size Bytes Class Attributes
lookupTable 256x8 2048 uint8

Option #1: Loop over each pixel and use BITGET
You can loop over each pixel (or RGB value) in your image and use BITGET to get a vector of zeroes and ones. Here's an example of how to use 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
Option #2: Vectorized solution with BITGET
It's possible to create a vectorized solution where you loop over each bit instead of each pixel, performing a BITGET operation on the entire image matrix each time through the loop. The following is one such implementation:
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
If the matrix A is 2-D (n-by-m) or 3-D (n-by-m-by-p), the matrix B will be one dimension larger. The extra dimension will be of size N with the highest bit in index 1. You can either index into this dimension to get a bit value or reshape B to a more easily visualized form. Here's an example of the usage:
>> 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

Can't you use bitand to get the bits directly ?
s(0) = 256 bitand input
s(1) = 128 bitand input
s(2) = 64 bitand input
etc...

This kind of problem (perform a per-element operation on a large array, because Matlab's built-in code is too slow) sometimes calls for a solution in Java, since Matlab runs on a JRE and converting/passing array arguments is usually a fairly fast operation.
gnovice's solution sounds like it works for you, but if you run into a situation you can't solve in pure Matlab, and you're proficient in Java, consider writing a custom JAR file. It's pretty easy. (well, a whole lot easier than trying to interface C++ to Matlab!)

Related

How to Implement Box Function in better way in Matlab?

This function in Matlab presents Box_Function:
output = 1 while sample n belongs to the range (-a, +a).
otherwise the output is 0 outside that range.
So how can I implement this function in Matlab in a better way to shift the plot in case of negative values of time, without assigning negative values to the array.
Thanks in Advance
function B_X = Box_Func(N,K,a)
if(N <= 0)||(K+a > N)
warning('Please Enter Valid Positive Integer !');
else
B_X = zeros([-N N]);
for i = -N : 1 : N
if (i >= K-a) && (i <= K+a)
B_X(i)=1;
end
end
end
end
Your question is unclear since it does not really explain what you want to do, and in one comment you state that you know where the error comes from. I suggest to read the docs (also in a comment), but here I'll show you my problems with your code, provide some simple ways of testing your code and I hope this helps to solve your problem and to understand how to ask better questions.
First, one remark to the lines
if(N <= 0)||(K+a > N) % if samples Number wrong, or shifting exceeds limit
% of Samples Print a warning.
warning('Please Enter Valid Positive Integer !');
I suggest to throw an error instead of a warning if the input parameters are wrong and will lead to an error anyway. Otherwise you could omit the test and let Matlab throw the respective error.
The next misunderstanding is
B_X = zeros([-N N])
What do you expect B_X to be after this line if, let's say, N=2? Test if the result is what you expect by simply entering this command in the command line directly:
>> zeros([-2 2])
ans =
0×2 empty double matrix
I guess that's not what you expect. As the docs state, zeros(N) will yield a square matrix with N rows and N columns; zeros(M,N) will yield a matrix with M rows and N columns. Look:
>> zeros(2)
ans =
0 0
0 0
>> zeros(2,1)
ans =
0
0
I do not know what you expect from zeros([-2 2]), but I guess that you are looking for one of the following:
>> N = 2;
>> zeros(2*N+1,1)
ans =
0
0
0
0
0
>> zeros(1,2*N+1)
ans =
0 0 0 0 0
>> zeros(2*N+1)
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
My guess is that somehow you expect the function zeros to operate on some range of indices you provide. Your misunderstanding might be that you expect zeros([-2 2]) to provide a vector of zeros into which you can index using -2:2 (that is, one of -2,-1,0,+1,+2). If you assume this, your assumption is wrong.
I guess this from the line
for i = -N : 1 : N
in your code. Due to this line, I'll first thought that
>> B_X = zeros(1, 2*N+1)
B_X =
0 0 0 0 0
is what you expect. However, from the comment
% if samples Number wrong, or shifting exceeds limit
I guessed that N might be just the number of data points in the result. This would mean
>> B_X = zeros(1, N)
B_X =
0 0
(which would not make much sense for N=2). So, for the next question you ask (or an edit to this question): Clearly explain the meaning of the function inputs!
Since later, you set the limits of your x-axes to [-N N], I'll keep my first assumption, thus the number of data points (and therefore the argument to zeros) should be 2*N+1.
The next argument to your function is K, you call it the shift. k only occurs in combination with the third input of the function, a. You do not provide any inforamtion about a.
From this line I guess that a is something that specifies a width:
if (i >= K-a) && (i <= K+a)
Now, slowly, if one also considers
B_X(i)=1;
and the usage of the word box (and heaviside, which is still in the comments), one can get a clue of what you want to do. Together with your comment that you want your function
to appear on the plotting shifted on X Axis, so it looks like that the center of the Box Function is in the negative area of X axis
Might this be your goal: I want to plot a vector from -N to N (in steps of 1) with zero values except for the region of -K±a, where I want it to be one?
If this is the case, one attempt would be as follows (it remains to you to put it into a function):
>> N=15;
>> K=7;
>> a = 3;
Get the x-values:
>> x = -N:N;
(-15, -14, ... 14, 15). Next, allocate B_X:
>> B_X = zeros(1, 2*N+1);
Last, use logical indexing (this might help to understand this) to set the values around -K±a to one:
>> B_X(x>(-K-a) & x<(-K+a)) = 1;
Eventually, plot the result:
plot(x,B_X);
and adjust the axis limits:
>> ax=gca;
>> ax.YLim = [-.2 1.2];
Result is:
function B_X = Box_Func(N,K,a)
% Box_Func This Function takes Number of Samples N,Count of shift K, and
% half of Box width a then it stem Them ,
% Note it works only for positive shifting
% that means K should be positive or Zero
if(N <= 0)||(K+a > N) % if samples Number wrong, or shifting exceeds limit
% of Samples Print a warning.
warning('Please Enter Valid Positive Integer !');
else % if The inputs are fine , then :
B_X = zeros([1 2*N+1]);
x = -N:N;
B_X(x>=(K-a) & x<=(K+a)) = 1;
end
%===========================================
% Plotting the Results
%===========================================
figure('Name','Box Function','NumberTitle','off');
stem(x,B_X)
hold on
xlabel('Samples')
ylabel('Box Shifeted Function')
xlim([-N N]) ;
ylim([-1 2]);
grid on
hold off
end

MATLAB - Create repeated sequences of ones and zeros with loops

I am trying to create a single column vector (out), which is comprised of a sequence of ones and zeros. These should occur in sets of length B and C respectively, which are repeated A number of times. For example:
out=[1
0
0
1
0
0
1
0
0]
It is currently set up as:
out=[0]; %not ideal, but used to initially define 'out'
A=3;
B=1;
C=2;
for i = 1:length(A)
for ii = 1:length(B)
out(end+1,1) = ones(ii,1);
end
for iii = 1:length(C)
out(end+1,1) = zeros(iii,1);
end
end
This is not working - current output:
out=[0
1
0]
How can I correct these loops to get the desired output? Also, is there a better way of achieving this with the given the inputs?
Many thanks.
1) You do not need to use length as this returns the length of an array type, so A,B,C will all be length of 1.
2) Just directly use the values as shown below. Also you can initialize an empty array with empty brackets []
3) If you're using the zeros and ones commands, these generate whole arrays/matrices and do not need to be in a loop. If you want to keep your loop version, just use =1 or =0
out=[]; %--> you can use this instead
A=3;
B=1;
C=2;
for i = 1:A
out(end+1:end+B,1) = ones(B,1);
out(end+1:end+C,1) = zeros(C,1);
end
... or of course to be more "Matlaby" just do what David said in the comments repmat([ones(B,1);zeros(C,1)],A,1), but the above is there to help you on your way.
How about some modulo arithmetic?
result = double(mod(0:(B+C)*A-1, B+C)<B).';
Example:
>> B = 2; %// number of ones in each period
>> C = 4; %// number of zeros in each period
>> A = 3; %// number of periods
>> result = double(mod(0:(B+C)*A-1, B+C)<B).'
result =
1
1
0
0
0
0
1
1
0
0
0
0
1
1
0
0
0
0
I can suggest 2 ways:
a)Using for loop-
A=3;
B=2;
C=3;
OneVector=ones(1,B); % B is the length of ones.
zeroVector=zeros(1,C); % C is the length of zeros.
combinedVector=cat(2,OneVector,zeroVector);
Warehouse=[]; % to save data
for(i=1:A)
Warehouse=cat(2,Warehouse,combinedVector);
end
b)using repmat:
OneVector=ones(1,B); % B is the length of ones.
zeroVector=zeros(1,C); % C is the length of zeros.
combinedVector=cat(2,OneVector,zeroVector);
Warehouse=repmat(combinedVector, [A,1]);
I hope, this will solve your problem.

Hash function for binary matrices (Matlab)

I am working with big binary 2D matrices that are stored in a vector and every time a new matrix is obtained it is added to this vector, that can reach sizes of about 500 or 1000 elements. What I ask is if there is a more efficient way to store this matrices, maybe with a hash function. When there is a coincidence of two elements in the vector what I need is their position in the vector, not the matrix itself. I am working with Matlab.
this is executed after a new matrix is obtained:
states = [states new_state];
for i = 1:size(states,3)-1
if isequal(states(:,:,end), states(:,:,i))
found = 1;
num = size(states,3) - i;
break
end
end
matrices are binary:
new_state = [1 0 0 0; 0 0 0 1; 1 1 0 1; 1 1 0 0];

MATLAB: efficient generation of a large integer matrix of multi-indices

Let d and p be two integers. I need to generate a large matrix A of integers, having d columns and N=nchoosek(d+p,p) rows. Note that nchoosek(d+p,p) increases quickly with d and p, so it's very important that I can generate A quickly. The rows of A are all the multi-indices with components from 0 to p, such that the sum of the components is less than or equal to p. This means that, if d=3 and p=3, then A is an [N=nchoosek(3+3,3)=20x3] matrix with the following structure:
A=[0 0 0;
1 0 0;
0 1 0;
0 0 1;
2 0 0;
1 1 0;
1 0 1;
0 2 0;
0 1 1;
0 0 2;
3 0 0;
2 1 0;
2 0 1;
1 2 0;
1 1 1;
1 0 2;
0 3 0;
0 2 1;
0 1 2;
0 0 3]
It is not indispensable to follow exactly the row ordering I used, although it would make my life easier (for those interested, it's called graded lexicographical ordering and it's described here:
http://en.wikipedia.org/wiki/Monomial_order).
In case you are curious about the origin of this weird matrix, let me know!
Solution using nchoosek and diff
The following solution is based on this clever answer by Mark Dickinson.
function degrees = monomialDegrees(numVars, maxDegree)
if numVars==1
degrees = (0:maxDegree).';
return;
end
degrees = cell(maxDegree+1,1);
k = numVars;
for n = 0:maxDegree
dividers = flipud(nchoosek(1:(n+k-1), k-1));
degrees{n+1} = [dividers(:,1), diff(dividers,1,2), (n+k)-dividers(:,end)]-1;
end
degrees = cell2mat(degrees);
You can get your matrix by calling monomialDegrees(d,p).
Solution using nchoosek and accumarray/histc
This approach is based on the following idea: There is a bijection between all k-multicombinations and the matrix we are looking for. The multicombinations give the positions, where the entries should be added. For example the multicombination [1,1,1,1,3] will be mapped to [4,0,1], as there are four 1s, and one 3. This can be either converted using accumarray or histc. Here is the accumarray-approach:
function degrees = monomialDegrees(numVars, maxDegree)
if numVars==1
degrees = (0:maxDegree).';
return;
end
degrees = cell(maxDegree+1,1);
degrees{1} = zeros(1,numVars);
for n = 1:maxDegree
pos = nmultichoosek(1:numVars, n);
degrees{n+1} = accumarray([reshape((1:size(pos,1)).'*ones(1,n),[],1),pos(:)],1);
end
degrees = cell2mat(degrees);
And here the alternative using histc:
function degrees = monomialDegrees(numVars, maxDegree)
if numVars==1
degrees = (0:maxDegree).';
return;
end
degrees = cell(maxDegree+1,1);
degrees(1:2) = {zeros(1,numVars); eye(numVars);};
for n = 2:maxDegree
pos = nmultichoosek(1:numVars, n);
degrees{n+1} = histc(pos.',1:numVars).';
end
degrees = cell2mat(degrees(1:maxDegree+1));
Both use the following function to generate multicombinations:
function combs = nmultichoosek(values, k)
if numel(values)==1
n = values;
combs = nchoosek(n+k-1,k);
else
n = numel(values);
combs = bsxfun(#minus, nchoosek(1:n+k-1,k), 0:k-1);
combs = reshape(values(combs),[],k);
end
Benchmarking:
Benchmarking the above codes yields that the diff-solution is faster if your numVars is low and maxDegree high. If numVars is higher than maxDegree, then the histc solution will be faster.
Old approach:
This is an alternative to Dennis' approach of dec2base, which has a limit on the maximum base. It is still a lot slower than the above solutions.
function degrees = monomialDegrees(numVars, maxDegree)
Cs = cell(1,numVars);
[Cs{:}] = ndgrid(0:maxDegree);
degrees = reshape(cat(maxDegree+1, Cs{:}),(maxDegree+1)^numVars,[]);
degrees = degrees(sum(degrees,2)<=maxDegree,:);
I would solve it this way:
ncols=d;
colsum=p;
base=(0:colsum)';
v=#(dm)permute(base,[dm:-1:1]);
M=bsxfun(#plus,base,v(2));
for idx=3:ncols
M=bsxfun(#plus,M,v(idx));
end
L=M<=colsum;
A=cell(1,ncols);
[A{:}]=ind2sub(size(L),find(L));
a=cell2mat(A);
%subtract 1 because 1 based indexing but base starts at 0
a=a-1+min(base);
It builds up a p-dimensional matrix which contains the sum. The efficiency of this code depends on sum(L(:))/numel(L), this quotient tells you how much of the created matrix is actually used for solutions. If this gets low for your intput, there probably exits a better solution.
Here is a very easy way to do it:
L = dec2base(0:4^3-1,4);
idx=sum(num2str(L)-'0',2)<=3;
L(idx,:)
I think the first line can be very time efficient for creating a list of candidates, but unfortunately I don't know how to reduce the list in an efficient way after that.
So the second line works, but could use improvement performance wise.

embedding a character in an image

So here is what I was trying to do. I'm absolutely new to matlab. It has only been a day or so that I've used it and here is a little something that my teacher had asked me to do. Embed statements or group of strings within an image using the LSB Algorithm. The string is to be read from a file.
As of now, I've not used any file operations. I'm trying this using one character and I don't know whats wrong. The algo seems simple but my output i.e, both the cover and the steg pixels show the same value. :(
cover=imread('D:\l.jpg');
steg=cover;
l=1;
LSB=0;
height = size (cover, 1);
width = size (cover, 2);
message = 'J' ;
mdec = uint8(message);
mbin = dec2bin(mdec, 8);
mbins= mbin(:);
len=length(mbins);
for i = 1:height
for j = 1:width
if(l<=len)
LSB = mod(cover(i,j), 2);
if(mbins(l)==LSB)
steg(i,j) = cover(i,j);
else if (mbins(l)~=LSB && LSB==1 && mbins(l)==0)
steg(i,j) = cover(i,j)-1;
else if (mbins(l)~=LSB && LSB==0 && mbins(l)==1)
steg(i,j) = cover(i,j)+1;
end
end
end
l=l+1;
end
end
end
imwrite(steg,'D:\hidden.jpg');
%imshow(steg)
cover(1, 1:8)
steg(1, 1:8)
Oh, nested loops... that's not the way to go.
You want to replace the least significant bits of the first l pixels with the binary ascii representation of your input string.
First thing that went wrong - converting char to binary:
Converting a character to its binary representation should be done using bitget
>> bitget( uint8('J'), 1:8 )
0 1 0 1 0 0 1 0
Gives back 1-by-8 binary array, while using dec2bin:
>> dec2bin( uint8('J'), 8 )
01001010
Gives back 1-by-8 string: the actual numeric values of this array are
>> uint8(dec2bin( uint8('J'), 8 ))
48 49 48 48 49 48 49 48
Can you appreciate the difference between the two methods?
If you insist on using dec2bin, consider
>> dec2bin( uint8('J'), 8 ) - '0'
0 1 0 0 1 0 1 0
Second point - nested loops:
Matlab favors vector/matrix vectorized operations rather than loops.
Here's a nice way of doing it without loops, assuming cover is a gray scale image (that is it has a single color channel rather than 3) of type uint8.
NoLsb = bitshift( bitshift( cover, -1 ), 1 ); %// use shift operation to set lsb to zero
lsb = cover - NoLsb; %// get the lsb values of ALL pixels
lsb( 1:l ) = mbins; %// set lsb of first l pixels to bits of message
steg = NoLsb + lsb; %// this is it!