Remove noise close to an object of a grayscale image - matlab

I have the image bellow that has a main object and around it there is some noise, like smoke, circled with the red line.
Is it possible to remove this noise keeping the main object intact as possible?
Can we do that without using a manual threshold, e.g., look here if that helps?
I would like to mention that the background does not correspond to zero values. So applying a threshold method and setting to zero the corresponding spots, based on the obtained mask, will destroy the smoothness of the background.
Best regards,
Thoth
EDIT: Just for the visualization purposes, I placed an output image (I just copy a background patch inside the circle.)

S.A.
Yes you can simply accomplish your task using some morphological operations such as
Opening
Closing
Dilation
Erosion
and here is a simple code that may help you :
%After input image 'img' is read:
structuredElement1 = strel('disk',5);
structuredElement2 = strel('disk',3);
imageAfterErosion = imerode(img,structuredElement2);
imageAfterClosing = imclose(imageAfterErosion,structuredElement1);
imageAfterDilation = imdilate(imageAfterClosing,structuredElement1);
imageAfterDilation = imdilate(imageAfterDilation,structuredElement1);
imageAfterClosing = imclose(imageAfterDilation,structuredElement1);
binaryImage = imfill(imageAfterClosing, 'holes');
imshow(binaryImage);

Related

Subtract background in image with Matlab

