Find the intersections of a series of curves of an image: Matlab - matlab

I have an image with a series of lines, like below:
I would like to know if there is some method for finding the intersections of all of the lines.
I was checking another post where they offer a way to find the intersections, but once the image is segmented I suppose it has noise or something similar... I will start with a simple image to find each intersection.
My main idea was to solve the "system of equations" but I think for an image with many intersections would be too difficult, I do not know if there is any method to find all intersections.

I assume you don't have the line equations. I used skeletonization and filtering to detect small areas with more than one line crossing them. I'm not sure that it will be so simple for noisy image but it worth trying:
im = im2double(rgb2gray(imread('lines.png')));
% binarize black lines
bw = im == 0;
% skelatonize lines
sk = bwmorph(bw,'skel',inf);
% filter skeleton with 3X3 ones filter
A = imfilter(double(sk),ones(3));
% find blobs greater than 4 - more than one line crossing the filter
B = A > 4;
% get centroids of detected blobs
C = regionprops(B,'Centroid');
Cent = reshape([C.Centroid],2,[]).';
% plot
imshow(im)
hold on;
plot(Cent(:,1),Cent(:,2),'gx','LineWidth',2)

Related

Detect parallel lines using Hough transform in matlab

Suppose there is a binary image of a black background and white lines "plotted" on it, i.e., they aren't burnt onto the image. For example:
I need to retain only the lines that are parallel to atleast one of the other lines in the picture. If not perfectly parallel, at least close enough to be parallel(perhaps a variable that can control the degree of parallelism would help with that). In other words, if I choose a particular line and it has one or more lines that are parallel to it, I retain it, else I discard it. I need to do that for all lines in the image.
I came across Hough transform but I'm having trouble understanding how to use the bins to check the orientations and determine parallel lines. Or is there a better way to go about this?
Also, since the lines aren't a part of the image and are just plotted on it, I don't have an image to feed into the Hough Transform function. Can I use the output of the plot function as input directly? This is the code I wrote to plot the white lines:
Location1 is a m-by-2 matrix that contains the coordinates to draw the lines.
figure; imshow(blackImage);
hold on ;
for i=1:size(Location1,1)-1
h = plot([Location1(i,1) Location1(i+1,1)], [Location1(i,2) Location1(i+1,2)]) ;
set(h,'linewidth', .1, 'color', 'b') ;
end
Any help would be appreciated.
Given that
for i=1:size(Location1,1)-1
% one line = Location1(i,:) to Location1(i+1,:)
end
then
theta = atan2(diff(Location1(:,2)),diff(Location1(:,1)));
But since lines are parallel even if their theta is in the opposite direction, you want to map all angles to half a circle:
theta = mod(theta,pi/2);
Now theta is in the range [-π/2,π/2].
To find similar angles:
[s,i] = sort(theta);
k = find(diff(s)<0.01); % diff(s) is always positive because s is sorted
i = i([k,k+1]);
theta(i) % <-- sets of similar angles
% Location1(i,:),Location1(i+1,:) <- corresponding lines

Image Segmentation Matlab

I have this BW image:
And using the function RegionProps, it shows that some objetcs are connected:
So I used morphological operations like imerode to separte the objects to get their centroids:
Now I have all the centroids of each object separated, but to that I lost a lot of information when eroding the region, like you can see in picture 3 in comparison with picture 1.
So I was thinking if is there anyway to "dilate" the picture 3 till get closer to picture 1 but without connecting again the objects.
You might want to take a look at bwmorph(). With the 'thicken', inf name-value pair it will thicken the labels until they would overlap. It's a neat tool for segmentation. We can use it to create segmentation borders for the original image.
bw is the original image.
labels is the image of the eroded labels.
lines = bwmorph(labels, 'thicken', inf);
segmented_bw = bw & lines
You could also skip a few phases and achieve similiar results with a marker based watershed. Or even better, as the morphological seesaw has destroyed some information as seen on the poorly segmented cluster on the lower right.
You can assign each white pixel in the mask to the closest centroid and work with the resulting label map:
[y x]= find(bw); % get coordinates of mask pixels
D = pdist2([x(:), y(:)], [cx(:), cy(:)]); % assuming cx, cy are centers' coordinates
[~, lb] = min(D, [], 2); % find index of closest center
lb_map = 0*bw;
lb_map(bw) = lb; % should give you the map.
See pdist2 for more information.

Extract Individual Line Segment Coordinates from Boundary Image - MATLAB

