matlab's imfill function seems bugged? - matlab

I need to work with imfill in Matlab (Version 2010b, 7.11.0). I now think there is a bug in the program.
The most simple example that i found here is following: (Fills the Image background (0) beginning at the position [4 3])
BW = [ 0 0 0 0 0 0 0 0;
0 1 1 1 1 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 0 0 0 1 0 0;
0 1 1 1 1 0 0 0;
0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0];
imfill(BW,[4 3])
According to the specifications this should work IMHO, but I always get following message. Can anyone tell me what I am doing wrong?
??? Error using ==> iptcheckconn at 56
Function IMFILL expected its second input argument, CONN,
to be a valid connectivity specifier.
A nonscalar connectivity specifier must be 3-by-3-by- ...
-by-3.
Error in ==> imfill>parse_inputs at 259
iptcheckconn(conn, mfilename, 'CONN', conn_position);
Error in ==> imfill at 124
[I,locations,conn,do_fillholes] = parse_inputs(varargin{:});
Error in ==> test at 9
imfill(BW,[4 3])

That does not explain the problem but converting BW to a logical array does work. I'm not sure as to why it's like this though:
clear
close all
clc
BW = [ 0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 0 0 0 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0];
BW2 = imfill(logical(BW),[4 3])
BW2 =
0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 1 0 0
0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

As you have already seen in the other solution by #Benoit_11, that most probably that input wasn't of logical class, which was throwing an error at you. So, you are set there!
Now, I would like to put forth a tiny bit of bonus suggestion here.
Let's suppose you have a set of seed points with their row and column IDs and you would like to fill an image with those seed points in one go. For that case,
you need to use those IDs as column vectors. Thus, if you have the row and column IDs as -
row_id = [4 3];
col_id = [3 7];
You can fill image with this -
BW = imfill(BW,[row_id(:) col_id(:)])
But, the following code would throw error at you -
BW = imfill(BW,[row_id col_id])

Related

What is the result of dilation of this image?

I have this following matrix:
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 0 0 0
1 1 0 0 0 0 0
1 0 0 0 0 1 1
1 0 0 0 0 1 1
And I want to dilate it with the following structuring element:
1 0 0
1 1 1
1 1 1
I already did dilation on Matlab but the result does not match with the one I did by hand. So I guess I missing something here. As far as I know if any '1' of the structuring element touches any of the '1' in the matrix, then it means it is a hit and the center of the current window should be set as 1. If I make dilation in such fashion I would get following (without considering edges):
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 1 1 0 0 0 0
1 1 1 0 1 1 0
1 1 1 0 1 1 1
1 0 0 0 0 1 1
But Matlab gives the following result:
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
1 **0** **0** 0 0 0 0
1 1 1 0 1 1 0
1 1 1 0 1 1 1
1 1 0 0 1 1 1
Without considering edges it almost looks like my result but pixels styled with bold are '1' in my result but '0' in Matlab's result. What am I doing wrong? Pixel just below those '0's are '1's in the original image and the structuring element has '1' at that space when the center of the window is on those '0's so it is a hit and the center must be set '1' but Matlab doesn't do this. Can anyone explain me why? Am I missing something essential here?
Suppose matrix A is your image and matrix B is structuring element. You should pad the matrix A with zeroes on all sides. So let's say you have matrix C. Then you should perform Logical AND operation of C and B. The result matrix called D will be a dilated matrix. For further information, please see here.
Here is the code of Matlab which dilate image without 'imdilate' function:
clc;clearvars;close all;
%Image Dilation without using 'imdilate' function
% Matrix A is our image
A=[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 0 0 0;
1 1 0 0 0 0 0;
1 0 0 0 0 1 1 ;
1 0 0 0 0 1 1 ];
%Structuring element
B=[1 0 0; 1 1 1; 1 1 1];
%Pad zeros on all the sides
C=padarray(A,[1 1]);
%Intialize a matrix of matrix size A with zeros
D=false(size(A));
for i=1:size(C,1)-2
for j=1:size(C,2)-2
%Perform logical AND operation
D(i,j)=sum(sum(B&C(i:i+2,j:j+2)));
end
end
display(D);
And this is my output, dilated matrix D:

How do I create random matrix where each column is all zeroes except for one random row?