I have a list of images that i expect to have uneven illumination across the x axis only. The background estimation/model will be calculated in advance but only its shape will be given (so i will not have an empty background image that i can just subtract), I will just have the form/shape of it (for example linear).
Is there a way to subtract the background and get an even illumination of the image with just knowing its shape (and without having an actual background image)? I have attached an image from the Matlab library that was created using a linear background (background=-3*x+0.5). Can someone show me how to go from this example to the original image with just using the background shape?
I am also including the original image.
If you have the shape, and the conditions you state are correct, then you have the full background information. It is, however, not possible to undo the clipping that happened (where the image has values 255, you don't know what the original value was).
This is how you would create a background image given the shape:
img = imread('https://i.stack.imgur.com/0j2Gi.jpg');
img = img(27:284,91:370); % OP posted a screen shot? What is this margin?
x = 0:size(img,2)-1;
background = 0.3*x+0.5;
background = repmat(background,size(img,1),1);
imshow(img-background)
The results looks not exactly like the original image, but most of that can be explained by the clipping.
I replaced your -3*x+0.5 with 0.3*x+0.5 because the -3 makes no sense, and 0.3 makes it so that the background values remain in a meaningful range.
If, on the other hand, you are asking about fitting the linear model to the image data and estimating the exact background to subtract, then the problem is a bit more difficult, but not impossible. You can, for example, make an assumption about intensity uniformity across the x-axis if the illumination had been uniform across the image. You can then take the mean intensity along the x-axis and fit your model to it:
meanintensity = mean(img,1)';
plot(m)
X = [ones(length(meanintensity),1),(0:length(meanintensity)-1)']; % meanintensity = X*params
params = X\meanintensity;
hold on, plot(X*params)
background = X*params;
background = repmat(background',size(img,1),1);
imshow(img-background)

Filling the gaps in a binary image

I have found a couple areas referring to filling of gaps in binary images in matlab, however I am still struggling. I have written the following code but I cannot get it to work. Here is my binary image:
.
However, what I'm trying to achieve is the following
.
Does anyone know how to do this? I have been trying using imfill but I know I think I need to define boundaries also with the bwlabel function but I dont know how. Any help would be greatly appreciated.
%%Blade_Image_Processing
clc;
clear;
%%Video file information
obj = VideoReader('T9_720p;60p_60mm_f4.MOV');
% Sampling rate - Frames per second
fps = get(obj, 'FrameRate');
dt = 1/fps;
% ----- find image info -----
file_info = get(obj);
image_width = file_info.Width;
image_height = file_info.Height;
% Desired image size
x_range = 1:image_height;
y_range = 1:image_width;
szx = length(x_range);
szy = length(y_range);
%%Get grayscale image
grayscaleimg1 = rgb2gray(read(obj,36));
grayscaleimg = imadjust(grayscaleimg1);
diff_im = medfilt2(grayscaleimg, [3 3]);
t1=60;
t2=170;
range=(diff_im > t1 & diff_im <= t2);
diff_im (range)=255;
diff_im (~range)=0;
% Remove all those pixels less than 300px
diff_im = bwareaopen(diff_im,2000);
%imshow(diff_im)
%imhist(grayscaleimg)
%Fill gaps in binary image
BW2 = imfill(diff_im,'holes');
There are two main problems: desired object has no readily usable distinguishing features, and it touches other object. Second problem could be perhaps cleared with morphological opening/closing (touching object is thin, desired object not, is this always the case?), but first problem remains. If your object touched edge but others didn't or vice versa, you could do something with imfill and subtractions. As it is now, MAYBE something like this would work:
With opening/closing remove connection, so your object is disjoint.
With imfill, remove what is left of this thin horizontal thing.
Then, you can bwlabel and remove everything that touches sides or bottom of the image - in shown case that would leave only your object.
Exact solution depends heavily on what additional constrains are there for your pictures. I believe it is not a one-shot, rather you have more of those pictures and want to correctly find objects on all? You have to check what holds for all pictures, such as if object always touches only something thin or if it always touches only upper edge etc.

counting the number of objects on image with MatLab

I need to count the number of chalks on image with MatLab. I tried to convert my image to grayscale image and than allocate borders. Also I tried to convert my image to binary image and do different morphological operations with it, but I didn't get desired result. May be I did something wrong. Please help me!
My image:
You can use the fact that chalk is colorful and the separators are gray. Use rgb2hsv to convert the image to HSV color space, and take the saturation component. Threshold that, and then try using morphology to separate the chalk pieces.
This is also not a full solution, but hopefully it can provide a starting point for you or someone else.
Like Dima I noticed the chalk is brightly colored while the dividers are almost gray. I thought you could try and isolate gray pixels (where a gray pixel says red=blue=green) and go from there. I tried applying filters and doing morphological operations but couldn't find something satisfactory. still, I hope this helps
mim = imread('http://i.stack.imgur.com/RWBDS.jpg');
%we average all 3 color channels (note this isn't exactly equivalent to
%rgb2gray)
grayscale = uint8(mean(mim,3));
%now we say if all channels (r,g,b) are within some threshold of one another
%(there's probabaly a better way to do this)
my_gray_thresh=25;
graymask = (abs(mim(:,:,1) - grayscale) < my_gray_thresh)...
& (abs(mim(:,:,2) - grayscale) < my_gray_thresh)...
& (abs(mim(:,:,3) - grayscale) < my_gray_thresh);
figure(1)
imshow(graymask);
Ok so I spent a little time working on this- but unfortunately I'm out of time today and I apologize for the incomplete answer, but maybe this will get you started- (if you need more help, I'll edit this post over the weekend to give you a more complete answer :))
Here's the code-
for i=1:3
I = RWBDS(:,:,i);
se = strel('rectangle', [265,50]);
Io = imopen(I, se);
Ie = imerode(I, se);
Iobr = imreconstruct(Ie, I);
Iobrd = imdilate(Iobr, se);
Iobrcbr = imreconstruct(imcomplement(Iobrd), imcomplement(Iobr));
Iobrcbr = imcomplement(Iobrcbr);
Iobrcbrm = imregionalmax(Iobrcbr);
se2 = strel('rectangle', [150,50]);
Io2 = imerode(Iobrcbrm, se2);
Ie2 = imdilate(Io2, se2);
fgm{i} = Ie2;
end
fgm_final = fgm{1}+fgm{2}+fgm{3};
figure, imagesc(fgm_final);
It does still pick up the edges on the side of the image, but from here you're going to use connected bwconnectedcomponents, and you'll get the lengths of the major and minor axes, and by looking at the ratios of the objects it will get rid those.
Anyways good luck!
EDIT:
I played with the code a tiny bit more, and updated the code above with the new results. In cases when I was able to get rid of the side "noise" it also got rid of the side chalks. I figured I'd just leave both in.
What I did: In most cases a conversion to HSV color space is the way to go, but as shown by #rayryeng this is not the way to go here. Hue works really well when there is one type of color- if for example all chalks were red. (Logically you would think that going with the color channel would be better though, but this is no the case.) In this case, however, the only thing all chalks have in common is the relative shape. My solution basically used this concept by setting the structuring element se to something of the basic shape and ratio of the chalk and performing morphological operations- as you originally guessed was the way to go.
For more details, I suggest you read matlab's documentation on these specific functions.
And I'll let you figure out how to get the last chalk based on what I've given you :)

remove some top, down rows and right, and left some columns of jpg image border using matlab

I have RGB museum JPG Images. most of them have image footnotes on one or more sides, and I'd like to remove them. I do that manually using paint software. now I applied the following matlab code to remove the image footnotes automatically. I get a good result for some images but for others it not remove any border. Please, can any one help me by update this code to apply it for all images?
'rgbIm = im2double(imread('A3.JPG'));
hsv=rgb2hsv(rgbIm);
m = hsv(:,:,2);
foreground = m > 0.06; % value of background
foreground = bwareaopen(foreground, 1000); % or whatever.
labeledImage = bwlabel(foreground);
measurements = regionprops(labeledImage, 'BoundingBox');
ww = measurements.BoundingBox;
croppedImage = imcrop(rgbImage, ww);'
In order to remove the boundaries you could use "imclearborder", where it checks for labelled components at boundaries and clears them. Caution! if the ROI touches the boundary, it may remove. To avoid such instance you can use "imerode" with desired "strel" -( a line or disc) before clearing the borders. The accuracy or generalizing the method to work for all images depends entirely on "threshold" which separates the foreground and background.
More generic method could be - try to extract the properties of footnotes. For instance, If they are just some texts, you can easily remove them by using a edge detection and morphology opening with line structuring element along the cols. (basic property for text detection)
Hope it helps.
I could give you a clear idea or method if you upload the image.

How can I replace the border with white color in Matlab?

This is the original image.
I changed it into 1) grayscale and apply 2) threshold.
As seen in the original image, there are some shadow that still exist after apply two method above.
But most of the image are perfect after 2 method.
I need to extract the text, so I need to get rid of the noise. I almost finish the work but the problem is some cases have a black border and I wanted to replace that into white color.
And I insist that I want just only border to turn into white
I think of create some white rectangle and fill the border with those rectangle but I don't know how to do it.
How can I achieve that using Matlab?
Any other method would be appreciate too!
If you can be sure only the borders will be black, why not simply crop the image until all isolated shapes are recognizable characters? Something along the lines of
done = false;
ii = 1;
while (~done)
% fill the outer border
img(:,ii) = 255; img(ii,:) = 255;
img(:,end-ii+1) = 255; img(end-ii+1,:) = 255;
% (run your algorithms here. It positive match, done = true)
end
That could be computationally intensive, since you have to do pattern recognition on each iteration, but you indicated it only occurs in "some cases".
Otherwise, I suspect some morphological operation can also be used, probably erosion or thinning or similar. But that has the drawback of altering the characters you want to match. But, if all images you have to process look like the one you show, I hardly suspect that'll give you any problems.
Some ways to detecting straight lines are mentioned in this question. I'd say you could detect all lines, and remove those (with a small tolerance around it) that are perfectly horizontal/vertical and on one of the edges.