MATLAB: pdist, finding pixel locations of minimum pairwise distance in binary image - matlab

I have a binary image and have found the minimum distance connecting two nearby regions of interest/connected components using
min(min(pdist2(CCstats(1).PixelList,CCstats(2).PixelList)))
I also need to get the coordinates of these ends of this distance/the most adjacent pixels between these 2 regions of interest
I plan on drawing a line along this distance. I was going to use something like:
x=linspace(coord1(1), coord2(1),1000);
y=linspace(coord1(2), coord2(2),1000);
index=sub2ind(size(image),round(y),round(x));
image(index)=1;
Any suggestions for how to find these coordinates?

You will want the second output of min (combined with ind2sub) to determine the row/column of the pdist2 matrix that corresponds to the minimum distance.
distances = pdist2(CCstats(1).PixelList, CCstats(2).PixelList);
[mindist, minind] = min(distances(:));
%// Now convert this linear index into index1/index2 into your pixel lists
[index1, index2] = ind2sub(size(distances), minind);
%// Now grab the coordinates using these index values
coord1 = CCstats(1).PixelList(index1,:);
coord2 = CCstats(2).PixelList(index2,:);

Related

Find closest point of labelled area to a point in an image with Matlab

I'm trying to find the closes point to an area in an image with Matlab:
consider this example code:
myimg = rgb2gray(imread('tissue.png')); %load grayscale example image of cells
BW=bwareaopen(myimg<150,10); %only look at dark pixels, remove small objects
BW=bwlabel(imfill(BW,'holes')) %fill holes of structures, label structures
figure;
imagesc(BW); %display image
I'd like to find the closest point of the closest structure to a point e.g. [0,0]. My approach so far is to get all centroids of all connected structures, then loop through all of them to find the closest one (inaccurate and inefficient).
If you just want to find a single closest point, you can use bwdist with a second output argument. This will give you a matrix which at each point contains the linear index of the closest non-zero point of the input image. You then just need to select the index corresponding to the point you are interested in. The input image to bwdist should be binary, so in your case you could try something like
% Make the image binary
binaryimage = BW > 0;
% Get the linear indices of the closest points
[~, idx] = bwdist(binaryimage);
% Find the linear index for point (3, 2)
x = 3;
y = 2;
pointindex = sub2ind(size(binaryimage), y, x);
% Find the index of the closet point from the segmentation
closestpointindex = idx(pointindex);
% Get coordinates of the closest point
[yc, xc] = ind2sub(size(binaryimage), closestpointindex);
This will give you the coordinates (xc, yc) and the matrix index (closestpointindex) of the pixel with a non-zero value in the binary image which is closest to the point (x,y), where x and y are Matlab indices, remembering that Matlab indices start at 1 and rows are first, i.e. BW(y,x).

Centroid calculation for a connected component in 3D volume using Matlab

I am trying to implement brain tumor segmentation on 3D brain MRI(.mha data type).
After preliminary segmentation, I am applying 26-neighbor connected component algorithm(using bwconncomp) to obtain the largest connected component by obtaining the component with the largest volume, following which I need to calculate the centroid of the resultant component.
I am not sure if my method of calculating the largest connected component and the centroid is correct, because the centroid obtained and its nearby voxels all have value 0.
Also I am having confusion with the representation of 3D voxel coordinates. For eg. if centroid=(x,y,z), does it correspond to x=row,y=column and z=2D slice?
Any help would be appreciated. Below is my code with the relevant part.
CC=bwconncomp(Ibin,26); %Input Black & White 3D data of size 240x240x155
Pixelid=regionprops(CC,'PixelIdxList');
[prow pcol]=size(Pixelid);
maxval=numel(Pixelid(1).PixelIdxList);
index=1;
for i=1:prow
number=numel([Pixelid(i).PixelIdxList]);
if (number>maxval) %calculating the component with max number of voxels
maxval=number;
index=i;
end
end
for i=1:prow
if i~=index
Ibin(Pixelid(i).PixelIdxList)=0;
end
end
CC1=bwconncomp(Ibin,26);
Cent=regionprops(CC1,'Centroid');
I changed your code to the following:
CC=bwconncomp(Ibin,26);
PixelIdxList = CC.PixelIdxList;
maxval = numel(PixelIdxList{1});
index = 1;
for ii = 1:length(PixelIdxList)
number = numel(PixelIdxList{ii});
if number > maxval
maxval = number;
index = ii;
end
end
[y,x,z] = ind2sub(size(Ibin),PixelIdxList{index})
centroid = [mean(x), mean(y), mean(z)];
bwconncomp already gives you a PixelIdxList so you don't have to use regionprops. The PixelIdxList lists pixels by their linear indices, so you have to convert them into subscripts to get x, y, and z coordinates. The first dimension in MATLAB matrix represents y coordinates, and second dimension represents x, while the third dimension represents z. Centroid is calculated by taking the mean x, y, and z coordinates of all the pixels contained in the object.

