How do I automatically remove white spots in an image?

51 views (last 30 days)
Luke G.
Luke G. on 1 Nov 2021
Edited: yanqi liu on 2 Nov 2021
I'm trying to write some code to automatically remove white spots from the image below:
I've figured out a way to manually do it (see code at bottom of post, Approach 1) where the user has to draw a rectangle around each spot, but this is slow & non-ideal. The right image below has one spot removed from left of center.
Ideally, I would like to use some sort of thresholding to identify the locations of the bright spots (see code at bottom of post, Approach 2), and then use region fill to smooth out those spots. My current application of this (see below) doesn't produce a smooth result. It seems to only darken the spots a little bit. Maybe I need to draw rectangles around the location of each bright spot? Any help is greatly appreciated.
The code:
clc, clear all, close all
% load the image:
folder = pwd;
fileName = uigetfile('*.png','Multiselect','off');
fullName = fullfile(folder,fileName);
imgCropped = imread(fullName);
figure; imshow(imgCropped,'InitialMagnification',300);
% Approach 1 - Hand-picked:
figure
imshow(imgCropped,'InitialMagnification',300);
title('Select a spot:','FontSize',fontSize);
spotROI = drawrectangle('Color',[1 1 0]);
rectPosition = spotROI.Position;
r_w = rectPosition(3);
r_h = rectPosition(4);
x = ones(1,4);
y = ones(1,4);
x(1) = rectPosition(1);
x(2) = rectPosition(1)+r_w;
x(3) = rectPosition(1)+r_w;
x(4) = rectPosition(1);
y(1) = rectPosition(2);
y(2) = rectPosition(2);
y(3) = rectPosition(2)+r_h;
y(4) = rectPosition(2)+r_h;
L = regionfill(imgCropped,x,y);
figure; imshowpair(imgCropped,L,'montage');
title('Original vs. Hand-picked ''Region-fill''')
% Approach 2 - Automated:
figure
level = 0.8;
BW = imbinarize(imgCropped,level);
mask = bwareaopen(BW, 40);
J = regionfill(imgCropped,mask); % use BW as a mask
figure; imshowpair(imgCropped,J,'montage');
title('Original vs. ''Region-filled'' Image')

Accepted Answer

Image Analyst
Image Analyst on 2 Nov 2021
You can follow these steps. The regionfill() function will give you a more natural and continuous output image than replacing the white spots with the mean of the image.
  1. Threshold the image with a locally adaptive threshold to find the white spots.
  2. Enlarge the spots a bit so we can get a representative surrounding gray level outline.
  3. Use regionfill() to smear in those surrounding gray levels.
% Demo by Image Analyst
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;
markerSize = 40;
%--------------------------------------------------------------------------------------------------------
% READ IN IMAGE
fileName = 'white spots.png';
grayImage = imread(fileName);
% 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.
% Extract the red channel (so the magenta lines will be white).
grayImage = grayImage(:, :, 1);
end
%--------------------------------------------------------------------------------------------------------
% Display the image.
subplot(2, 2, 1);
imshow(grayImage);
impixelinfo;
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;
% Maximize window.
g = gcf;
g.WindowState = 'maximized'
drawnow;
%--------------------------------------------------------------------------------------------------------
% Get a mask using locally adaptive thresholding.
mask = imbinarize(grayImage, 'adaptive');
% Dilate it a bit to make the spots bigger.
mask = imdilate(mask, true(5));
% Display the image.
subplot(2, 2, 2);
imshow(mask, []);
impixelinfo;
axis('on', 'image');
title('Mask/Binary/Logical Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;
%--------------------------------------------------------------------------------------------------------
% Repair the image by using regionfill()
% to smear in the surrounding pixels values into the white spots.
repairedImage = regionfill(grayImage, mask);
% Display the image.
subplot(2, 2, 3);
imshow(repairedImage);
impixelinfo;
axis('on', 'image');
title('Repaired Image', 'FontSize', fontSize, 'Interpreter', 'None');
hold on
drawnow;
  2 Comments
Image Analyst
Image Analyst on 2 Nov 2021
Luke, you're welcome. Thanks for accepting. Another function I tried first before imbinarize was imtophat - a "top hat filter". It didn't seem to do as well but you may want to learn about it anyway. That and imbothat()'s claim to fame is to find spots on varying backgrounds by doing a morphological opening or closing (to get a background without the spots) and then subtracting that from the original image to get the spots alone without the background in there. You can then threshold that to get a mask. Like I said, it didn't seem to perform as well as imbinarize().

Sign in to comment.

More Answers (1)

yanqi liu
yanqi liu on 2 Nov 2021
Edited: yanqi liu on 2 Nov 2021
clc; clear all; close all;
im = imread('https://www.mathworks.com/matlabcentral/answers/uploaded_files/786560/image.png');
figure; imshow(im);
bw = imbinarize(im,'adaptive','ForegroundPolarity','dark','Sensitivity',0.7);
jm = regionfill(im, bw);;
figure; imshow(bw);
figure; imshow(jm);

Community Treasure Hunt

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

Start Hunting!