MATLAB M x N x 24 array to bitmap - image

I am working in MATLAB.
I have a an array of M x N and I fill it with 1 or 0 to represent a binary pattern. I have 24 of these "bit planes", so my array is M x N x 24.
I want to convert this array into a 24 bit M x N pixel bitmap.
Attempts like:
test = image(1:256,1:256,1:24);
imwrite(test,'C:\test.bmp','bmp')
Produce errors.
Any help and suggestions would be appreciated.

Let's assume A is the input M x N x 24 sized array. I am also assuming that those 24 bits in each of its 3D "slices" have the first one-third elements for the red-channel, next one-third for the green-channel and rest one-third as blue-channel elements. So, with these assumptions in mind, one efficient approach using the fast matrix multiplication in MATLAB could be this -
%// Parameters
M = 256;
N = 256;
ch = 24;
A = rand(M,N,ch)>0.5; %// random binary input array
%// Create a 3D array with the last dimension as 3 for the 3 channel data (24-bit)
Ar = reshape(A,[],ch/3,3);
%// Concatenate along dim-3 and then reshape to have 8 columns,
%// for the 8-bit information in each of R, G and B channels
Ar1 = reshape(permute(Ar,[1 3 2]),M*N*3,[]);
%// Multiply each bit with corresponding multiplying factor, which would
%// be powers of 2, to create a [0,255] data from the binary data
img = reshape(Ar1*(2.^[7:-1:0]'),M,N,3); %//'
%// Finally convert to UINT8 format and write the image data to disk
imwrite(uint8(img), 'sample.bmp')
Output -

%some example data
I=randi([0,1],256,256,24);
%value of each bit
bitvalue=permute(2.^[23:-1:0],[3,1,2])
%For each pixel, the first bit get's multiplied wih 2^23, the second with 2^22 and so on, finally summarize these values.
sum(bsxfun(#times,I,bitvalue),3);
To understand this code, try debugging it with input I=randi([0,1],1,1,24);

Related

How to construct a loop with reducing iterations

In MATLAB, I have a 256x256 RGB image and a 3x3 kernel that passes over it. The 3x3 kernel computes the colour-euclidean distance between every pair combination of the 9 pixels in the kernel, and stores the maximum value in an array. It then moves by 1 pixel and performs the same computation, and so on.
I can easily code the movement of the kernel over the image, as well as the extraction of the RGB values from the pixels in the kernel.
HOWEVER, I do have trouble efficiently computing the colour-euclidean distance operation for every pair combination of pixels.
For example if I had a 3x3 matrix with the following values:
[55 12 5; 77 15 99; 124 87 2]
I need to code a loop such that the 1st element performs an operation with the 2nd,3rd...9th element. Then the 2nd element performs the operation with the 3rd,4th...9th element and so on until finally the 8th element performs the operation with the 9th element. Preferrably, the same pixel combination shouldn't compute again (like if you computed 2nd with 7th, don't compute 7th with 2nd).
Thank you in advance.
EDIT: My code so far
K=3;
s=1; %If S=0, don't reject, If S=1 Reject first max distance pixel pair
OI=imread('onion.png');
Rch = im2col(OI(:,:,1),[K,K],'sliding')
Gch = im2col(OI(:,:,2),[K,K],'sliding')
Bch = im2col(OI(:,:,3),[K,K],'sliding')
indexes = bsxfun(#gt,(1:K^2)',1:K^2)
a=find(indexes);
[idx1,idx2] = find(indexes);
Rsqdiff = (Rch(idx2,:) - Rch(idx1,:)).^2
Gsqdiff = (Gch(idx2,:) - Gch(idx1,:)).^2
Bsqdiff = (Bch(idx2,:) - Bch(idx1,:)).^2
dists = sqrt(double(Rsqdiff + Gsqdiff + Bsqdiff)) %Distance values for all 36 combinations in 1 column
[maxdist,idx3] = max(dists,[],1) %idx3 is each column's index of max value
if s==0
y = reshape(maxdist,size(OI,1)-K+1,[]) %max value of each column (each column has 36 values)
elseif s==1
[~,I]=max(maxdist);
idx3=idx3(I);
n=size(idx3,2);
for i=1:1:n
idx3(i)=a(idx3(i));
end
[I,J]=ind2sub([K*K K*K],idx3);
for j=1:1:a
[M,N]=ind2sub([K*K K*K],dists(j,:));
M(I,:)=0;
N(:,J)=0;
dists(j,:)=sub2ind; %Incomplete line, don't know what to do here
end
[maxdist,idx3] = max(dists,[],1);
y = reshape(maxdist,size(OI,1)-K+1,[]);
end
If I understood the question correctly, you are looking to form unique pairwise combinations within a sliding 3x3 window, perform euclidean distance calculations consider all three channels, which we are calling as colour-euclidean distances and finally picking out the largest of all distances for each sliding window. So, for a 3x3 window that has 9 elements, you would have 36 unique pairs. If the image size is MxN, because of the sliding nature, you would have (M-3+1)*(N-3+1) = 64516 (for 256x256 case) such sliding windows with 36 pairs each, and therefore the distances array would be 36x64516 sized and the output array of maximum distances would be of size 254x254. The implementation suggested here involves im2col to extract sliding windowed elements as columns, nchoosek to form the pairs and finally performing the square-root of squared differences between three channels of such pairs and would look something like this -
K = 3; %// Kernel size
Rch = im2col(img(:,:,1),[K,K],'sliding')
Gch = im2col(img(:,:,2),[K,K],'sliding')
Bch = im2col(img(:,:,3),[K,K],'sliding')
[idx1,idx2] = find(bsxfun(#gt,(1:K^2)',1:K^2)); %//'
Rsqdiff = (Rch(idx2,:) - Rch(idx1,:)).^2
Gsqdiff = (Gch(idx2,:) - Gch(idx1,:)).^2
Bsqdiff = (Bch(idx2,:) - Bch(idx1,:)).^2
dists = sqrt(Rsqdiff + Gsqdiff + Bsqdiff)
out = reshape(max(dists,[],1),size(img,1)-K+1,[])
Your question is interesting and caught my attention. As far as I understood, you need to calculate euclidean distance between RGB color values of all cells inside 3x3 kernel and to find the largest one. I suggest a possible way to do this by using circshift function and 4D array operations:
Firstly, we pad the input array and create 8 shifted versions of it for each direction:
DIM = 256;
A = zeros(DIM,DIM,3,9);
A(:,:,:,1) = round(255*rand(DIM,DIM,3));%// random 256x256 array (suppose it is your image)
A = padarray(A,[1,1]);%// add zeros on each side of image
%// compute shifted versions of the input array
%// and write them as 4th dimension starting from shifted up clockwise:
A(:,:,:,2) = circshift(A(:,:,:,1),[-1, 0]);
A(:,:,:,3) = circshift(A(:,:,:,1),[-1, 1]);
A(:,:,:,4) = circshift(A(:,:,:,1),[ 0, 1]);
A(:,:,:,5) = circshift(A(:,:,:,1),[ 1, 1]);
A(:,:,:,6) = circshift(A(:,:,:,1),[ 1, 0]);
A(:,:,:,7) = circshift(A(:,:,:,1),[ 1,-1]);
A(:,:,:,8) = circshift(A(:,:,:,1),[ 0,-1]);
A(:,:,:,9) = circshift(A(:,:,:,1),[-1,-1]);
Next, we create an array that calculates the difference for all the possible combinations between all the above arrays:
q = nchoosek(1:9,2);
B = zeros(DIM+2,DIM+2,3,size(q,1));
for i = 1:size(q,1)
B(:,:,:,i) = (A(:,:,:,q(i,1)) - A(:,:,:,q(i,2))).^2;
end
C = sqrt(sum(B,3));
Finally, what we have is all the euclidean distances between all possible pairs within a 3x3 kernel. All we have to do is to extract the maximum values. As far as I understood, you do not consider image edges, so:
C = sqrt(sum(B,3));
D = zeros(DIM-2);
for i = 3:DIM
for j = 3:DIM
temp = C(i-1:i+1,j-1:j+1);
D(i-2,j-2) = max(temp(:));
end
end
D is the 254x254 array with maximum Euclidean distances for A(2:255,2:255), i.e. we exclude image edges.
Hope that helps.
P.S. I am amazed by the shortness of the code provided by #Divakar.

Speed-efficient classification in Matlab

I have an image of size as RGB uint8(576,720,3) where I want to classify each pixel to a set of colors. I have transformed using rgb2lab from RGB to LAB space, and then removed the L layer so it is now a double(576,720,2) consisting of AB.
Now, I want to classify this to some colors that I have trained on another image, and calculated their respective AB-representations as:
Cluster 1: -17.7903 -13.1170
Cluster 2: -30.1957 40.3520
Cluster 3: -4.4608 47.2543
Cluster 4: 46.3738 36.5225
Cluster 5: 43.3134 -17.6443
Cluster 6: -0.9003 1.4042
Cluster 7: 7.3884 11.5584
Now, in order to classify/label each pixel to a cluster 1-7, I currently do the following (pseudo-code):
clusters;
for each x
for each y
ab = im(x,y,2:3);
dist = norm(ab - clusters); // norm of dist between ab and each cluster
[~, idx] = min(dist);
end
end
However, this is terribly slow (52 seconds) because of the image resolution and that I manually loop through each x and y.
Are there some built-in functions I can use that performs the same job? There must be.
To summarize: I need a classification method that classifies pixel images to an already defined set of clusters.
Approach #1
For a N x 2 sized points/pixels array, you can avoid permute as suggested in the other solution by Luis, which could slow down things a bit, to have a kind of "permute-unrolled" version of it and also let's bsxfun work towards a 2D array instead of a 3D array, which must be better with performance.
Thus, assuming clusters to be ordered as a N x 2 sized array, you may try this other bsxfun based approach -
%// Get a's and b's
im_a = im(:,:,2);
im_b = im(:,:,3);
%// Get the minimum indices that correspond to the cluster IDs
[~,idx] = min(bsxfun(#minus,im_a(:),clusters(:,1).').^2 + ...
bsxfun(#minus,im_b(:),clusters(:,2).').^2,[],2);
idx = reshape(idx,size(im,1),[]);
Approach #2
You can try out another approach that leverages fast matrix multiplication in MATLAB and is based on this smart solution -
d = 2; %// dimension of the problem size
im23 = reshape(im(:,:,2:3),[],2);
numA = size(im23,1);
numB = size(clusters,1);
A_ext = zeros(numA,3*d);
B_ext = zeros(numB,3*d);
for id = 1:d
A_ext(:,3*id-2:3*id) = [ones(numA,1), -2*im23(:,id), im23(:,id).^2 ];
B_ext(:,3*id-2:3*id) = [clusters(:,id).^2 , clusters(:,id), ones(numB,1)];
end
[~, idx] = min(A_ext * B_ext',[],2); %//'
idx = reshape(idx, size(im,1),[]); %// Desired IDs
What’s going on with the matrix multiplication based distance matrix calculation?
Let us consider two matrices A and B between whom we want to calculate the distance matrix. For the sake of an easier explanation that follows next, let us consider A as 3 x 2 and B as 4 x 2 sized arrays, thus indicating that we are working with X-Y points. If we had A as N x 3 and B as M x 3 sized arrays, then those would be X-Y-Z points.
Now, if we have to manually calculate the first element of the square of distance matrix, it would look like this –
first_element = ( A(1,1) – B(1,1) )^2 + ( A(1,2) – B(1,2) )^2
which would be –
first_element = A(1,1)^2 + B(1,1)^2 -2*A(1,1)* B(1,1) + ...
A(1,2)^2 + B(1,2)^2 -2*A(1,2)* B(1,2) … Equation (1)
Now, according to our proposed matrix multiplication, if you check the output of A_ext and B_ext after the loop in the earlier code ends, they would look like the following –
So, if you perform matrix multiplication between A_ext and transpose of B_ext, the first element of the product would be the sum of elementwise multiplication between the first rows of A_ext and B_ext, i.e. sum of these –
The result would be identical to the result obtained from Equation (1) earlier. This would continue for all the elements of A against all the elements of B that are in the same column as in A. Thus, we would end up with the complete squared distance matrix. That’s all there is!!
Vectorized Variations
Vectorized variations of the matrix multiplication based distance matrix calculations are possible, though there weren't any big performance improvements seen with them. Two such variations are listed next.
Variation #1
[nA,dim] = size(A);
nB = size(B,1);
A_ext = ones(nA,dim*3);
A_ext(:,2:3:end) = -2*A;
A_ext(:,3:3:end) = A.^2;
B_ext = ones(nB,dim*3);
B_ext(:,1:3:end) = B.^2;
B_ext(:,2:3:end) = B;
distmat = A_ext * B_ext.';
Variation #2
[nA,dim] = size(A);
nB = size(B,1);
A_ext = [ones(nA*dim,1) -2*A(:) A(:).^2];
B_ext = [B(:).^2 B(:) ones(nB*dim,1)];
A_ext = reshape(permute(reshape(A_ext,nA,dim,[]),[1 3 2]),nA,[]);
B_ext = reshape(permute(reshape(B_ext,nB,dim,[]),[1 3 2]),nB,[]);
distmat = A_ext * B_ext.';
So, these could be considered as experimental versions too.
Use pdist2 (Statistics Toolbox) to compute the distances in a vectorized manner:
ab = im(:,:,2:3); % // get A, B components
ab = reshape(ab, [size(im,1)*size(im,2) 2]); % // reshape into 2-column
dist = pdist2(clusters, ab); % // compute distances
[~, idx] = min(dist); % // find minimizer for each pixel
idx = reshape(idx, size(im,1), size(im,2)); % // reshape result
If you don't have the Statistics Toolbox, you can replace the third line by
dist = squeeze(sum(bsxfun(#minus, clusters, permute(ab, [3 2 1])).^2, 2));
This gives squared distance instead of distance, but for the purposes of minimizing it doesn't matter.

looking for faster way to deal with cell and vector operations

I have a cell list with each elements contains varied number of coordinates to access a vector. For example,
C ={ [1 2 3] , [4 5], [6], [1 8 9 12 20]}
this is just an example, in real case, C is of 10^4 to 10^6 size, each element contains a vector of 1 to 1000 elements. I need to use each element as coordinates to access the corresponding elements in a vector. I am using a loop to find the mean value of vector elements specified by the cell elements
for n=1:size(C,1)
x = mean(X(C{n}));
% put x to somewhere
end
here X is the big vector of 10000 elements. Using the loop is ok but I am wondering if any way to do the same thing but without using a loop? The reason I am asking is above code need to be run for so many times and it is quite slow now to use a lopp.
Approach #1
C_num = char(C{:})-0; %// 2D numeric array from C with cells of lesser elements
%// being filled with 32, which is the ascii equivalent of space
mask = C_num==32; %// get mask for the spaces
C_num(mask)=1; %// replace the numbers in those spaces with ones, so that we
%// can index into x witout throwing any out-of-extent error
X_array = X(C_num); %// 2D array obtained after indexing into X with C_num
X_array(mask) = nan; %// set the earlier invalid space indices with nans
x = nanmean(X_array,2); %// final output of mean values neglecting the nans
Approach #2
lens = cellfun('length',C); %// Lengths of each cell in C
maxlens = max(lens); %// max of those lengths
%// Create a mask array with no. of rows as maxlens and columns as no. of cells.
%// In each column, we would put numbers from each cell starting from top until
%// the number of elements in that cell. The ones(true) in this mask would be the
%// ones where those numbers are to be put and zeros(false) otherwise.
mask = bsxfun(#le,[1:maxlens]',lens) ; %//'
C_num = ones(maxlens,numel(lens)); %// An array where the numbers from C are to be put
C_num(mask) = [C{:}]; %// Put those numbers from C in C_num.
%// NOTE: For performance you can also try out: double(sprintf('%s',C{:}))
X_array = X(C_num); %// Get the corresponding X elements
X_array(mask==0) = nan; %// Set the invalid locations to be NaNs
x = nanmean(X_array); %// Get the desired output of mean values for each cell
Approach #3
This would be almost same as approach #2, but with some changes at the end to avoid nanmean.
Thus, edit the last two lines from approach #2, to these -
X_array(mask1==0) = 0;
x = sum(X_array)./lens;

Maximizing the efficiency of a simple algorithm in MATLAB

So here is what I'm trying to do in MATLAB:
I have an array of n, 2D images. I need to go through pixel by pixel, and find which picture has the brightest pixel at each point, then store the index of that image in another array at that point.
As in, if I have three pictures (n=1,2,3) and picture 2 has the brightest pixel at [1,1], then the value of max_pixels[1,1] would be 2, the index of the picture with that brightest pixel.
I know how to do this with for loops,
%not my actual code:
max_pixels = zeroes(x_max, y_max)
for i:x_max
for j:y_max
[~ , max_pixels(i, j)] = max(pic_arr(i, j))
end
end
But my question is, can it be done faster with some of the special functionality in MATLAB? I have heard that MATLAB isn't too friendly when it comes to nested loops, and the functionality of : should be used wherever possible. Is there any way to get this more efficient?
-PK
You can use max(...) with a dimension specified to get the maximum along the 3rd dimension.
[max_picture, indexOfMax] = max(pic_arr,[],3)
You can get the matrix of maximum values in this way, using memory instead of high performance of processor:
a = [1 2 3];
b = [3 4 2];
c = [0 4 1];
[max_matrix, index_max] = arrayfun(#(x,y,z) max([x y z]), a,b,c);
a,b,c can be matrices also.
It returns the matrix with max values and the matrix of indexes (in which matrix is found each max value).

Find maximum pixel using BLOCKPROC in Matlab

In Matlab I've got a 3D matrix (over 100 frames 512x512). My goal is to find some representative points through the whole hyper-matrix. To do so I've implemented the traditional (and not very efficient) method: I subdivide the large matrix into smaller sub-matrices and then I look for the pixel with the highest value. After doing that I change those relative coordinates of that very pixel in the sub-matrix to global coordinates referenced to the large matrix.
Now, I'm redesigning the algorithm. I've seen that in order to analyze a large matrix block-by-block (that's actually what I'm doing with my old algorithm) the BLOCKPROC function is very efficient. I've read the documentation but I don't know how the "fun" function should be implemented to extract that the pixel with the highest value of each block. Thank you in advance.
*I'm trying to get the coordinates of those maximum pixels referenced to the global matrix, I really don't care about their value.
First define a function to find the location of the maximum of a (sub)matrix:
function loc = max_location(M);
[~, ii] = max(M(:));
[r c] = ind2sub(size(M),ii);
loc = [r c];
Then use
blockproc(im, blocksize, #(x) x.location+max_location(x.data)-1)
where im is your image (2D array) and blocksize is a 1x2 vector specifying block size. Within blockproc, the data field is the submatrix (which you pass to max_location), and the location field contains the coordinates of the top-left corner of the submatrix (which you add to the result of max_location, minus 1).
Example:
>> blocksize = [3 3];
>> im = [ 0.3724 0.0527 0.4177 0.6981 0.0326 0.4607
0.1981 0.7379 0.9831 0.6665 0.5612 0.9816
0.4897 0.2691 0.3015 0.1781 0.8819 0.1564
0.3395 0.4228 0.7011 0.1280 0.6692 0.8555
0.9516 0.5479 0.6663 0.9991 0.1904 0.6448
0.9203 0.9427 0.5391 0.1711 0.3689 0.3763 ];
>> blockproc(im, blocksize, #(x) x.location+max_location(x.data)-1)
ans =
2 3 2 6
5 1 5 4
meaning your block maxima are located at coordinates (2,3), (5,1), (2,6) and (5,4)
Another possiblity is to use im2col for each frame. If I is your frame (512,512):
% rearranges 512 x 512 image into 4096 x 64
% each column of I2 represents a 64 x 64 block
n = 64;
I2 = im2col(I,[n,n],'distinct');
% find max in each block
% ~ to ignore that output
[~,y] = max(I2);
% convert those values to overall indices
ind = sub2ind(size(I2),y, 1:n);
% create new matrix
I3 = zeros(size(I2));
I3(ind)=1;
I3 = col2im(I3,[n,n],size(I),'distinct');
I3 should now be an image the same size of input I but with all zeros except for the locations of the maximum points in each sub-matrix.
the tricky part with the function handle "fun" is that it refers to the subblocks which are a struct, this is an object with one or more fields and one or more values assigend to each of the fields.
The values of your subblocks are stored in a field called "data" so the function call
#(x)max(x)
is not enough, in this case the correct version of that is
#(x)max(x.data)
A 2D example of what you are looking for would look like this:
a=magic(4);
b=blockproc(a,[2,2],#(x) find(x.data==max(max(x.data)))); %linear indexes
outputs
a =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
b =
1 3
4 2
b are the linear indexes of each subblock, so that's the values 16, 13, 14, 15 in a.
Hope that helps!

Resources