Decomposing uint32s into uint8s in a large matrix - image

For a project I am working on, I am loading in large image files, which Matlab inputs as LxWx3 arrays of uint8s. I have a function which concatenates these component-wise into a LxWx1 array of uint32s, but I can't find a way to do the reverse without using nested for loops, which is far too slow for the matrices I am working with.
Could anyone recommend a way to accomplish this effuciently? Basically, given a LxW Matrix of uint32s, I want to return a LxWx3 matrix of uint8s, where the (x, y,1:3) components are the three most significant bytes in the corresponding uint32.

You can do that with typecast:
A = uint32([2^16 2^30; 256 513]);
B = permute(reshape(typecast(A(:), 'uint8'), [], size(A,1), size(A,2)), [2 3 1]);
B = flipdim(B, 3); %// flip 3rd dim to bring MSB first, if needed (depends on computer)
B = B(:,:,2:4);
Example: for A = uint32([2^16 2^30; 256 513]);
A =
65536 1073741824
256 513
the result is
B(:,:,1) =
1 0
0 0
B(:,:,2) =
0 0
1 2
B(:,:,3) =
0 0
0 1

Related

EIGEN : Sparse matrix multiplication not producing a pruned result

I'm using EIGEN for the sparse matrix optimizations and functions. Everything is "working" fine, except in some case and I can't figure this case out.
Here is the thing :
Matrix A
2 0 0
0 2 0
0 0 2
Matrix B
6 3
0 1
2 8
Result
12 6
0 2
4 16
As you can see, this is the right result, and I'm always having the right result.
The problem is about the values considered as "Non Zero". In this case :
SparseMatrix<int, RowMajor> A;
SparseMatrix<int, RowMajor> B;
//Parsing and initializing matrix
SparseMatrix<int, RowMajor> result = A*B;
result.pruned();
cout << result.nonZeros();
The result of nonZeros() is 5, which is the "normal" case, since Result got only 5 non Zero values.
Now, let's consider this code :
SparseMatrix<int, RowMajor> A;
SparseMatrix<int, RowMajor> B;
//Parsing and initializing matrix
SparseMatrix<int, RowMajor> result = (A*B).pruned();
cout << result.nonZeros();
The result of nonZeros() is 6. I do not understand why, this is the syntax available on the documentation.
And now the strangest part is that on very large matrix result = A*B; result.pruned() is sometimes ALSO saving 0 as nonZero, but less than if I used (A*B).pruned();
I got three questions :
Why are result = (A*B).pruned() and result=A*B;result.pruned(); giving different results concerning nonZero values (and not effective result, which is right in both case)?
Why are 0 values from a product sometimes not considered as Zero Values?
Are you having the same result than me?
I'm using Visual Studio Professional 2013 and Eigen 3.3.2, using DEBUG mode and targeting WIN32.
Thanks for your help.
EDIT : Benchmark of sparse multiplication with VS2013, DEBUG/Release mode for W32 (With or without SSE2 instruction set, same results in both case); the result is always the right one so i'm not pasting it here, it's not bringing any information. With :
1 = SparseMatrix<int, RowMajor> resultA = A*B;
2 = SparseMatrix<int, RowMajor> resultB = (A*B);resultB.pruned();
3 = SparseMatrix<int, RowMajor> resultC = (A*B).pruned();
Case 1
Matrix A
2 0 0
0 2 0
0 0 2
Matrix B
5 3
0 1
2 8
Expected value = 5
1 = 5
2 = 5
3 = 6
Case 2
Matrix are too large, here is the file
Expected value = 0
1 = 1444
2 = 1444
3 = 0
As you can see, depending both on the input and the way I'm calling functions, the result is optimized or not, and none of 1, 2 or 3 are working in every case.
EDIT² : Problem fixed by ggael solution (thanks).
My previous answer (below) was wrong. Problem fixed there.
This is because you are targeting win32 and thus you are hitting
classical issues with the extended precision of the FPU registers. By
default, pruned remove entries that are strictly equal to 0, but
with the FPU, it could be that a non zero becomes zero only after
being copied from its register to memory. Update your compiler flags
to either target SSE2 instruction set, or to kill the extra FPU
precision.

Vectorizing range setting - MATLAB

