Why my binary image dilation function doesn't work properly? - matlab

I'm having a kind of trouble since I'm new the concept Image Analysis and the tool Matlab.
What I have in my mind does not work well as lines of codes.
I'm trying to dilation function for binary images. It has to widen the given binary images.
This is my main page:
I = imread('logo_XXXX.png');
binaryImage = im2bw(I, 0.4);
s = ones(3,3,'int8');
i = dilate(binaryImage,s);
figure, imshow(i);
This is dilate.m function:
function [i] = dilate(I,s)
[Irows,Icols] = size(I);
i=I;
Itemp = I;
for row=1:Irows
for col=1:Icols
x = intersectAt(Itemp,s,row,col);
if x == 1
i(row,col)=1;
else
i(row,col)=0;
end
end
end
And this is istersectAt.m function:
function [i] = intersectAt(I,s,row,col)
[Srows,Scols] = size(s);
[Irows,Icols] = size(I);
i=0;
rowx = row - int8(Srows/2);
colx = col - int8(Scols/2);
for r=1:Srows
for c=1:Scols
if rowx+r <= 0 || rowx+r > Irows || colx+c <= 0 || colx+c > Icols
continue;
elseif I(rowx+r,colx+c) == 1 && s(r,c)==1
i = 1;
end
end
end
These codes must be widen this image:
however, in some point it doesn't work properly s.t:
If you help me fix my code I would be appriciated. If you want to know about dilation you can follow this url: http://www.mathworks.com/help/toolbox/images/f18-12508.html
Matlab has this function in its library but i need to implement my own function.

You should avoid loops as much as possible in matlab.
If you need to write your own function just do:
s=ones(3);
i=(conv2(double(binaryImage),s,'same')>0)
From your example:
I can obtain:

I will give a hint then. Ask yourself what int8() exactly does for a number larger then 127. Incidentally the column index number after which your algorithm start behaving weird.
Edit to clarify
If you subtract a int8 type number from another one, a double in this case, Matlab will automatically cast to int8. For example:
test = double(140) - int8(3)
Gives a 127.

I assume imdilate is implemented with conv2, but your code would be more readable if you used this:
b = imdilate(bwImage,ones(3));

Related

Average filter Matlab

I have written the 3x3 average filter. It works fine but it shows the same output image three times instead of one. How to resolve the problem?
The code is
function [filtr_image] = avgFilter(noisy_image)
[x,y] = size(noisy_image);
filtr_image = zeros(x,y);
for i = 2:x-1
for j =2:y-1
sum = 0;
for k = i-1:i+1
for l = j-1:j+1
sum = sum+noisy_image(k,l);
end
end
filtr_image(i,j) = sum/9.0;
filtr_image = uint8(filtr_image);
end
end
end
thanks in advance
What is most likely happening is the fact that you are supplying a colour image when the code is specifically meant for grayscale. The reason why you see "three" is because when you do this to allocate your output filtered image:
[x,y] = size(noisy_image)
If you have a 3D matrix, the number of columns reported by size will be y = size(noisy_image,2)*size(noisy_image,3);. As such, when you are iterating through each pixel in your image, in column major order each plane would be placed side by side each other. What you should do is either convert your image into grayscale from RGB or filter each plane separately.
Also, you have an unnecessary casting performed in the loop. Just do it once outside of the loop.
Option #1 - Filter per plane
function [filtr_image] = avgFilter(noisy_image)
[x,y,z] = size(noisy_image);
filtr_image = zeros(x,y,z,'uint8');
for a = 1 : z
for i = 2:x-1
for j =2:y-1
sum = 0;
for k = i-1:i+1
for l = j-1:j+1
sum = sum+noisy_image(k,l,a);
end
end
filtr_image(i,j,a) = sum/9.0;
end
end
end
end
Then you'd call it by:
filtr_image = avgFilter(noisy_image);
Option #2 - Convert to grayscale
filtr_image = avgFilter(rgb2gray(noisy_image));
Minor Note
You are using sum as a variable. sum is an actual function in MATLAB and you would be overshadowing this function with your variable. This will have unintended consequences if you have other functions that rely on sum later down the line.
I can't see why your code would repeat the image (unless it's a pattern cause by an integer overflow :/ ) but here are some suggestions:
if you want to use loops, at least drop the inner loops:
[x,y] = size(noisy_image);
filtr_image = zeros(x,y);
for i = 2:x-1
for j =2:y-1
% // you could do this in 1 line if you use mean2(...) instead
sub = noisy_image(i-1:i+1, j-1:j+1);
filtr_image = uint8(mean(sub(:)));
end
end
However do you know about convolution? Matlab has a built in function for this:
filter = ones(3)/9;
filtr_image = uint8(conv2(noisy_image, filter, 'same'));

Matlab get vector of specific pixels