Define points within a radius for post analysis

I'm new to matlab an I'm trying for figure something out. I have a matrix that is 50x50. It represents data I recorded behind a turbine. The turbine is essentially placed in the center of this plane at the point (25,25). It has a radius of 5. Therefore it reaches to (20,25) to the left and (30,25) to the right of the center of the matrix. I know the formula for distance calculation is pdist([dpx,dpy;centerx,centery]). But how do I set this up so that matlab will identify all the points within the radius of 5. Im trying to multiple all these points (only the points within the radius of the turbine) by their distance from the center of the matrix. I imagine a for loop is required but I have no idea how to apply it.
Create a coordinate grid:
[x, y] = meshgrid(1 : 50);
Compute the distance of each grid point from (25, 25):
d = sqrt((x - 25) .^ 2 + (y - 25) .^ 2);
Generate a logical array that contains 1 (true) for every grid place within the turbine area:
turb = (d <= 5);
You can plot the result:
imagesc(turb)
axis equal tight
Or use turb for selecting values from a measurement matrix m
m(turb)
using logical indexing.
Note that indices (25, 25) do not denote the center of a 50 x 50 grid, but rather (25.5, 25.5).
Using logical indexing, you can find the relevant indexes in the matrix and select only them:
[x,y] = meshgrid(1:50);
centered_valued = ((x-25).^2+(y-25).^2 <= 5^2);
requested_matrix = originalMatrix(centered_values);
The meshgrid function computes two matrices: the first one contains the x indexes in every row, the second one contains the y indexes of every column.
You then use boolean computation to find the indexes which are within the radius from the center (located in (25,25).
This logical array then can be used as an "index" for the original matrix. The result will be a smaller matrix (though you might be forced to use the (:) operator, as the result is not necessarily a rectangular matrix).
If you have the image processing toolbox, you can also use the bwdist command to do the distance calculation for you.
Create a mask with the center point selected:
bw = zeros(50,50); bw(25,25) = 1;
Calculate the distance to each point from the center (note bwdist also allows for a variety of distance calculations, see doc bwdist for details)
distance = bwdist(bw);
Create a mask of the turbine pixels:
turbine = (distance <= 5);
You asked about multiplying pixels in the turbine by their distance from the center. If the original data is stored in the 50x50 matrix orig, then you can do:
orig(turbine) = orig(turbine) .* distance(turbine);

Finding the max/min of a discrete image

Given a discrete image, e.g.:
how can one find the local minima/maxima locations?
EDIT:
Maximum and minimum in terms of derivative, not absolute max/min. In the example below the results should be two lines at the bottom, and some local peaks at the top.
Note that deriving is not that simple since the zero locations falls between pixels, and zero crossing in a 2d image is more complected than a 1d signal.
Thanks,
Find the linear index of the max/min (second output) and then use ind2sub to get the row and column coordinates.
%Assuming your image is stored in matrix I
[Vmax, Imax] = max(I(:));
[Rmax, Cmax] = ind2sub(size(I), Imax);
[Vmin, Imin] = min(I(:));
[Rmin, Cmin] = ind2sub(size(I), Imin);

Determine distance from coastline in Matlab

In MATLAB, I have an array of latitude and longitude pairs that represents locations in the United States. I need to determine the distance to the nearest coastline.
I think MATLAB has a built in database of lat/lon points of the United States. How do I access it and use it?
Also any suggestions on how to efficiently determine the distance?
Update: Follow-up question : Determine center of bins when using meshm
Since I don't have access to the Mapping Toolbox, which would be ideal to solve this problem, I came up with a solution that is independent of any toolboxes, including the Image Processing Toolbox.
Steve Eddins has an image processing blog at The MathWorks where last year he had a series of pretty cool posts devoted to using digital elevation maps. Specifically, he pointed out where to get them and how to load and process them. Here are the relevant blog posts:
Locating the US continental divide, part 1 - Introduction: Here, Steve shows where you can get digital elevation map (DEM) tiles and how to load and process them. You can get the DEM tiles (tile E and tile F cover the continental US) from the Global Land One-km Base Elevation Project. The latitude and longitude ranges for each tile can be found here.
Locating the US continental divide, part 4 - Ocean masks: Using the processed DEM data from the above post, Steve shows how to create an ocean mask.
With this DEM data, you can find out the latitude and longitude for where the edges of the oceans are, find the distance from an inland map point to the closest of these coastal points, then make a sweet visualization. I used the function FILTER2 to help find the edges of the oceans via convolution with the ocean mask, and the equations for computing great-circle distances to get the distance between map points along the surface of the Earth.
Using some of the sample code from the above blog posts, here's what I came up with:
%# Load the DEM data:
data_size = [6000 10800 1]; %# The data has 1 band.
precision = 'int16=>int16'; %# Read 16-bit signed integers into a int16 array.
header_bytes = 0;
interleave = 'bsq'; %# Band sequential. Not critical for 1 band.
byte_order = 'ieee-le';
E = multibandread('e10g',data_size,precision,... %# Load tile E
header_bytes,interleave,byte_order);
F = multibandread('f10g',data_size,precision,... %# Load tile F
header_bytes,interleave,byte_order);
dem = [E F]; %# The digital elevation map for tile E and F
clear E F; %# Clear E and F (they are huge!)
%# Crop the DEM data and get the ranges of latitudes and longitudes:
[r,c] = size(dem); %# Size of DEM
rIndex = [1 4000]; %# Row range of DEM to keep
cIndex = [6000 14500]; %# Column range of DEM to keep
dem = dem(rIndex(1):rIndex(2),cIndex(1):cIndex(2)); %# Crop the DEM
latRange = (50/r).*(r-rIndex+0.5); %# Range of pixel center latitudes
longRange = (-180/c).*(c-cIndex+0.5); %# Range of pixel center longitudes
%# Find the edge points of the ocean:
ocean_mask = dem == -500; %# The ocean is labeled as -500 on the DEM
kernel = [0 1 0; 1 1 1; 0 1 0]; %# Convolution kernel
[latIndex,longIndex] = ... %# Find indices of points on ocean edge
find(filter2(kernel,~ocean_mask) & ocean_mask);
coastLat = latRange(1)+diff(latRange).*... %# Convert indices to
(latIndex-1)./diff(rIndex); %# latitude values
coastLong = longRange(1)+diff(longRange).*... %# Convert indices to
(longIndex-1)./diff(cIndex); %# longitude values
%# Find the distance to the nearest coastline for a set of map points:
lat = [39.1407 35 45]; %# Inland latitude points (in degrees)
long = [-84.5012 -100 -110]; %# Inland longitude points (in degrees)
nPoints = numel(lat); %# Number of map points
scale = pi/180; %# Scale to convert degrees to radians
radiusEarth = 3958.76; %# Average radius of Earth, in miles
distanceToCoast = zeros(1,nPoints); %# Preallocate distance measure
coastIndex = zeros(1,nPoints); %# Preallocate a coastal point index
for iPoint = 1:nPoints %# Loop over map points
rho = cos(scale.*lat(iPoint)).*... %# Compute central angles from map
cos(scale.*coastLat).*... %# point to all coastal points
cos(scale.*(coastLong-long(iPoint)))+...
sin(scale.*lat(iPoint)).*...
sin(scale.*coastLat);
d = radiusEarth.*acos(rho); %# Compute great-circle distances
[distanceToCoast(iPoint),coastIndex(iPoint)] = min(d); %# Find minimum
end
%# Visualize the data:
image(longRange,latRange,dem,'CDataMapping','scaled'); %# Display the DEM
set(gca,'DataAspectRatio',[1 1 1],'YDir','normal',... %# Modify some axes
'XLim',longRange,'YLim',fliplr(latRange)); %# properties
colormap([0 0.8 0.8; hot]); %# Add a cyan color to the "hot" colormap
xlabel('Longitude'); %# Label the x axis
ylabel('Latitude'); %# Label the y axis
hold on; %# Add to the plot
plot([long; coastLong(coastIndex).'],... %'# Plot the inland points and
[lat; coastLat(coastIndex).'],... %'# nearest coastal points
'wo-');
str = strcat(num2str(distanceToCoast.',... %'# Make text for the distances
'%0.1f'),{' miles'});
text(long,lat,str,'Color','w','VerticalAlignment','bottom'); %# Plot the text
And here's the resulting figure:
I guess that puts me almost 400 miles from the nearest "ocean" coastline (in actuality, it's probably the Intracoastal Waterway).
load coast;
axesm('mercator');
plotm(lat,long)
There are other datasets in the same directory as coast.mat that might be more useful.
I would then just find the distance to all the points in the dataset, and take the shortest distance. This would assume that coastlines outside of the US are acceptable answers. You will want to use the distance function since Euclidean geometry does not apply here.
Gnovice's answer was nice and useful for the future but I did not need that high of fidelity and didn't want to spend extra timing converting from pixel distance to latitude/longitude distance. Taking MatlabDoug's answer, I wrote the following script:
% Get Data
coast = load('coast.mat');
locations = load('locations.mat');
% Preallocate
coast_indexes = nan(size(locations.lat));
distancefromcoast = nan(size(locations.lat));
% Find distance and corresponding coastal point
for i=1:1:numel(locations.lat)
[dist, az] = distance(locations.lat(i), locations.long(i), coast.lat, coast.long);
[distancefromcoast(i),coast_indexes(i)] = min(dist);
end