I have got the following code. I need to rewrite it without looping. How should I do it?
l1 = [1 2 3 2 1];
l2 = [3 4 4 5 4];
A = zeros(5,5);
for i=1:5
A(i, l1(i):l2(i)) = 1;
end
A
You can use bsxfun -
I = 1:5 % Array corresponding to iterator : "for i=1:5"
out = bsxfun(#le,l1(:),I) & bsxfun(#ge,l2(:),I)
If you need a double datatype array, convert to double, like so -
out_double = double(out)
Add one more into the mix then! This one simply uses a cumsum to generate all the 1s - so it does not use the : operator at all - It's also fully parallel :D
l1 = [1 2 3 2 1];
l2 = [3 4 4 5 4];
A = zeros(5,5);
L1 = l1+(1:5)*5-5; %Convert to matrix location index
L2 = l2+(1:5)*5-5; %Convert to matrix location index
A(L1) = 1; %Place 1 in that location
A(L2) = 1; %Place 1 in that location
B = cumsum(A,1) ==1 ; %So fast
Answer = (A|B)'; %Lightning fast
Answer =
1 1 1 0 0
0 1 1 1 0
0 0 1 1 0
0 1 1 1 1
1 1 1 1 0
Here is how you could build the matrix without using a loop.
% Our starting values
l1 = [1 2 3 2 1];
l2 = [3 4 4 5 4];
% Coordinate grid of the right size (we don't need r, but I keep it there for illustration)
[r,c] = ndgrid(1:5);
% Build the logical index based on our lower and upper bounds on the column indices
idx_l1=bsxfun(#ge,c,l1');
idx_l2=bsxfun(#le,c,l2');
% The result
A = zeros(size(idx_l1));
A(idx_l1&idx_l2)=1
You may need something like [r,c] = ndgrid(1:numel(l1),1:10).
Also if your matrix size is truly huge and memory becomes an issue, you may want to stick to a loop anyway, but for 'normal size' this could be faster.
There should be some skepticism in every vectorization. If you measure the time actually your loop is faster than the given answers, mostly because you only perform in place write.
Here is another one that would probably get faster for larger sizes but I haven't tested:
tic
myind = [];
for i = 1:5
myind = [myind (5*(i-1))+[l1(i):l2(i)]];
end
A(myind) = 1;
toc
gives the transposed A because of the linear indexing order.

How to remove connected components from an image while retaining some

Let's say I have 5 connected components (labelled objects) in an image called labelledImage from bwlabel. How can I manipulate labelledImage so that the objects that are labelled as 1 and 4 only display, while removing the objects that are labelled as 2, 3 and 5. Then, how can I manipulate the original RGB image so that the connected components that are labelled as 1 and 4 only display.
I know how to retain a single connected component by using this line of code below. However, I don't know how to do this for multiple labelled regions.
Works.
connectedComponent1 = (labelledImage == 1);
imshow(connectedComponent1)
Doesn't work.
connectedComponent1and4 = (labelledImage == [1 4]);
imshow(connectedComponent1and4)
You can't do logical indexing that way. The simplest way is to perhaps use Boolean statements to combine things.
connectedCompoonent1and4 = labelledImage == 1 | labelledImage == 4;
In general, supposing you had a vector of elements that denote which components you want to keep, you could use bsxfun, permute and any to help you with that. Something like this should work:
components = [1 4];
connected = any(bsxfun(#eq, labelledImage, permute(components, [1 3 2])), 3);
The above code uses matrix broadcasting to create a temporary 3D matrix where each slice i contains the ith value of the vector components which contain the desired labels you want to keep. labelledImage is also replicated in the third dimension so the result using bsxfun creates a 3D matrix where each slice i segments out the ith object you want to keep. We then combine all of the objects together using any and looking in the third dimension.
If you don't like one-liners, you could even use a simple for loop:
components = [1 4];
connected = false(size(labelledImage, 1), size(labelledImage, 2));
for ind = 1 : numel(components)
connected = connected | labelledImage == components(ind);
end
This creates an output image that is all false, then we loop through each value in the vector of components you want to keep and append those results on top of the result. The end will give you all of the components you want to keep.
Lastly, you could use also use ismember and determine those values in your matrix that can be found between the label matrix and the components vector and simply create your mask that way:
connected = ismember(labelledImage, components);
Now that you have a mask of objects you want to extract out, to use this on the original image, simply multiply each channel with the mask. Another use of bsxfun can do that for you. Assuming your image in RGB is called img, simply do the following:
outImg = bsxfun(#times, img, cast(connected, class(img)));
To perform element-wise multiplication, you must ensure that both matrices that are being multiplied have the same type. I convert the mask into the same class as whatever the input image is and perform the multiplication.
Use ismember.
Ex:
A = randi(5,5); % your connected component matrix
B = [1 4] % list of components you want to keep
A =
4 2 1 3 5
2 4 2 5 1
3 4 5 1 4
1 4 1 3 5
4 3 5 1 5
A(~ismember(A,B)) = 0
A =
4 0 1 0 0
0 4 0 0 1
0 4 0 1 4
1 4 1 0 0
4 0 0 1 0

Convert non-zero image pixels to row-column coordinates and save the output to workspace

I'm having difficulties converting image pixels to coordinates and making them appear in my MATLAB workspace. For example, I have the image with pixel values as below (it's a binary image of size 4x4):
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
After getting the pixels, I want to read each value and if they're not equal to zero (which means 1), I want to read the coordinates of that value and save them in to my MATLAB workspace. For example, this is the idea that I thought of:
[x,y] = size(image)
for i=1:x
for j=1:y
if (image(i,j)~=0)
....
However, I am stuck. Can anyone give any suggestion on how to read the coordinates of the non-zero values and save them to my workspace?
Specifically, my expected result in the workspace:
2 2
2 3
3 2
3 3
Doing it with loops is probably not the most efficient way to do what you ask. Instead, use find. find determines the locations in a vector or matrix that are non-zero. In your case, all you have to do is:
[row,col] = find(image);
row and col would contain the row and column locations of the non-zero elements in your binary image. Therefore, with your example:
b = [0 0 0 0;
0 1 1 0;
0 1 1 0;
0 0 0 0];
We get:
>> disp([row, col]);
2 2
3 2
2 3
3 3
However, you'll see that the locations are not in the order you expect. This is because the locations are displayed in column-major order, meaning that the columns are traversed first. In your example, you are displaying them in row-major order. If you'd like to maintain this order, you would sort the results by the row coordinate:
>> sortrows([row, col])
ans =
2 2
2 3
3 2
3 3
However, if you really really really really... I mean really... want to use for loops, what you would do is keep two separate arrays that are initially empty, then loop through each pixel and determine whether it's non-zero. If it is, then you would add the x and y locations to these two separate arrays.
As such, you would do this:
row = []; col = [];
[x,y] = size(image);
for i=1:x
for j=1:y
if (image(i,j)~=0)
row = [row; i]; %// Concatenate row and column location if non-zero
col = [col; j];
end
end
end
This should give you the same results as find.
you can use meshgrid() to collect those coordinates. The function generates two outputs, first being x coordinates, second being y coordinates. you'd go like this:
[xcoord ycoord] = meshgrid( 1:x_size, 1:y_size);
zeros_coordsx = xcoord( image == 0);
zeros_coordsy = ycoord( image == 0);
this is way faster that nested looping and keeps you within matlab's natural vector operation space... these two outputs are in sync,meaning that
image( zeros_coordsy(1), zeros_coordsx(1))
is one of the zeros on the image

Form a Matrix From a Large Text File Quickly

Hi I am struggling with reading data from a file quickly enough. ( Currently left for 4hrs, then crashed) must be a simpler way.
The text file looks similar like this:
From To
1 5
3 2
2 1
4 3
From this I want to form a matrix so that there is a 1 in the according [m,n]
The current code is:
function [z] = reed (A)
[m,n]=size(A);
i=1;
while (i <= n)
z(A(1,i),A(2,i))=1;
i=i+1;
end
Which output the following matrix, z:
z =
0 0 0 0 1
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
My actual file has 280,000,000 links to and from, this code is too slow for this size file. Does anybody know a much faster was to do this in matlab?
thanks
You can do something along the lines of the following:
>> A = zeros(4,5);
>> B = importdata('testcase.txt');
>> A(sub2ind(size(A),B.data(:,1),B.data(:,2))) = 1;
My test case, 'testcase.txt' contains your sample data:
From To
1 5
3 2
2 1
4 3
The result would be:
>> A
A =
0 0 0 0 1
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
EDIT - 1
After taking a look at your data, it seems that even if you modify this code appropriately, you may not have enough memory to execute it as the matrix A would become too large.
As such, you can use sparse matrices to achieve the same as given below:
>> B = importdata('web-Stanford.txt');
>> A = sparse(B.data(:,1),B.data(:,2),1,max(max(B.data)),max(max(B.data)));
This would be the approach I'd recommend as your A matrix will have a size of [281903,281903] which would usually be too large to handle due to memory constraints. A sparse matrix on the other hand, maintains only those matrix entries which are non-zero, thus saving on a lot of space. In most cases, you can use sparse matrices more-or-less as you use normal matrices.
More information about the sparse command is given here.
EDIT - 2
I'm not sure why it isn't working for you. Here's a screenshot of how I did it in case that helps:
EDIT - 3
It seems that you're getting a double matrix in B while I'm getting a struct. I'm not sure why this is happening; I can only speculate that you deleted the header lines from the input file before you used importdata.
Basically it's just that my B.data is the same as your B. As such, you should be able to use the following instead:
>> A = sparse(B(:,1),B(:,2),1,max(max(B)),max(max(B)));

Resources