4
votes

I am having some problems with the find function in MATLAB. I have a matrix consisting of zeros and ones (representing the geometry of a structural element), where material is present when the matrix element = 1, and where no material is present when the matrix element = 0. The matrix may have the general form shown below (it will update as the geometry is changed, but that isn't too important).

                 Geometry = [0 0 0 0 0 0 0 0 0 0;
                             0 0 1 0 1 0 1 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 0 0 0;
                             0 0 0 0 0 0 0 1 0 0;
                             0 0 0 0 0 0 0 0 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 1 1 1 0 1 0 0;
                             0 0 0 0 0 0 0 0 0 0;]

I'm trying to find the the rows and columns that are not continuously connected (i.e. where the row and columns are not all equal to 1 between the outer extents of the row or column) and then update them so they are all connected. I.e. the matrix above becomes:

                Geometry =  [0 0 0 0 0 0 0 0 0 0;
                             0 0 1 1 1 1 1 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 0 0 0 0 1 0 0;
                             0 0 1 1 1 1 1 1 0 0;
                             0 0 0 0 0 0 0 0 0 0;]

The problem I am having is I want to be able to find the indices of the first and last element that is equal to 1 in each row (and column), which will then be used to update the geoemtry matrix.

Ideally, I want to represent these in vectors, so going across the columns, find the row number of the first element equal to 1 and store this in a vector called rowfirst.

I.e.:

                    rowfirst = zeros(1,numcols)
                    for i = 1:numcols % Going across the columns
                    rowfirst(i) = find(Geometry(i,1) == 1, 1,'first') 
                                       % Store values in vector called rowfirst
                    end

and the repeat this for the columns and to find the last elements in each row.

For some reason, I can't get the values to store properly in the vector, does anyone have an idea of where I'm going wrong?

Thanks in advance. Please let me know if that isn't clear, as I may not have explained the problem very well.

4

4 Answers

2
votes

0) bwmorph(Geometry,'close') dose it all in one line. If the holes may be bigger, try bwmorph(Geometry,'close',Inf).

Regarding your attempt:

1) It should be Geometry(i,:) instead of Geometry(i,1).

2) Your real problem here is empty matrices. Actually, what do you want rowfirst(i) to be if there are no 1s in the i'th row?

1
votes

I'm pretty sure there's a more efficient way of doing this, but if you replace your call to find with this, it should work ok:

find(Geometry(i,:), 1,'first') 

(otherwise you're just looking at the first cell of the ith row. And the == 1 is useless, since find already returns only non-zero elements, and your matrix is binary)

1
votes

Ok, I can spot two mistakes:

  • You should use an array as the first argument of find. So, if you want to find the row number of the first element of each column, then you should use find(Geometry(:, i), 1, 'first').

  • Find returns an empty array if the column contains only zeros. You should handle this case and decide what number you want to put into rownumber (e.g. you can put -1, to indicate that the corresponding column contains no non-zero elements).

Following the above, you can try this:

for i = 1:numcols
  tmp = find(Geometry(:, i), 1, 'first');
  if(tmp)
    rowfirst(i) = tmp;
  else
    rowfirst(i) = -1;
  end;
end;
1
votes

Use the AccumArray() function to find the min and max col (row) number.

Imagine finding the last (first) row in each column that contains a NaN.

a = [1 nan nan nan ;
     2 2   3   4;
     3 nan 3   3;
     4 nan 4   4]

This code gets the row indices for the last NaN in each column.

[row,col] = find(isnan(a))
accumarray(col,row,[],@max)

This code gets the row indices for the first NaN in each column.

[row,col] = find(isnan(a))
accumarray(col,row,[],@min)

Swap the row and col variables to scan row-wise instead of column-wise.

This answer inspired by Finding value and index of min value in a matrix, grouped by column values