Recognize edges in mosaic-like background - draw horizontal lines and save line coordinates

Hello,
I am looking for a good automated method to find the edges of the horizontal gray surfaces in the mosaic background. The edges should be displayed with horizontal lines (like Sample.jpg). The gray surfaces could be a little tilted, but it's enough for me if the lines are displayed horizontally,
Thx

 Respuesta aceptada

Try this. (Similar to @Les Beckham's solution but developed before I saw his answer):
% Demo by Image Analyst
% https://www.mathworks.com/matlabcentral/answers/2044247-recognize-edges-in-mosaic-like-background-draw-horizontal-lines-and-save-line-coordinates?s_tid=srchtitle
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 = 16;
markerSize = 20;
%--------------------------------------------------------------------------------------------------------
% READ IN TEST IMAGE
folder = [];
baseFileName = 'sample 1.jpg';
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
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);
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage, []);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Update the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
if numberOfColorChannels == 3
grayImage = rgb2gray(grayImage);
end
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
g.Name = 'Demo by Image Analyst';
g.NumberTitle = 'off';
drawnow;
%--------------------------------------------------------------------------------------------------------
% Get the mean vertical profile of the standard deviation of each row.
verticalProfile = std(single(grayImage), 0, 2);
% Smooth out noise but leave big dips
verticalProfile = movmedian(verticalProfile,61);
subplot(2, 2, 2);
plot(verticalProfile, 'b-', 'LineWidth', 2);
title('Standard Deviation Row-by-Row', 'FontSize', fontSize, 'Interpreter', 'None');
xlabel('Row of Image', 'FontSize', fontSize, 'Interpreter', 'None');
ylabel('Standard Deviation', 'FontSize', fontSize, 'Interpreter', 'None');
grid on;
drawnow;
%--------------------------------------------------------------------------------------------------------
% Get mask by thresholding at 62.
grayRegions = verticalProfile' <= 62;
% Get tops
topLines = strfind(grayRegions, [0, 1])
% Get bottoms
bottomLines = strfind(grayRegions, [1, 0])
subplot(2, 2, 3);
imshow(grayImage, []);
axis('on', 'image');
hold on;
% Draw line at edges
for k = 1 : numel(topLines)
yline(topLines(k), 'Color', 'y', 'LineWidth', 3);
end
for k = 1 : numel(bottomLines)
yline(bottomLines(k), 'Color', 'y', 'LineWidth', 3);
end
title('Edges Identified', 'FontSize', fontSize, 'Interpreter', 'None');

4 comentarios

Nice work @Image Analyst. As I said, I was confident that the image analysis experts would do this better than I could, but is nice to know that my concept for solving this was reasonable.
It looks like you used a row standard deviation as well, but with filtering, which I had thought about, but didn't bother to try. I was hoping that the idea would push the OP in the right direction to solve their own problem. I think your answer will push them a little further in that direction.
I thought about testing for crossings through "around 62" as well, but since I couldn't envision a way to make that threshold "auto-detect", I just adjusted the xline values until they looked right. I'm assuming that you did something similar (e.g., just looking at the filtered std plot) to arrive at the test conditions of "grayRegions = verticalProfile' <= 62;".
Based on OP's statement that they are "looking for an solution that automatically determines the lines", I suspect that they are out of luck for an "automated" (i.e., no human judgement involved) solution, unless the image capturing is very consistent.
@Les Beckham yes, a crucial component to doing image analysis is to do everything you can to make sure you can get consistent images, like with the same lighting, exposure time, etc. And a jig to mount the samples in a consistent place. Avoid shadows, use concentric lenses (if needed), etc. etc. Do background correction (flat field correction) to compensate for the lens shading that lenses always have. I've designed many light booths. It's always best to start with as good an image as you can rather than try to compensate for a lousy image in post-capture image processing.
If you can do that, then you can often get by with a fixed threshold, like 62, which is better, more consistent, and more reliable than having to develop an automatic threshold where the threshold must be adjusted for every image because you don't have control of your image capture conditions.
Nonetheless, it would still be possible to develop an automated routine to find the threshold (edges of the stripe). Let's hope that it's not necessary and that a fixed threshold will work fine.
Thanks for all of your excellent contributions to this forum and for teaching me (and, hopefully, the OP).
It was gratifying to see that my naive thoughts about how to approach this were not to far off the mark (probably from all of the reading I have done on this forum).

Iniciar sesión para comentar.

Más respuestas (1)

Big caveat: I'm not even close to an image processing expert so there is probably a smarter way to do this.
I noticed that the two bands seem to have a more uniform grey, while the rest of the fabric (?) is more black and white, so I decided to use the standard deviations of the rows to look for the edges.
im = imread('1.jpg');
img = im2gray(im);
ims = imshow(img);
rowmean = mean(img, 2);
rowstd = std(double(img), 0, 2);
plot(rowstd)
xline([280 385 805 930]) % <<< I experimented with changing these numbers to line up on the "edges"
grid on
Now I've found the row numbers in the image that define the "edges".
Unfortunately, I couldn't figure out how to draw the lines on top of the image.

1 comentario

its a good idea with the mean function but its not a automated solution. With your approach I have to determine the line coordinates manually. I am looking for an solution that automatically determines the lines (coordinates)

Iniciar sesión para comentar.

Categorías

Preguntada:

el 7 de Nov. de 2023

Comentada:

el 10 de Nov. de 2023

Community Treasure Hunt

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

Start Hunting!

Translated by