I have image with black background and white lines. How to find co-ordinate (x,y) of end points of white lines on that image?

7 visualizaciones (últimos 30 días)

Respuesta aceptada

Image Analyst
Image Analyst el 15 de Dic. de 2015
It looks to me like my code works, as long as you skeletonize your lines before finding branchpoints and endpoints. See code below and image below that it creates.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
% clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 20;
%===============================================================================
% Read in a gray scale demo image.
folder = pwd;
baseFileName = 'image.png';
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% File doesn't exist -- didn't find it there. Check the search path for it.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
grayImage = imread(fullFileName);
% Get the dimensions of the image.
% numberOfColorBands should be = 1.
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
% Convert it to gray scale by taking only the green channel.
grayImage = grayImage(:, :, 2); % Take green channel.
end
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
axis on;
title('Original Grayscale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0 1 1]);
% Get rid of tool bar and pulldown menus that are along top of figure.
set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
set(gcf, 'Name', 'Demo by ImageAnalyst', 'NumberTitle', 'Off')
% Unfortunately the image was saved as color so we need to get the circle only.
% Threshold the image at 128 to binarize it.
binaryImage = grayImage >= 128;
% Crop out the center part, getting rid of the 4 pixel wide border that's there for some reason.
binaryImage = binaryImage(4:end-4, 4:end-4);
% Make sure it's skeletonized to 8-connected, not 4-connected like it is originally
binaryImage = bwmorph(binaryImage, 'skel', inf);
% Display the image.
subplot(2, 2, 2);
imshow(binaryImage, []);
axis on;
title('Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
branchpoints = bwmorph(binaryImage, 'branchpoints');
[rowsBP, columnsBP] = find(branchpoints)
% Display the image.
subplot(2, 2, 3);
imshow(branchpoints, []);
axis on;
title('Branchpoints Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Plot circles over the branchpoints because we can't see all of them due to subsampling for display on the monitor.
hold on;
for k = 1 : length(rowsBP);
plot(columnsBP(k), rowsBP(k), 'ro', 'MarkerSize', 12, 'LineWidth', 2);
end
% You can find the endpoints where a single line hits the edge of the image using the 'endpoints' option instead of branchpoints.
endpoints = bwmorph(binaryImage, 'endpoints');
[rowsEP, columnsEP] = find(endpoints);
% Display the image.
subplot(2, 2, 4);
imshow(endpoints, []);
axis on;
title('Endpoints Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Plot circles over the endpoints because we can't see all of them due to subsampling for display on the monitor.
hold on;
for k = 1 : length(rowsEP);
plot(columnsEP(k), rowsEP(k), 'ro', 'MarkerSize', 12, 'LineWidth', 2);
end
% Tell user we're done
message = sprintf('Done!');
uiwait(helpdlg(message));
  1 comentario
LAKSHMANAN ADAIKKAPPAN
LAKSHMANAN ADAIKKAPPAN el 16 de Dic. de 2015
Thank you very much sir for your guidance. The code perfectly worked for my application and also worked for various images. once again thank you very much for your guidance.

Iniciar sesión para comentar.

Más respuestas (2)

Image Analyst
Image Analyst el 14 de Dic. de 2015
To find where the lines branch, use
branchpoints = bwmorph(binaryImage, 'branchpoints');
[rows, columns] = find(branchpoints);
You can find the endpoints where a single line hits the edge of the image using the 'endpoints' option instead of branchpoints.
endpoints = bwmorph(binaryImage, 'endpoints');
[rows, columns] = find(endpoints);
  2 comentarios
LAKSHMANAN ADAIKKAPPAN
LAKSHMANAN ADAIKKAPPAN el 15 de Dic. de 2015
Thank you for your guidance. I find end points where a single line hits the edge of the image using this code. But i could not find end coordinate of each line(branch) in this image. This will give rows 1559x1 double columns 1559x1 double. But i need only endpoint of each line segment(branch). please help me.

Iniciar sesión para comentar.


John BG
John BG el 15 de Dic. de 2015
Hi, Perhaps LAKSHMANAN ADAIKKAPPAN does not have the Image Toolbox. I tried with R2012 image toolbox and your code did not find a single node.
Let me suggest a different approach:
1. grid the image with enough resolution so that there is only one node per image block
2. recur: repeat only on the blocks where nodes have been found
% BW: image that looks like binary,
% but 1.- values are [0:255] not [0 1] 2.- has 3 layers, slightly misaligned
BW=imread('binary cells map.jpg')
% .jpg .png files have 3 layers, haven't found a single BW image in .jpg slightly, ever
% always missaligned, even fill all black grap a white-white pend and draw a line
% has to do with compression and perhaps OS embedding data in the image with slight
% colour variations,never mind
BW=BW(:,:,1) % not a standard way to clean image supposed to be BW, but as starter will do
[BWy,BWx]=size(BW)
% augenblick: choose a block size to split your image that will roughly catch 1 or no nodes, % I say split 7 for Y, 5 for X
Amount_Blocks_x=7; Amount_Blocks_y=5
blocky=floor(linspace(1,BWy,Amount_Blocks_y));blockx=floor(linspace(1,BWx,Amount_Blocks_x))
% With 7 5 i can see a couple blocks where there is more than one crossing take place
figure(1);imshow(BW);xlabel('X');ylabel('Y');hold all
for i=2:1:Amount_Blocks_x-1 plot([blockx(i) blockx(i)],[0 BWy],'r'); end
for i=2:1:Amount_Blocks_y-1 plot([1 BWx],[blocky(i) blocky(i)],'r'); end
% so increase blocks resolution a bit, meaning decrease blocks size:
Amount_Blocks_x=9; Amount_Blocks_y=7
blocky=floor(linspace(1,BWy,Amount_Blocks_y));blockx=floor(linspace(1,BWx,Amount_Blocks_x))
figure(2);imshow(BW);xlabel('X');ylabel('Y'); % same as ax.XLabel.String='X';ax.XLabel.String('Y')
hold all
for i=2:1:Amount_Blocks_x-1 plot([blockx(i) blockx(i)],[0 BWy],'r'); end
for i=2:1:Amount_Blocks_y-1 plot([1 BWx],[blocky(i) blocky(i)],'r'); end
% increase resolution further
Amount_Blocks_x=12; Amount_Blocks_y=12
blocky=floor(linspace(1,BWy,Amount_Blocks_y));blockx=floor(linspace(1,BWx,Amount_Blocks_x))
figure(3);imshow(BW);xlabel('X');ylabel('Y'); hold all
for i=2:1:Amount_Blocks_x-1 plot([blockx(i) blockx(i)],[0 BWy],'r'); end
for i=2:1:Amount_Blocks_y-1 plot([1 BWx],[blocky(i) blocky(i)],'r'); end
% Now I am confident to say only that all blocks with nodes or crossings have 3
% or 4 sides crossed by lines Let's spot blocks containing nodes
Ny=floor(mean(diff(linspace(1,BWy,Amount_Blocks_y))));
Nx=floor(mean(diff(linspace(1,BWx,Amount_Blocks_y))))
% Nxy % blocks size simplified to non-overlapping and squares
mark_block=zeros(Amount_Blocks_y,Amount_Blocks_x)
block_with_crossings_x=0;block_with_crossings_y=0
for i=1:1:numel(blockx)-1 % x sweep
for j=1:1:numel(blocky)-1 % y sweep
bw_block=BW([blocky(j):1: blocky(j+1)],[blockx(i):1:blockx(i+1)])
bwblk_top_line=bw_block(1,:) % top line
bwblk_bot_line=bw_block(end,:)' % bottom line
bwblk_left_line=bw_block(:,1) % left side line
bwblk_right_line=bw_block(:,end)' % right side line
tp_ln_ref=find(bwblk_top_line>250)
bt_ln_ref=find(bwblk_bot_line>250)
lft_ln_ref=find(bwblk_left_line>250)
rght_ln_ref=find(bwblk_right_line>250)
% catch blocks with 4 sides or 3 sides crossed by line
if ((numel(tp_ln_ref)>0)&&(numel(bt_ln_ref)>0)&&...
(numel(lft_ln_ref)>0)&&(numel(rght_ln_ref)>0)) mark_block(i,j)=1; end
if ((numel(bt_ln_ref)>0)&&(numel(lft_ln_ref)>0)&&...
(numel(rght_ln_ref)>0)) mark_block(i,j)=1; end
if ((numel(tp_ln_ref)>0)&&(numel(lft_ln_ref)>0)&&...
(numel(rght_ln_ref)>0)) mark_block(i,j)=1; end
if ((numel(tp_ln_ref)>0)&&(numel(bt_ln_ref)>0)&&...
(numel(rght_ln_ref)>0)) mark_block(i,j)=1; end
if ((numel(tp_ln_ref)>0)&&(numel(bt_ln_ref)>0)&&...
(numel(lft_ln_ref)>0)) mark_block(i,j)=1; end
% it could still be u turns hitting all sides but lines not crossing: recur,
% smaller blocks inside blocks blocks that flagged
end
end
% find coordinates of blocks containing node
spot_mark_block=find(mark_block>0);[I,J]=ind2sub(size(mark_block),spot_mark_block)
% count them all
numel(mark_block(mark_block>0))
% crossings_x(1)=[];crossings_y(1)=[]
% imshow(BW)
% hold all
% plot(crossings_x,crossings_y,'og')
If you find this to be the correct approach, I challenge you to increase resolution
1.- to find possibly missed crossings, for instance 2 diagonal parallels would hit all 4 sides yet if the block is too big it would give a false node 2.- achieve accurate coordinates of the all nodes found
I also tried for each block to calculate 2 lines and find possible intersections, but reached time limit for this question. It would approximate anyway, recurring with smaller blocks is the best way, and without the Image Toolbox.
If you choose to develop this solution let me know about your progress.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by