I am pretty new to Matlab and encountered a problem when working with images.
I want to get a pixel that is in a specific colour (blue) in the following image:
image
My current code looks something like this:
function p = mark(image)
%// display image I in figure
imshow(image);
%// first detect all blue values higher 60
high_blue = find(image(:,:,3)>60);
%cross elements is needed as an array later on, have to initialize it with 0
cross_elements = 0;
%// in this iteration the marked values are reduced to the ones
%where the statement R+G < B+70 applies
for i = 1:length(high_blue)
%// my image has the size 1024*768, so to access the red/green/blue values
%// i have to call the i-th, i+1024*768-th or i+1024*768*2-th position of the "array"
if ((image(high_blue(i))+image(high_blue(i)+768*1024))<...
image(high_blue(i)+2*768*1024)+70)
%add it to the array
cross_elements(end+1) = high_blue(i);
end
end
%// delete the zero element, it was only needed as a filler
cross_elements = cross_elements(cross_elements~=0);
high_vector = zeros(length(cross_elements),2);
for i = 1:length(cross_elements)
high_vector(i,1) = ceil(cross_elements(i)/768);
high_vector(i,2) = mod(cross_elements(i), 768);
end
black = zeros(768 ,1024);
for i = 1:length(high_vector)
black(high_vector(i,2), high_vector(i,1)) = 1;
end
cc = bwconncomp(black);
a = regionprops(cc, 'Centroid');
p = cat(1, a.Centroid);
%// considering the detection of the crosses:
%// RGB with B>100, R+G < 100 for B<150
%// consider detection in HSV?
%// close the figure
%// find(I(:,:,3)>150)
close;
end
but it is not optimized for Matlab, obviously.
So i was wondering if there was a way to search for pixels with specific values,
where the blue value is larger than 60 (not hard with the find command,
but at the same time the values in the red and green area not too high.
Is there a command I am missing?
Since English isn't my native language, it might even help if you gave me some suitable keywords for googling ;)
Thanks in advance
Based on your question at the end of the code, you could get what you want in a single line:
NewImage = OldImage(:,:,1) < SomeValue & OldImage(:,:,2) < SomeValue & OldImage(:,:,3) > 60;
imshow(NewImage);
for example, where as you see you provide a restriction for each channel using logical operators, that you can customize of course (eg. using | as logical OR). Is this what you are looking for? According to your code you seem to be looking for specific regions in the image like crosses or coins is that the case? Please provide more details if the code I gave you is completely off the track :)
Simple example:
A = imread('peppers.png');
B = A(:,:,3)>60 & A(:,:,2)<150 & A(:,:,1) < 100;
figure;
subplot(1,2,1);
imshow(A);
subplot(1,2,2)
imshow(B);
Giving this:

Matlab imfilter function implemenation

I am trying to write a function that implements imfilter function. but getting this error.
??? Subscript indices must either be real positive integers or logicals
at this point
s= size(img);
Find below the code snippet
s = size(img);
Ix = zeros(s);
Iy = zeros(s);
for i = 1:s
for j = 1:s
temp = img(i-1:i+1,j-1:j+1) .* Gx;
Ix(i,j) = sum(temp(:));
end
end
Please is there anything Im doing wrong?
EDITED CODE
s = size(img);
Ix = zeros(s);
Iy = zeros(s);
for i = 2:s(1)-1
for j = 2:s(2)-1
temp = img(i-1:i+1,j-1:j+1) .* Gx;
Ix(i,j) = sum(temp(:));
end
end
If it genuinely happens at the point of calling s= size(img);, then you probably have a variable size in your workspace which is shadowing the size function.
In addition, there are a couple of possible issues with your loop. First, you can't use zero as in index in MATLAB. Hence, when you have i = 1, j = 1 at the start of your loop, you would expect the temp line to return the Subscript indices error.
the output of size, presuming img is a greyscale image, is going to be two numbers. When you do i = 1:s, it will ignore the second one. This is fine so long as your image is square but will not do what you expect if it isn't.
Finally, have a look at conv2 for cases like this rather than creating a loop.

Matlab working with Matrices / images to reset a certain pixel(3 dims)

I am trying to decide, for a single frame, whether I want to add it to the frame or not..
(Implementing background subtraction)..
How do I do it in a fast way? ( I did it with looping and it's working realll slow...)
This is what I have: (seq is input, diff is the image I am testing against, and F is the new image)
for y = 1:height
for x = 1:width
res = 0;
for c = 1:channels
if diff(y,x,c) > thresh
res = 1;
end
end
if res == 1
F(y,x, :) = seq(y,x,:);
else
F(y,x, :) = 0;
end
end
end
Thanks !!
Your question is missing some definition for the filter, but apart from this I can provide a basic template for image masking:
img=imread(...) %some input image
mask = sum( img>threshold , 3) >0
%now the tricky part, we have a nxmx3 image and a nxm mask to filter:
img2=bsxfun(#times,img,mask);
You may modify the bsxfun-line, but using a binary matrix to indicate which image to select is the most common method. Thus adapt the mask to your requirements.

Value used in comparison not returned, why?

In matlab, I have this .mat file. If you look inside and double click the cells with vlues 1.000, you will find that the value that appears is 0.999999999259113 . That's fine. But, when I use for instance the following command:
>> sel = find (u2 == 0.999999999259113 );
The answer I get is as follows:
>> sel
sel =
5
We have more than one 0.999999999259113 value. Don't we? Where are they? What is 5 supposed to be?
Now, when I come to the following function since the .mat file is related to this image:
function s = pixel(x, y)
pixels = [];
index = 1;
for i=1:length(y)
for j=1:length(y)
if y(i,j) == 0.999999999259113;
pixels(index) = x(i,j);
index = index+1;
end
end
end
pixels
end
And, when I run the function I get the following (I: image, u2: the .mat file):
pixel(I,u2);
pixels =
[]
Empty?! What is this supposed to mean?
Any ideas why I'm not getting the expected results, although the commands seem logically working?
Thanks.
Instead of checking for exact floating point equality, can you set a tolerance? Find values close to 1.0 like this:
tolerance = 0.01;
sel = find(abs(u2 - 1.0) < tolerance);
Try using
if abs(y(i,j)-)<1e-6
instead of
if y(i,j) == 0.999999999259113;