I want to create a matrix of size m-by-n where all elements in a column are 0 except one element which is 1. That one element must be at a random position.
eg.
[0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 0 1]
To add some variety, here's another approach:
m = 4;
n = 5;
[~, result] = sort(rand(m,n));
result = double(result==1);
This gives, for example,
result =
0 0 0 0 1
0 1 0 0 0
1 0 0 1 0
0 0 1 0 0
You can also use rand and max to do the job:
m=4;
n=5;
R=rand(m,n);
result = bsxfun(#eq, R, max(R,[],1))
On my machine it gave:
1 1 0 0 0
0 0 0 0 0
0 0 1 0 1
0 0 0 1 0
How it works: Generating a random matrix, R, and then setting to 1 the entry corresponding to the maximal element at each column. No need for sorting.
Regarding the original answer of Divakar, since it uses randperm it is restricted to square matrix only, and it will only produce random permutation matrices.
One possible way to correct his solution is to use randi instead of randperm:
result = bsxfun( #eq, (1:m)', randi(m, 1, n ) )
May give this output:
1 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
As for the answer of bla, using accumarry can save the use of zeros and sub2ind:
m=5; n=10;
R=randi(m,n,1);
A = accumarray( {R, (1:n)' }, 1, [m n] )
May give this output:
0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Another idea I have is to create the identity matrix of size m x m, then use randi with a range from 1 up to m to create a vector of n elements long. After, you'd use this vector to access the columns of the identity matrix to complete the random matrix you desire:
m = 5; n = 5; %// Given your example
M = eye(m);
out = M(:,randi(m, n, 1));
Here's one possible run of the above code:
out =
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 1 1 0 1
here's an example using randi:
m=5; n=10;
A=zeros(m,n);
R=randi(m,n,1);
A(sub2ind(size(A),R',1:n))=1
A =
0 0 0 0 0 0 0 1 0 1
0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0
You can use sparse with randi for a one-liner, like so -
full(sparse(randi(m,1,n),1:n,1,m,n))
Sample run -
>> m = 5; n = 6;
>> full(sparse(randi(m,1,n),1:n,1,m,n))
ans =
0 1 0 0 0 1
0 0 1 1 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0

Extract multiple indices from matrix

I want to access multiple indices of a matrix as shown below. So what I want is indices (1,3),(2,6),(3,7) to be set to one. However, as you can see the entire column is set to one. I can see what it is doing but is there a way to do what I want it to (in an elegant way - no loops).
a=zeros(3,10)
a(1:3,[3 6 7])=1
a =
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
0 0 1 0 0 1 1 0 0 0
I realise that you can do something along the lines of
x_idx=1:3, y_idx=[3 6 7];
idx=x_idx*size(a,2)+y_idx;
a(idx)=1;
but just wondering if there was a better, or proper way of doing this in Matlab
You can use sub2ind, which essentially is doing what you have mentioned in your post, but MATLAB has this built-in:
a = zeros(3,10);
a(sub2ind(size(a), 1:3, [3 6 7])) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
Another way would be to create a logical sparse matrix, then use this to index into a:
a = zeros(3,10);
ind = logical(sparse(1:3, [3 6 7], true, size(a,1), size(a,2)));
a(ind) = 1
a =
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0

Matlab: sort an array to ascending order in terms of binary interpretation

The array contains binary numbers per line: one row means one binary number. They are in no order so I am trying to find a command by which I can sort them to ascending order, how to do it?
Input
>> [1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0]
ans =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
Goal: by which command I can get by the input the below output?
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
You can do it by converting to strings (num2str) and then from binary string to number (bin2dec):
[vv ii] = sort(bin2dec(num2str(data)));
data_sorted = data(ii,:);
Based on my suggestion in the comments, "you should be able to do a radix sort using sortrows on columns n down to 1.", the OP got the following code working:
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1];sortrows(A)
ans =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
And has now included Luis' cool idea for indexing.
Beaker answered in the comment "you should be able to do a radix sort using sortrows on columns n down to 1." -- and it works! Then Luis Mendo had a method to store the original positioning so putting the ideas together, vuola!
>> A=[1 0 0 1 1; 0 0 1 0 0; 1 0 1 0 0;0 0 0 0 1]
[vv ii]=sortrows(A)
A =
1 0 0 1 1
0 0 1 0 0
1 0 1 0 0
0 0 0 0 1
vv =
0 0 0 0 1
0 0 1 0 0
1 0 0 1 1
1 0 1 0 0
ii =
4
2
1
3

Easy Way To Accomplish Data Compression in MATLAB?

I am working on an assignment where I have to take a large matrix containing data, and somehow compress the data so that it will be in a form of more manageable size. However, the data needs to be re-utilized as input to something else. (A toolbox, for example). Here's what I've done so far. For this example matrix, I use the find function to give me a matrix of all the indices where the values are non-zero. But I have no idea as to how to use it as input so that the original figure information is retained. I was curious if other folks had any other better (simple) solutions to this.
number_1 = [0 0 0 0 0 0 0 0 0 0 ...
0 0 1 1 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 1 1 1 1 1 1 1 1 0 ...
0 0 0 0 0 0 0 0 0 0];
number = number_1;
compressed_number = find(number);
compressed_number = compressed_number';
disp(compressed_number)
When you have only ones and zeros, and the fill factor is not terribly small, your best bet is to store the numbers as binary numbers; if you need the original size, save it separately. I have expanded the code, showing the intermediate steps a little more clearly, and also showing the amount of storage needed for the different arrays. Note - I reshaped your data into a 13x10 array because it displays better.
number_1 = [0 0 0 0 0 0 0 0 0 0 ...
0 0 1 1 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 1 1 1 1 1 1 1 1 0 ...
0 0 0 0 0 0 0 0 0 0];
n1matrix = reshape(number_1, 10, [])'; % make it nicer to display;
% transpose because data is stored column-major (row index changes fastest).
disp('the original data in 13 rows of 10:');
disp(n1matrix);
% create a matrix with 8 rows and enough columns
n1 = numel(number_1);
nc = ceil(n1/8); % "enough columns"
npad = zeros(8, nc);
npad(1:n1) = number_1; % fill the first n1 elements: the rest is zero
binVec = 2.^(7-(0:7)); % 128, 64, 32, 16, 8, 4, 2, 1 ... powers of two
compressed1 = uint8(binVec * npad); % 128 * bit 1 + 64 * bit 2 + 32 * bit 3...
% showing what we did...
disp('Organizing into groups of 8, and calculated their decimal representation:')
for ii = 1:nc
fprintf(1,'%d ', npad(:, ii));
fprintf(1, '= %d\n', compressed1(ii));
end
% now the inverse operation: using dec2bin to turn decimals into binary
% this function returns strings, so some further processing is needed
% original code used de2bi (no typo) but that requires a communications toolbox
% like this the code is more portable
decompressed = dec2bin(compressed1);
disp('the string representation of the numbers recovered:');
disp(decompressed); % this looks a lot like the data in groups of 8, but it's a string
% now we turn them back into the original array
% remember it is a string right now, and the values are stored
% in column-major order so we need to transpose
recovered = ('1'==decompressed'); % all '1' characters become logical 1
display(recovered);
% alternative solution #1: use logical array
compressed2 = (n1matrix==1);
display(compressed2);
recovered = double(compressed2); % looks just the same...
% other suggestions 1: use find
compressed3 = find(n1matrix); % fewer elements, but each element is 8 bytes
compressed3b = uint8(compressed); % if you know you have fewer than 256 elements
% or use `sparse`
compressed4 = sparse(n1matrix);
% or use logical sparse:
compressed5 = sparse((n1matrix==1));
whos number_1 comp*
the original data in 13 rows of 10:
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0
Organizing into groups of 8, and their decimal representation:
0 0 0 0 0 0 0 0 = 0
0 0 0 0 1 1 1 1 = 15
0 0 0 0 0 1 1 0 = 6
1 1 0 0 0 0 0 1 = 193
1 0 1 1 0 0 0 0 = 176
0 0 0 0 1 1 0 0 = 12
0 0 0 0 0 0 1 1 = 3
0 0 0 0 0 0 0 0 = 0
1 1 0 0 0 0 0 0 = 192
0 0 1 1 0 0 0 0 = 48
0 0 0 0 1 1 0 0 = 12
0 0 0 0 0 0 1 1 = 3
0 0 0 0 0 0 0 0 = 0
1 1 0 0 0 0 0 1 = 193
1 1 1 1 1 1 1 0 = 254
0 0 0 0 0 0 0 0 = 0
0 0 0 0 0 0 0 0 = 0
the string representation of the numbers recovered:
00000000
00001111
00000110
11000001
10110000
00001100
00000011
00000000
11000000
00110000
00001100
00000011
00000000
11000001
11111110
00000000
00000000
compressed2 =
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0
recovered =
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0
Name Size Bytes Class Attributes
compressed1 1x17 17 uint8
compressed2 13x10 130 logical
compressed3 34x1 272 double
compressed3b 34x1 34 uint8
compressed4 13x10 632 double sparse
compressed5 13x10 394 logical sparse
number_1 1x130 1040 double
As you can see, the original array takes 1040 bytes; the compressed array takes 17. You get almost 64x compression (not quite because 132 is not a multiple of 8); only a very sparse dataset would be better compressed by some other means. The only thing that gets close (and that is super fast) is
compressed3b = uint8(find(number_1));
At 34 bytes, it is definitely a contender for small arrays (< 256 elements).
Note - when you save data in Matlab (using save(fileName, 'variableName')), some compression happens automatically. This leads to an interesting and surprising result. When you take each of the above variables and save them to file using Matlab's save, the file sizes in bytes become:
number_1 195
compressed1 202
compressed2 213
compressed3 219
compressed3b 222
compressed4 256
compressed5 252
On the other hand, if you create a binary file yourself using
fid = fopen('myFile.bin', 'wb');
fwrite(fid, compressed1)
fclose(fid)
It will by default write uint8, so the file sizes are 130, 17, 130, 34, 34 -- sparse arrays cannot be written in this way. It still shows the "complicated" compression having the best compression.
First of all, you can use the find function to get all non-zero indices of your array, instead of doing it manually. More info here: http://www.mathworks.com/help/matlab/ref/find.html
Anyways, you will need not only matrix but also the original size. So when you pass matrix into whatever, you must also pass in length(number_1). This is because matrix will not tell you how many 0s there were after the last 1. You can figure it out by subtracting the last value of matrix from the original length (there might be an off-by-one error there).