
detect defects (notches and breaks) in rubber O-rings
1 view (last 30 days)
Show older comments
Borhan Raad
on 20 Aug 2020
Commented: Borhan Raad
on 20 Aug 2020
Hi,
I'm trying to detect defects (notches and breaks) in rubber O-rings. Tried many command: "imopen", "adapthisteq", "bwmorph", etc...they work on some images, but not on all of them. You'll realise that some backgrounds are not 100% clear, the shadow and rubber pieces (in some) are considered part of the object sometimes. I tried "graythresh" to sepatrate the object from the background, nothing works....any idea? you assistance would be apprciated.
images attached....
Sincerely,
BR
0 Comments
Accepted Answer
Image Analyst
on 20 Aug 2020
Here is a more complete answer:
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 = 22;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
folder = pwd;
baseFileName = 'oring03.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
grayImage = imread(fullFileName);
% 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.
subplot(2, 3, 1);
imshow(grayImage, []);
title('Original Grayscale Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
hFig = gcf;
hFig.WindowState = 'maximized'; % May not work in earlier versions of MATLAB.
drawnow;
% Display histogram
subplot(2, 3, 2);
imhist(grayImage);
grid on;
title('Histogram of original gray image', 'FontSize', fontSize);
%--------------------------------------------------------------------------------------------------------
% SEGMENTATION OF IMAGE
threshold = 100;
outerMask = grayImage < threshold;
outerMask = imfill(outerMask, 'holes');
outerMask = bwareafilt(outerMask, 1);
% Display the image.
subplot(2, 3, 3);
imshow(outerMask, []);
title('Outer Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
% Measure area and solidity.
props = regionprops(outerMask, 'Area', 'Solidity', 'ConvexHull', 'EquivDiameter');
fprintf('Outer Area = %d pixels. Outer Solidity = %.5f\n', props.Area, props.Solidity);
% Fit the convex hull perimeter to a circle.
[xCenter, yCenter, R, a] = FitCircle(props.ConvexHull(:, 1), props.ConvexHull(:, 2));
% Plot that circle in the overlay
hold on;
theta = linspace(0, 2*pi, 2 * (rows + columns));
x = R * cos(theta) + xCenter;
y = R * sin(theta) + yCenter;
plot(x, y, 'r-', 'LineWidth', 2);
% Make a mask of the circle.
circleMask = poly2mask(x, y, rows, columns);
% Do an xor with the mask to see where it's different.
differing = xor(circleMask, outerMask);
% Display the image.
subplot(2, 3, 4);
imshow(differing, []);
title('Non-Circular Parts', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
% Now get the inner circle.
innerMask = (grayImage >= threshold) & outerMask;
innerMask = imfill(innerMask, 'holes');
innerMask = bwareafilt(innerMask, 1);
% Display the image.
subplot(2, 3, 5);
imshow(innerMask, []);
title('Inner Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
% Measure area and solidity.
props = regionprops(innerMask, 'Area', 'Solidity', 'ConvexHull', 'EquivDiameter');
fprintf('Inner Area = %d pixels. Inner Solidity = %.5f\n', props.Area, props.Solidity);
% Fit the convex hull perimeter to a circle.
[xCenter, yCenter, R, a] = FitCircle(props.ConvexHull(:, 1), props.ConvexHull(:, 2));
% Plot that circle in the overlay
hold on;
theta = linspace(0, 2*pi, 2 * (rows + columns));
x = R * cos(theta) + xCenter;
y = R * sin(theta) + yCenter;
plot(x, y, 'r-', 'LineWidth', 2);
% Make a mask of the circle.
circleMask = poly2mask(x, y, rows, columns);
% Do an xor with the mask to see where it's different.
differing = xor(circleMask, innerMask);
% Display the image.
subplot(2, 3, 6);
imshow(differing, []);
title('Non-Circular Parts', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
function [xCenter, yCenter, R, a] = FitCircle(x,y)
% FitCircle() : Fits a circle in x-y plane.
% Result is center point (xCenter, yCenter) and radius R.
% "a" is an optional output describing the circle's equation:%
% x^2+y^2+a(1)*x+a(2)*y+a(3)=0
% by Bucher izhak 25/oct/1991
n = length(x);
xx = x.*x;
yy = y.*y;
xy = x.*y;
A = [sum(x) sum(y) n;sum(xy) sum(yy) sum(y);sum(xx) sum(xy) sum(x)];
B = [-sum(xx+yy) ; -sum(xx.*y+yy.*y) ; -sum(xx.*x+xy.*y)];
a = A\B;
xCenter = -.5*a(1);
yCenter = -.5*a(2);
R = sqrt((a(1)^2+a(2)^2)/4-a(3));
end

3 Comments
Image Analyst
on 20 Aug 2020
If you want to ignore small parts that are basically noise in the parts that are non-circular, you can use bwareafilt() or bwareaopen() to extract blobs larger than a specified size only.
More Answers (1)
Image Analyst
on 20 Aug 2020
Edited: Image Analyst
on 20 Aug 2020
Doesn't look too hard. If it's not cut into a C shape, try this:
- Background correct, if needed
- Threshold to find dark ring: mask = grayImage < someValue.
- Fill holes with imfill(mask, 'holes')
- Call bwareafilt(mask, 1) to retain only the largest blob.
- Call regionprops(mask, 'Solidity') to get "Solidity". Should be 1 if no nicks or cuts in the outer boundary.
- Threshold to find light pixels.
- Call imclearborder to remove surround (outside ring) and leave just the inner disc.
- Repeat steps 3 - 5
It's just a little more complicated to do steps 6-8 if there is a cut so that the rubber is in a C shape, but I'm sure you'll be able to figure it out. Then you can subtract the mask from the convex hull of the mask to get the area of the blobs sticking out of or into the ring.
See Also
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!