I have a MATLAB script that gives me the boundary lines of an image using bwboundaries().
Now, after plotting that image, I am getting the complete image, formed from various straight line segments.
I would like to get the coordinates or show the individual line segments that form the boundary.
I think the method is called digital straightness of lines, but I want to know how to apply it here in this case.
[B,L,N] = bwboundaries(z,'noholes');
for k=1:length(B),
boundary = B{k};
if(k > N)
figure, plot(boundary(:,2),boundary(:,1),'g','LineWidth',2);
else
figure, plot(boundary(:,2),boundary(:,1),'r','LineWidth',2);
end
end
According to my understanding of your question,my idea is to use bwtraceboundary().
BW = imread('image.png');
imshow(BW,[]);
r = 165; % you can get the r and c for your image using "impixelinfo"
c = 43;
contour = bwtraceboundary(BW,[r c],'W',4,Inf,'counterclockwise');
hold on;
plot(contour(:,2),contour(:,1),'g','LineWidth',2);
x=contour(:,2)'
y=contour(:,2)'
Am I answering your question?
Use regionprops('desired feature') on the labelled image.
To generate a labelled image use
bwlabel(Img) (high memory usage)
or
bw=bwconncomp(Img,conn) (low memory use)
followed by
labelmatrix(bw)
The best way to proceed would probably be to use a Hough Transform to first get an idea of the lines present in the image. You can play around with Hough Transform to extract the end points of the lines.

Calculate the average of part of the image

How can i calculate the average of a certain area in an image using mat-lab?
For example, if i have an intensity image with an area that is more alight and i want to know what is the average of the intensity there- how do i calculate it?
I think i can find the coordinates of the alight area by using the 'impixelinfo' command.
If there is another more efficient way to find the coordinates i will also be glad to know.
After i know the coordinates how do i calculate the average of part of the image?
You could use one of the imroi type functions in Matlab such as imfreehand
I = imread('cameraman.tif');
h = imshow(I);
e = imfreehand;
% now select area on image - do not close image
% this makes a mask from the area you just drew
BW = createMask(e);
% this takes the mean of pixel values in that area
I_mean = mean(I(BW));
Alternatively, look into using regionprops, especially if there's likely to be more than one of these features in the image. Here, I'm finding points in the image above some threshold intensity and then using imdilate to pick out a small area around each of those points (presuming the points above the threshold are well separated, which may not be the case - if they are too close then imdilate will merge them into one area).
se = strel('disk',5);
BW = imdilate(I>thresh,se);
s = regionprops(BW, I, 'MeanIntensity');

MATLAB Image Processing - Find Edge and Area of Image

