How to find the best averaging pattern in image

2 views (last 30 days)
Hi, I have an image in jpg format
That is the image of a metallic wire-mesh, of course the mesh is not regular, and I have to find the 'medium' pattern that best represents all the meshes present, i.e. the mesh within the net that has the greatest number of similar meshes.
I am thinking of using normxcorr2, but I cannot understand how to automate the search given an image.
My goal is to read the image of the complete network and to obtain through MatLab the jersey that has the most similarities within the complete network.
With normxcorr2 in general I can find the similarity given an external pattern, my idea to solve this problem is to subdivide the image with a grid (where ongi block will contain a single mesh), then the software will go to take each block of the grid and will compare it with the whole image via normxcorr2.
At the end of the process, having analyzed all the blocks, I should obtain the block (containing a single link) that obtained the highest number of similar links (clearly setting a value of the correlation coefficients, beyond which the software will give a positive result).
I attach the file of the net, and the file of the pattern to make it clear what I'm talking about.
Thank you

Accepted Answer

Image Analyst
Image Analyst on 14 Mar 2020
OK, here is a complete demo. I made some changes from my other answer, which was just off the top of my head. Input image and final script are attached.
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 = 15;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = pwd;
baseFileName = 'complete_net.jpg';
% Get the full filename, with path prepended.
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
% Read in the image from disk. If storedColorMap is not empty, it's an indexed image with a stored colormap.
[grayImage, storedColorMap] = imread(fullFileName);
if ~isempty(storedColorMap)
grayImage = ind2rgb(grayImage, storedColorMap);
end
% Get 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 > 1
% It's not really gray scale like we expected - it's color.
% Use weighted sum of ALL channels to create a gray scale image.
grayImage = rgb2gray(grayImage);
% ALTERNATE METHOD: Convert it to gray scale by taking only the green channel,
% which in a typical snapshot will be the least noisy channel.
% grayImage = grayImage(:, :, 2); % Take green channel.
end
% Display the image.
hFig = figure;
subplot(2, 3, 1);
imshow(grayImage, []);
title('Original Grayscale Image', 'FontSize', fontSize, 'Interpreter', 'None');
hFig.WindowState = 'maximized'; % May not work in earlier versions of MATLAB.
drawnow;
% Display the histogram
subplot(2, 3, 2);
imhist(grayImage);
grid on;
title('Histogram of Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
%--------------------------------------------------------------------------------------------------------
% SEGMENTATION
% Binarize the image
% binaryImage = imbinarize(grayImage);
binaryImage = grayImage > 225;
% Display the image.
subplot(2, 3, 3);
imshow(binaryImage, []);
title('Initial Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
axis('on', 'image');
% Fill holes.
binaryImage = imfill(binaryImage, 'holes');
% Get rid of partial blobs touching the border.
binaryImage = imclearborder(binaryImage);
% This image has some really tiny blobs that we don't want.
% Find out the areas so we can figure out what size corresponds to the small ones.
props = regionprops(binaryImage, 'Area');
allAreas = [props.Area];
fprintf('Initially found %d blobs in the image.\n', length(allAreas));
fprintf('Blobs range in size from %d pixels to %d pixels.\n', min(allAreas), max(allAreas));
% Get the min size to accept as the middle area between the smallest and largest blob.
smallestAcceptableBlobArea = round(mean([min(allAreas), max(allAreas)])); % Rounding because bwareaopen() needs an integer
% Now get rid of blobs smaller than smallestAcceptableBlobArea.
fprintf('Extracting only the blobs that are larger than %d pixels.\n', smallestAcceptableBlobArea);
binaryImage = bwareaopen(binaryImage, smallestAcceptableBlobArea);
[labeledImage, numBlobs] = bwlabel(binaryImage);
fprintf('After throwing out %d blobs smaller than %d pixels, we are left with %d blobs in the image.\n', length(allAreas) - numBlobs, smallestAcceptableBlobArea, numBlobs);
% Let's assign each blob a different color to visually show the user the distinct blobs.
coloredLabels = label2rgb (labeledImage, 'hsv', 'k', 'shuffle'); % pseudo random color labels
% coloredLabels is an RGB image. We could have applied a colormap instead (but only with R2014b and later)
imshow(coloredLabels);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.
caption = sprintf('%d blobs that are completely within the image', numBlobs);
title(caption, 'FontSize', fontSize);
drawnow;
%--------------------------------------------------------------------------------------------------------
% COMPUTATION OF AVERAGE SHAPE
% Make the average image of all the blobs by summing all the shapes.
% First need to find the individual blob images from regionprops().
props = regionprops(binaryImage, 'Image');
sumImage = zeros(size(binaryImage));
subplot(2, 3, 4);
numberOfShapes = length(props);
for k = 1 : numberOfShapes
% Crop blob from image
croppedBlob = props(k).Image;
[croppedRows, croppedColumns] = size(croppedBlob);
% Drop onto summation image.
row1 = round(rows/2 - croppedRows/2);
row2 = row1 + croppedRows - 1;
col1 = round(columns/2 - croppedColumns/2);
col2 = col1 + croppedColumns - 1;
sumImage(row1:row2, col1:col2) = sumImage(row1:row2, col1:col2) + croppedBlob;
% Display the image so far.
imshow(sumImage, []);
caption = sprintf('Summation Image after %d of %d shapes have been added in', k, numberOfShapes);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
end
% Let's crop it to get rid of the black surround. This will let us see the shape larger.
props = regionprops(sumImage > 0, 'BoundingBox');
sumImage = imcrop(sumImage, props.BoundingBox);
imshow(sumImage, []);
caption = sprintf('Summation Image after %d shapes have been added in', k);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo
axis('on', 'image');
hold on;
% Threshold this halfway up to get the average shape.
% The image will be slightly smaller than sumImage because we're not including the dimmer stuff around the edges.
finalShape = sumImage > numberOfShapes / 2;
% Let's crop it to get rid of the black surround.
props = regionprops(finalShape, 'BoundingBox');
finalShape = imcrop(finalShape, props.BoundingBox);
% Now display the final average shape image.
subplot(2, 3, 5);
impixelinfo
imshow(finalShape);
axis('on', 'image');
caption = sprintf('The Average Shape');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
hold on;
fprintf('Done with demo! Thanks Image Analyst! You are awesome!\n');
The command window shows:
Initially found 92 blobs in the image.
Blobs range in size from 1 pixels to 5928 pixels.
Extracting only the blobs that are larger than 2965 pixels.
After throwing out 41 blobs smaller than 2965 pixels, we are left with 51 blobs in the image.
  3 Comments
Image Analyst
Image Analyst on 14 Mar 2020
In case you want to find out how close each shape is to the average shape, I XORed the shapes with the average and counted the number of pixels that they are different from each other, and marked the one with the shape closest to the average shape, and the shape with the biggest difference from the average shape. See attached code and image.

Sign in to comment.

More Answers (2)

Image Analyst
Image Analyst on 14 Mar 2020
What I'd do is to threshold the image and then call regionprops and ask for the centroid and bounding box. Then, for each region, crop out the blob, and drop in onto an accumulation image where the centroids are all aligned. Now you have a summation image of all the blobs where the centers are overlapped. So if you have, say, 200 blobs, threshold at half that amount (100) to get the average shape. Here's a start
mask = grayImage > 128;
props = regionprops(mask, 'BoundingBox', 'Centroid');
sumImage = zeros(size(mask));
for k = 1 : length(props)
% Get bounding box of this blob.
thisBB = props(k).BoundingBox;
% Get centroid of this blob.
x = props(k).Centroid(1); % Column
y = props(k).Centroid(2); % Row
% Crop blob from image
croppedBlob = imcrop(mask, thisBB);
% Drop onto summation image.
row1 = round(....)
row2 =
col1 = ....
col2 = ......
sumImage(row1:row2, col1:col2) = croppedBlob
end
imshow(sumImage, [])
So you can figure out what row1, row2, col1, and col2 are. Make sure you round them! A smart engineer like you should be able to figure out the algebra required to place it at the center (x, y) or (columns/2, rows/2) of the image. Be sure to realize that (x,y) is not the same as (row, column) - a common beginner mistake. (x,y) is (column, row), NOT (row, column), and (column, row) is (y, x), NOT (x,y).
Images are arrays and are indexed (row, column) which is (y, x), just as all arrays are.

Praveen Patnaik
Praveen Patnaik on 15 Mar 2020
@ image analyst
Hello Sir,
Can you look into this optimisation problem with a script
Minimising the summation of distance between two curves by placing the arc at best distance from origin

Community Treasure Hunt

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

Start Hunting!