1
votes

I have a simple pcolor plot in Matlab (Version R 2016b) which I have uploaded as shown in the image below. I need to get only the blue sloped line which extends from the middle of the leftmost corner to the rightmost corner without hard-coding the matrix values.

For instance: One can see that the desired slope line has values somewhere approximately between 20 to 45 from the pcolor plot. (From a rough guess just by looking at the graph)

I'm applying the following code on the matrix named Slant which contains the plotted values.

load('Slant.mat');
Slant(Slant<20|Slant>50)=0;
pcolor(Slant); colormap(jet); shading interp; colorbar;

As one can see I hard-coded the values which I don't want to. Is there any method of detecting certain matrix values while making the rest equal to zero?

I used an other small algorithm of taking half the maximum value from the matrix and setting it to zero. But this doesn't work for other images.

[maxvalue, row] = max(Slant);
max_m=max(maxvalue);
Slant(Slant>max_m/2)=0;
pcolor(Slant); colormap(jet); shading interp; colorbar;

Slope Image

2
Is the matrix nonzero everywhere in the image?flawr
The matrix is non-zero in the colored region. Outside that it has values of zero.Sack11
Why do you use such a big matrix with so many entries that do not add anything? What properties does this line have that distinguishes it from the rest of the picture? Without any knowledge about what structure and information you expect this seems to be impossible to solve.flawr
The matrix is from certain measurements. The other entries are made zero because of the knowledge from standard noise. (I know prior that these rows and columns are noise values).The line is the measurement data of a moving vehicle/object. As I included in the question, by visual inspection one can easily guess that the value of the line is somewhere between 20 and 45. But I don't want to hard code it, I just want to remove the other background values like the yellow colored values (It doesn't have to be precise but clear enough so that the line is visible)Sack11
"by visual inspection" does not help anything, because you want to use a computre. Is this line always going to be a straight line? Does it always have the same thickness? Does it always have the same angle? Is it brighter /darker than the rest of the image? How can you tell it apart from the rest of the noise?flawr

2 Answers

1
votes

Here is another suggestion:

  1. Remove all the background.
  2. Assuming this "line" results in a Bimodal distribution of the data (after removing the zeros), find the lower mode.
  3. Assuming the values of the line are always lower than the background, apply a logic mask that set to zeros all values above the minimum + 2nd_mode, as demonstrated in the figure below (in red circle):

line_hist

Here is how it works:

A = Slant(any(Slant,2),:); % save in A only the nonzero data

Now we have A that looks like this:

A

[y,x] = findpeaks(histcounts(A)); % find all the mode in the histogram of A
sorted_x = sortrows([x.' y.'],-2); % sort them by their hight in decendet order
mA = A<min(A(:))+sorted_x(2,1); % mask all values above the second mode
result = A.*mA; % apply the mask on A

And we get the result:

result


The resulted line has some holes within it, so you might want to interpolate the whole line from the result. This can be done with simple math on the indices:

[y1,x1] = find(mA,1); % find the first nonzero row 
[y2,x2] = find(mA,1,'last'); % find the last nonzero row
m = (y1-y2)/(x1-x2); % the line slope
n = y1-m*x1; % the intercept
f_line = @(x) m.*x+n; % the line function

So we get a line function f_line like this (in red below):

interp_line

Now we want to make this line thicker, like the line in the data, so we take the mode of the thickness (by counting the values in each column, you might want to take max instead), and 'expand' the line by half of this factor to both sides:

thick = mode(sum(mA)); % mode thickness of the line
tmp = (1:thick)-ceil(thick/2); % helper vector for expanding
rows = bsxfun(@plus,tmp.',floor(f_line(1:size(A,2)))); % all the rows for each coloumn
rows(rows<1) = 1; % make sure to not get out of range
rows(rows>size(A,1)) = size(A,1); % make sure to not get out of range
inds = sub2ind(size(A),rows,repmat(1:size(A,2),thick,1)); % convert to linear indecies
mA(inds) = 1; % add the interpolation to the mask
result = A.*mA; % apply the mask on A

And now result looks like this:

inter and thick

1
votes

Idea: Use the Hough transform:

First of all it is best to create a new matrix with only the rows and columns we are interested in.

In order to apply matlab's built in hough we have to create a binary image: As the line always has lower values than the rest, we could e.g. determine the lowest quartile of the brightnesses present in the picture (using quantile, and set these to white, everything else to black.

Then to find the line, we can use hough directly on that BW image.