As a preface: this is my first question - I've tried my best to make it as clear as possible, but I apologise if it doesn't meet the required standards.
As part of a summer project, I am taking time-lapse images of an internal melt figure growing inside a crystal of ice. For each of these images I would like to measure the perimeter of, and area enclosed by the figure formed. Linked below is an example of one of my images:
The method that I'm trying to use is the following:
Load image, crop, and convert to grayscale
Process to reduce noise
Find edge/perimeter
Attempt to join edges
Fill perimeter with white
Measure Area and Perimeter using regionprops
This is the code that I am using:
clear; close all;
% load image and convert to grayscale
tyrgb = imread('TyndallTest.jpg');
ty = rgb2gray(tyrgb);
figure; imshow(ty)
% apply a weiner filter to remove noise.
% N is a measure of the window size for detecting coherent features
N=20;
tywf = wiener2(ty,[N,N]);
tywf = tywf(N:end-N,N:end-N);
% rescale the image adaptively to enhance contrast without enhancing noise
tywfb = adapthisteq(tywf);
% apply a canny edge detection
tyedb = edge(tywfb,'canny');
%join edges
diskEnt1 = strel('disk',8); % radius of 4
tyjoin1 = imclose(tyedb,diskEnt1);
figure; imshow(tyjoin1)
It is at this stage that I am struggling. The edges do not quite join, no matter how much I play around with the morphological structuring element. Perhaps there is a better way to complete the edges? Linked is an example of the figure this code outputs:
The reason that I am trying to join the edges is so that I can fill the perimeter with white pixels and then use regionprops to output the area. I have tried using the imfill command, but cannot seem to fill the outline as there are a large number of dark regions to be filled within the perimeter.
Is there a better way to get the area of one of these melt figures that is more appropriate in this case?
As background research: I can make this method work for a simple image consisting of a black circle on a white background using the below code. However I don't know how edit it to handle more complex images with edges that are less well defined.
clear all
close all
clc
%% Read in RGB image from directory
RGB1 = imread('1.jpg') ;
%% Convert RPG image to grayscale image
I1 = rgb2gray(RGB1) ;
%% Transform Image
%CROP
IC1 = imcrop(I1,[74 43 278 285]);
%BINARY IMAGE
BW1 = im2bw(IC1); %Convert to binary image so the boundary can be traced
%FIND PERIMETER
BWP1 = bwperim(BW1);
%Traces perimeters of objects & colours them white (1).
%Sets all other pixels to black (0)
%Doing the same job as an edge detection algorithm?
%FILL PERIMETER WITH WHITE IN ORDER TO MEASURE AREA AND PERIMETER
BWF1 = imfill(BWP1); %This opens figure and allows you to select the areas to fill with white.
%MEASURE PERIMETER
D1 = regionprops(BWF1, 'area', 'perimeter');
%Returns an array containing the properties area and perimeter.
%D1(1) returns the perimeter of the box and an area value identical to that
%perimeter? The box must be bounded by a perimeter.
%D1(2) returns the perimeter and area of the section filled in BWF1
%% Display Area and Perimeter data
D1(2)
I think you might have room to improve the effect of edge detection in addition to the morphological transformations, for instance the following resulted in what appeared to me a relatively satisfactory perimeter.
tyedb = edge(tywfb,'sobel',0.012);
%join edges
diskEnt1 = strel('disk',7); % radius of 4
tyjoin1 = imclose(tyedb,diskEnt1);
In addition I used bwfill interactively to fill in most of the interior. It should be possible to fill the interior programatically but I did not pursue this.
% interactively fill internal regions
[ny nx] = size(tyjoin1);
figure; imshow(tyjoin1)
tyjoin2=tyjoin1;
titl = sprintf('click on a region to fill\nclick outside window to stop...')
while 1
pts=ginput(1)
tyjoin2 = bwfill(tyjoin2,pts(1,1),pts(1,2),8);
imshow(tyjoin2)
title(titl)
if (pts(1,1)<1 | pts(1,1)>nx | pts(1,2)<1 | pts(1,2)>ny), break, end
end
This was the result I obtained
The "fractal" properties of the perimeter may be of importance to you however. Perhaps you want to retain the folds in your shape.
You might want to consider Active Contours. This will give you a continous boundary of the object rather than patchy edges.
Below are links to
A book:
http://www.amazon.co.uk/Active-Contours-Application-Techniques-Statistics/dp/1447115570/ref=sr_1_fkmr2_1?ie=UTF8&qid=1377248739&sr=8-1-fkmr2&keywords=Active+shape+models+Andrew+Blake%2C+Michael+Isard
A demo:
http://users.ecs.soton.ac.uk/msn/book/new_demo/Snakes/
and some Matlab code on the File Exchange:
http://www.mathworks.co.uk/matlabcentral/fileexchange/28149-snake-active-contour
and a link to a description on how to implement it: http://www.cb.uu.se/~cris/blog/index.php/archives/217
Using the implementation on the File Exchange, you can get something like this:
%% Load the image
% You could use the segmented image obtained previously
% and then apply the snake on that (although I use the original image).
% This will probably make the snake work better and the edges
% in your image is not that well defined.
% Make sure the original and the segmented image
% have the same size. They don't at the moment
I = imread('33kew0g.jpg');
% Convert the image to double data type
I = im2double(I);
% Show the image and select some points with the mouse (at least 4)
% figure, imshow(I); [y,x] = getpts;
% I have pre-selected the coordinates already
x = [ 525.8445 473.3837 413.4284 318.9989 212.5783 140.6320 62.6902 32.7125 55.1957 98.6633 164.6141 217.0749 317.5000 428.4172 494.3680 527.3434 561.8177 545.3300];
y = [ 435.9251 510.8691 570.8244 561.8311 570.8244 554.3367 476.3949 390.9586 311.5179 190.1085 113.6655 91.1823 98.6767 106.1711 142.1443 218.5872 296.5291 375.9698];
% Make an array with the selected coordinates
P=[x(:) y(:)];
%% Start Snake Process
% You probably have to fiddle with the parameters
% a bit more that I have
Options=struct;
Options.Verbose=true;
Options.Iterations=1000;
Options.Delta = 0.02;
Options.Alpha = 0.5;
Options.Beta = 0.2;
figure(1);
[O,J]=Snake2D(I,P,Options);
If the end result is an area/diameter estimate, then why not try to find maximal and minimal shapes that fit in the outline and then use the shapes' area to estimate the total area. For instance, compute a minimal circle around the edge set then a maximal circle inside the edges. Then you could use these to estimate diameter and area of the actual shape.
The advantage is that your bounding shapes can be fit in a way that minimizes error (unbounded edges) while optimizing size either up or down for the inner and outer shape, respectively.