I have a uint16 image of size 512*512. The problem is that the image is all black except there is a medium object of uniform intensity of value 40000. This object has a black hole and I need to extract the indexes of this hole.
So the matrix is in the form of all zeroes, and in some region of the matrix we have a submatrix filled with the value 40000, and in this submatrix we have another submatrix of zeroes. This zero submatrix is the required one to be extracted in terms of its indices. Any suggestions?
A very simple solution would be to use bwlabel. For example:
>> data = 40000.*[0 0 0 0 0; 0 1 1 1 0; 0 1 0 1 0; 0 1 1 1 0; 0 0 0 0 0]
data =
0 0 0 0 0
0 40000 40000 40000 0
0 40000 0 40000 0
0 40000 40000 40000 0
0 0 0 0 0
>> labelMatrix = bwlabel(~data)
labelMatrix =
1 1 1 1 1
1 0 0 0 1
1 0 2 0 1
1 0 0 0 1
1 1 1 1 1
>> holeIndex = find(labelMatrix == 2)
holeIndex =
13
The success of this is based on many assumptions, such as there only being one bright object and one hole in it. A more robust solution would require an example of the images you're analyzing, and might involve some preprocessing of the image and the use of functions such as regionprops to identify areas of the image.
I was attempting to apply a closing operation to an image using a line structuring element at 8 different directions. Initially I wanted to apply it to angles in the range [0 .. 360] but I later realised that my stucturing element is symmetrical so I thought of using the range [0 .. 180] instead. However, I later realized that Matlab's structuring element function (strel) does not produce symmetrical results for angles that are 180 degrees apart. Consider:
>> strel('line', 11, 120)
ans =
Flat STREL object containing 9 neighbors.
Neighborhood:
1 0 0 0 0
1 0 0 0 0
0 1 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 1 0
0 0 0 0 1
0 0 0 0 1
>>
And:
>> strel('line', 11, 300)
ans =
Flat STREL object containing 9 neighbors.
Neighborhood:
1 0 0 0 0 0 0
0 1 0 0 0 0 0
0 1 0 0 0 0 0
0 0 1 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 1 0
0 0 0 0 0 1 0
0 0 0 0 0 0 1
I expect that the 2 structuring elements above should be symmetrical, since 300 = 120 + 180. Why is this not the case for Matlab's strel function?
Potatoes:
This is an interesting observation. If you happen to look into the implementation of the strel object in MATLAB, the lines to observe are these (in the MakeLineStrel sub-function):
theta = theta_d * pi / 180;
x = round((len-1)/2 * cos(theta));
y = -round((len-1)/2 * sin(theta));
The theta_d value is the angle in degrees you've specified, and len is the length of the line you've requested for.
The values for x and y define the integer valued "end point" of the line, and the structuring element is constructed such that it is symmetric with respect to the origin.
Due to the rounding operation here, when you specify 120 for theta_d, the pair (x,y) will be (-2, -4), but when you specify 300, (x,y) will be (3, 4). This is the root cause for the discretized line being different due to the way the angles have been represented.
Given this understanding, it would be safest to actually print the neighborhood of the structuring element and ensure that it looks right, before using it in your operation.
Hope this helps.
Is there any inline command to generate shifted identity matrix in MATLAB?
A=[ ...
0, 1, 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, 0, 0, 0
0, 0, 0, 0, 1, 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
0, 0, 0, 0, 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0]
combination of circshift and eye is good however it needs another command to fix it. Any simpler way? (with just one simple syntax)
Try using a diag call in combination with ones. For your case, you have a 10 x 10 identity matrix and want to shift the diagonal to the right by 1.
>> n = 10;
>> shift = 1;
>> A = diag(ones(n-abs(shift),1),shift)
A =
0 1 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 0 0 0
0 0 0 0 1 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
0 0 0 0 0 0 0 1 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 0 0 0 0 0 0 0
The above code works by first declaring a column vector of all 1s, but we would need n-abs(shift) of them as moving to the right would mean that we would require less 1s to fill things up (more on this later). n-abs(shift) also corresponds to the total number of rows/columns of your matrix and subtracting out as many times you are shifting towards the right. Next, you can use diag where the first parameter is a column vector which creates a zero matrix and places the column vector as coefficients along the diagonal of this matrix. The second parameter (shift in your case) allows you to offset where to place this column. Specifying a positive value means to move the diagonals towards the right, and in our case we are moving this to the right by shift, and hence our output results. As you are essentially truncating the vector for each position towards the right you are moving, you would need to decrease the number of 1s in your vector by this much.
Up to now, I haven't explained why the abs call to shift is required in the last line of code. The reason why the abs call is required is to accommodate for negative shifts. If we didn't have the abs call in the third line of code, n-shift would essentially be adding more 1s to the vector and would thus expand our matrix beyond n x n. Because moving the diagonals to the left also decreases the amount of 1s seen in the result, that's why the abs call is required but you'll notice that the shift constant is left untouched in the second parameter of diag.
Here's a demonstration with a negative shift, shift = -1, and still maintaining the size to be 10 x 10:
A =
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 0 0 0 0 0
0 0 1 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 0 0
0 0 0 0 0 1 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 0 0 0 0 0 0 0 1 0
You can get the desired output with a single call to bsxfun -
n = 10
shift = 1
A = bsxfun(#eq,[1:n].',1-shift:n-shift)
Since you are basically creating a sparse matrix, alternatively you can use sparse -
n = 10
shift = 1
A = full(sparse(1:n-shift,1+shift:n,1,n,n))
way late in this game but let us not forget the simplest solution using linear indexing:
n=10; a=zeros(n);
a(n+1:n+1:end)=1
obviously, that just solves the shift=1 case, but you get the point...
You can use circshift and fix the matrix before passing it to the function:
>> shift = 1;
>> N=10;
>> A=circshift(diag(1:N>shift),-shift)
A =
0 1 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 0 0 0
0 0 0 0 1 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
0 0 0 0 0 0 0 1 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 0 0 0 0 0 0 0
1:N>shift will be 0 for fist shift number of places and 1 for the remaining.
Here is Another Alternative: (little similar to bsxfun Approach by Divakar)
n=10;
shift = 1;
c = repmat(1-shift:n-shift,n,1,1);
r = repmat((1:n).',1,n,1);
out = r == c
This could also be a one-liner:
out = repmat((1:n).',1,n,1) == repmat(1-shift:n-shift,n,1,1)
Here is another one (also works with negative shifts)
rot90(blkdiag(zeros(abs(shift)),rot90(eye(n))),sign(shift))
Given a matrix where 1 is the current subset
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Is there a function, or quick method to get change the subset to the boundary of the current subset?
Eg. Get this subset from 'test' above
test =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 0
0 1 1 1 1 0
0 0 0 0 0 0
In the end I just want to get the minimum of the cells surrounding a subset of a matrix. Sure I could loop through and get the minimum of the boundary (cell by cell), but there must be a way to do it with the method i've shown above.
Note the subset WILL be connected, but may not be rectangular. This may be the big catch.
This is a possible subset.... (Would pad this with a NaN border)
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1
Ideas?
The basic steps I'd use are:
Perform a dilation on the shape to get a new area which is the shape plus its boundary
Subtract the original shape from the dilated shape to leave just the boundary
Use the boundary to index your data matrix, then take the minimum.
Dilation
What I want to do here is pass a 3x3 window over each cell and take the maximum value in that window:
[m, n] = size(A); % assuming A is your original shape matrix
APadded = zeros(m + 2, n + 2);
APadded(2:end-1, 2:end-1) = A; % pad A with zeroes on each side
ADilated = zeros(m + 2, n + 2); % this will hold the dilated shape.
for i = 1:m
for j = 1:n
mask = zeros(size(APadded));
mask(i:i+2, j:j+2) = 1; % this places a 3x3 square of 1's around (i, j)
ADilated(i + 1, j + 1) = max(APadded(mask));
end
end
Shape subtraction
This is basically a logical AND and a logical NOT to remove the intersection:
ABoundary = ADilated & (~APadded);
At this stage you may want to remove the border we added to do the dilation, since we don't need it any more.
ABoundary = ABoundary(2:end-1, 2:end-1);
Find the minimum data point along the boundary
We can use our logical boundary to index the original data into a vector, then just take the minimum of that vector.
dataMinimum = min(data(ABoundary));
You should look at this as morphology problem, not set theory. This can be solved pretty easily with imdilate() (requires the image package). You basically only need to subtract the image to its dilation with a 3x3 matrix of 1.
octave> test = logical ([0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1]);
octave> imdilate (test, true (3)) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
It does not, however, pads with NaN. If you really want that, you could pad your original matrix with false, do the operation, and then check if there's any true values in the border.
Note that you don't have to use logical() in which case you'll have to use ones() instead of true(). But that takes more memory and has worse performance.
EDIT: since you are trying to do it without using any matlab toolbox, take a look at the source of imdilate() in Octave. For the case of logical matrices (which is your case) it's a simple usage of filter2() which belongs to matlab core. That said, the following one line should work fine and be much faster
octave> (filter2 (true (3), test) > 0) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
One possible solution is to take the subset and add it to the original matrix, but ensure that each time you add it, you offset its position by +1 row, -1 row and +1 column, -1 column. The result will then be expanded by one row and column all around the original subset. You then use the original matrix to mask the original subet to zero.
Like this:
test_new = test + ...
[[test(2:end,2:end);zeros(1,size(test,1)-1)],zeros(size(test,1),1)] + ... %move subset up-left
[[zeros(1,size(test,1)-1);test(1:end-1,2:end)],zeros(size(test,1),1)] + ... %move down-left
[zeros(size(test,1),1),[test(2:end,1:end-1);zeros(1,size(test,1)-1)]] + ... %move subset up-right
[zeros(size(test,1),1),[zeros(1,size(test,1)-1);test(1:end-1,1:end-1)]]; %move subset down-right
test_masked = test_new.*~test; %mask with original matrix
result = test_masked;
result(result>1)=1; % ensure that there is only 1's, not 2, 3, etc.
The result for this on your test matrix is:
result =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
Edited - it now grabs the corners as well, by moving the subset up and to the left, up and to the right, down then left and down then right.
I expect this would be a very quick way to achieve this - it doesn't have any loops, nor functions - just matrix operations.
Can somebody explain how to use this function in Matlab
"sequentialfs"
it looks straight forward but I do not know how can we design a function handler for it?!
any clue?!
Here's a simpler example than the one in the documentation.
First let's create a very simple dataset. We have some class labels y. 500 are from class 0, and 500 are from class 1, and they are randomly ordered.
>> y = [zeros(500,1); ones(500,1)];
>> y = y(randperm(1000));
And we have 100 variables x that we want to use to predict y. 99 of them are just random noise, but one of them is highly correlated with the class label.
>> x = rand(1000,99);
>> x(:,100) = y + rand(1000,1)*0.1;
Now let's say we want to classify the points using linear discriminant analysis. If we were to do this directly without applying any feature selection, we would first split the data up into a training set and a test set:
>> xtrain = x(1:700, :); xtest = x(701:end, :);
>> ytrain = y(1:700); ytest = y(701:end);
Then we would classify them:
>> ypred = classify(xtest, xtrain, ytrain);
And finally we would measure the error rate of the prediction:
>> sum(ytest ~= ypred)
ans =
0
and in this case we get perfect classification.
To make a function handle to be used with sequentialfs, just put these pieces together:
>> f = #(xtrain, ytrain, xtest, ytest) sum(ytest ~= classify(xtest, xtrain, ytrain));
And pass all of them together into sequentialfs:
>> fs = sequentialfs(f,x,y)
fs =
Columns 1 through 16
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 17 through 32
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 33 through 48
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 49 through 64
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 65 through 80
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 81 through 96
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 97 through 100
0 0 0 1
The final 1 in the output indicates that variable 100 is, as expected, the best predictor of y among the variables in x.
The example in the documentation for sequentialfs is a little more complex, mostly because the predicted class labels are strings rather than numerical values as above, so ~strcmp is used to calculate the error rate rather than ~=. In addition it makes use of cross-validation to estimate the error rate, rather than direct evaluation as above.