MATLAB Answers

Write a function called blur that blurs the input image

2,585 views (last 30 days)
Namarta Kapil
Namarta Kapil on 19 Jul 2019
Commented: Walter Roberson on 4 Aug 2020 at 18:47
Write a function called blur that blurs the input image. The function is to be called like this:
output = blur(img,w);
where img, the input image is a two-dimensional matrix of grayscale pixel values between 0 and 255. Blurring is to be carried out by averaging the pixel values in the vicinity of every pixel. Specifically, the output pixel value is the mean of the pixels in a square submatrix of size 2w+1 where the given pixel sits in the center. For example, if w is 1, then we use a 3x3 matrix, that is, we average all the neighboring pixels of the given pixel and itself. Only use valid pixels when portions of the blurring matrix fall outside the image. For example, the blurred value corresponding to w = 1 at index (1,1) would be the mean of of elements (1,1), (1, 2), (2,1) and (2, 2). Both input img and output output are of type uint8.
You can download the test image here
Opens in new tab
to use in MATLAB.
I am using the following code but it gives me an error. Can anyone please tell me where I am going wrong?
function output = blur(img,w)
B=double(img);
[m,n] = size(B);
k=2*w+1;
for i = 1:m
for j = 1:n
p=i-fix(k/2);
q=i+fix(k/2);
r=j-fix(k/2);
s=j+fix(k/2);
if p<1
p=1;
end
if q>m
q=m;
end
if r<1
r=1;
end
if s>n
s=n;
end
A=B([p:q],[r:s]);
B(i,j)=mean(A(:));
end
end
output=uint8(B);
end

  6 Comments

Show 3 older comments
Julian Veran
Julian Veran on 19 May 2020
function out = blur(img,w)
% convert to double for doing calculations
imgD = double(img);
[row, col] = size(img);
out = zeros(row, col);
for ii = 1:row
for jj = 1:col
% Get the indices for a submatrix
r1 = ii-w;
r2 = ii+w;
c1 = jj-w;
c2 = jj+w;
% Test that indices are valid
% If not, set to min/max that is valid
if r1 < 1
r1 = 1;
end
if r2 > row
r2 = row;
end
if c1 < 1
c1 = 1;
end
if c2 > col
c2 = col;
end
% Get the submatrix and assign the mean to the output pixel
m = imgD(r1:r2, c1:c2);
out(ii,jj) = mean(m(:));
end
end
% convert back to uint8
out = uint8(out);
end

Sign in to comment.

Accepted Answer

Aditya Sawant
Aditya Sawant on 22 Jul 2019
Your program is correct. But you are overlapping resultant matrix with input matrix which is creating proble.
For e.g. you have calculated avg pixel for w=1 and for location(1,1) which will store at same matrix at location(1,1). But for (1,2) while avg surrounding cells it will consider (1,1) location of matrix B where on location(1,1) you saved your result/output value not input value.
So just create new output matrix like mentioned below. Hope it will help you.
function output = blur(img,w)
B=double(img);
[m,n] = size(B);
k=2*w+1;
for i = 1:m
for j = 1:n
p=i-fix(k/2);
q=i+fix(k/2);
r=j-fix(k/2);
s=j+fix(k/2);
if p<1
p=1;
end
if q>m
q=m;
end
if r<1
r=1;
end
if s>n
s=n;
end
A=B([p:q],[r:s]);
C(i,j)=mean(A(:));
end
end
output=uint8(C);
end

  6 Comments

Show 3 older comments
Walter Roberson
Walter Roberson on 4 Aug 2020 at 18:47
k is the total window size. fix(k/2) is the distance to the edge of the window from the center of the window.

Sign in to comment.

More Answers (7)

Vishal Lodha
Vishal Lodha on 8 May 2020
function out = blur(img,w)
% convert to double for doing calculations
imgD = double(img);
[row, col] = size(img);
out = zeros(row, col);
for ii = 1:row
for jj = 1:col
% Get the indices for a submatrix
r1 = ii-w;
r2 = ii+w;
c1 = jj-w;
c2 = jj+w;
% Test that indices are valid
% If not, set to min/max that is valid
if r1 < 1
r1 = 1;
end
if r2 > row
r2 = row;
end
if c1 < 1
c1 = 1;
end
if c2 > col
c2 = col;
end
% Get the submatrix and assign the mean to the output pixel
m = imgD(r1:r2, c1:c2);
out(ii,jj) = mean(m(:));
end
end
% convert back to uint8
out = uint8(out);
end
try this up

  2 Comments

Durgesh Singh
Durgesh Singh on 9 May 2020
  1. Can you explain me the question once for all. Please .Thanks for the effort in advance.
Walter Roberson
Walter Roberson on 9 May 2020
Do this for each distinct pixel in an image:
Think about a box that is 2*w+1 by 2*w+1 that is centered around the current pixel; for example if w is 2 then that would be a 5 x 5 box with two "before" and two "after" the current pixel, left/right and up/down. Take the average (mean) of those (2*w+1)^2 pixels, and that is the output for the current pixel.
In the case where the pixel is close to an edge, only count the pixels that are inside the box. For example when the current pixel is the location marked with * and w is 2, then include only the pixels marked with Y and * in the average, and not the ones marked with N.
Y*YYNNN
YYYYNNN
YYYYNNN
NNNNNNN

Sign in to comment.


Walter Roberson
Walter Roberson on 21 Jul 2019
A=B([p:q],[r:s]);
B(i,j)=mean(A(:));
You are overwriting B as you go. You should be storing into a different array than you are using as the source to calculate the values,

  3 Comments

Namarta Kapil
Namarta Kapil on 21 Jul 2019
Isn't that what I am supposed to do to blur the image? I want to blur the original image and if I understood the question right, then according to the question "Blurring is to be carried out by averaging the pixel values in the vicinity of every pixel. Specifically, the output pixel value is the mean of the pixels in a square submatrix of size 2w+1 where the given pixel sits in the center". I have tried a lot of changes in the code but it doesnt seem to work. The code does blur the picture but its still giving me an error for some reason. I feel like maybe I am missing a step or two but what I can't figure it out.
Walter Roberson
Walter Roberson on 21 Jul 2019
Consider the difference between,
"You have a line of holes. Visit each one starting from the second and dig it one foot deeper than the one to its left"
compared to
"You have a line of holes. Visit each one starting from the second and dig it one foot deeper than the depth that the one to its left started out as"
Specifically, the output pixel value is the mean of the pixels in a square submatrix of size 2w+1 where the given pixel sits in the center.
"square submatrix" is referring to the square submatrix of the input pixels, not a square submatrix that includes already-blurred pixels.

Sign in to comment.


Arafat Roney
Arafat Roney on 10 May 2020
Edited: Arafat Roney on 10 May 2020
help me finding out the error....this shows "The server timed out while running and assessing your solution.''
function output=blur(img,w)
s=(2*w)+1; %SUB-MATRIX MATRIX DIMENSION
img=double(img); %CONVERTED TO DOUBLE FOR CALCULATIONS
[p,q]=size(img); %SIZE CALCULATED
m=[]; %INITIALIZED TO EMPTY MATRIX FOR OUTPUT MATRIX CALCULATION
for ii=1:p %OUTPUT MATRIX ROR CONTROL
row=[]; %CALCULATES EVERY ROW OF THE OUTPUT
for jj=1:q %OUTPUT MATRIX COLUMN CONTROL
sub=[]; %SUB-MATRIX WHICH IS USED TO CALCULATE MEAN
for i=1:s
sub1=[]; %ALL THE ELEMENTS OF THE ROW ARE STORED IN EVERY STEP
for j=1:s
y=ii-w+i-1;
z=jj-w+j-1;
if (y<1||y>p||z<1||z>q) %IF INDEX IS NOT VALID THEN WE TAKE EMPTY MATRIX
a=[];
else
a=img(y,z); %IF INDEX IS VALID THEN WE TAKE VALUES FROM THE 'img' MATRIX
end
sub1=[sub1 a]; %ROW OF THE SUB-MATRIX
end
sub=[sub sub1]; %SUB-MATRIX
end
b=mean(sub); %MEAN CALCULATED
row=[row b]; %ROW CALCULATED FROM ALL THE LOOPS
end
m=[m; row]; %FINAL MATRIX
end
output=uint8(m); %FINAL MATRIX CONVERTED TO 'uint8'
end

  1 Comment

Walter Roberson
Walter Roberson on 10 May 2020
It is not efficient to grow an array in place.
You should pre-allocate sub1 as the maximum possible size, 1 x s, and keep track of how many items are actually used, like
sub1 = zeros(1,s);
sub1c = 0;
for j = 1 : s
y=ii-w+i-1;
z=jj-w+j-1;
if y >= 1 && y <= p && z >= 1 && z <= q
sub1c = sub1c + 1;
sub1(sub1c) = img(y,z);
end
end
sub1 = sub1(1:subs1c);
You can extend this to deal with all of the information you would put into sub, using only one array of length s*s, without having to extend anything in place.
But after that I would point out that you do not need to store all of those values: you can just keep a running total of them as you go, along with a counter of how many you have, and then afterwards the mean is just the running total divided by the counter.

Sign in to comment.


Prashant Dubey
Prashant Dubey on 10 May 2020
function out = blur(img,w)
% convert to double for doing calculations
imgD = double(img);
[row, col] = size(img);
out = zeros(row, col);
for ii = 1:row
for jj = 1:col
% Get the indices for a submatrix
r1 = ii-w;
r2 = ii+w;
c1 = jj-w;
c2 = jj+w;
% Test that indices are valid
% If not, set to min/max that is valid
if r1 < 1
r1 = 1;
end
if r2 > row
r2 = row;
end
if c1 < 1
c1 = 1;
end
if c2 > col
c2 = col;
end
% Get the submatrix and assign the mean to the output pixel
m = imgD(r1:r2, c1:c2);
out(ii,jj) = mean(m(:));
end
end
% convert back to uint8
out = uint8(out);
end

  8 Comments

Show 5 older comments
Dhanush B
Dhanush B on 21 May 2020
When I typed the code, it says Undefined function 'unit8' for input arguments of type 'double'.
Error in blur (line 26) output=unit8(output);
Randall Ang
Randall Ang on 10 Jun 2020
Sorry if this sounds like a stupid question, but may I know
1) why we cant obtain the image using double but only after converting it to uint8?
2) May I also ask, why is the second line (B=double(img)) required? As it seems that even when I omit it, the variable img will still become double after the for loops.
Walter Roberson
Walter Roberson on 10 Jun 2020
1) why we cant obtain the image using double but only after converting it to uint8?
MATLAB looks at the datatype of the image to determine which range of values are expected for the image.
If the datatype is uint8 then MATLAB will expect that 0 is lowest intensity and that 255 is full intensity and everything else is to be scaled between those two. There are no other numbers outside this range that are possible for uint8 datatype, so it does not need any rules about what it should do for data outside the range 0 to 255.
If the datatype is single or double, then MATLAB will expect that 0 is lowest intensity and that 1 is full intensity and that everything else in the range 0 to 1 is to be scaled between those two. Numbers that are less than 0 are, by default, treated as 0, and numbers greater than 1 are, by default, treated as 1.
Now, if you start with a uint8 value that was, for example, 243, and if it got blurred to (say) 240.19, then it is outside the range 0 to 1, so if you try to image() or imshow() the double values, nearly all of the image will be treated as maximum intensity, and you will end up with the image being nearly all black (the 0's) and white (everything that blurred to become 1 or higher in double precision.) That will not be useful.
When you convert the blurred values such as 240.19 to uint8, getting 240 uint8, then the datatype would be uint8 and we would be back to the rule about 0 is minimum, 255 is maximum, and 240 would be 0.9412 (240/255) of maximum intensity.
It is possible to get the display the double precision values that are in the range 0 to 255 (double precision) in a meaningful way:
imshow(TheArray, [0 255])
May I also ask, why is the second line (B=double(img)) required?
That appears to refer to Namarta Kapil's code, not to the code written by Prashant Dubey that you are replying to.
Suppose you have uint8([1 2 3 4]) and you ask for the mean. If you take (uint8(1)+uint8(2)+uint8(3)+uint8(4))/4 then that would be uint8(10)/4 . When you do division with a uint8 value, the result is as-if you did double() of the numerator and denominator, did the division, and did uint8() of the result -- so the result of uint8(10)/4 would be the same as uint8(double(uint8(10))/double(4)) which would be uint8(2.5) and uint8() rounds values in converting to integer so the result would be uint8(3) .
Now suppose you have uint8([1 2 3 4]) and you double() first, calculate the mean, and uint8() afterwards. Then that would be mean() of double([1 2 3 4]) which would be double(10)/double(4) which would be 2.5, and then after you would uint8(), getting the same uint8(3) discussed above.
But... it turns out that mean(uint8([1 2 3 4])) does not do uint8((uint8(1)+uint8(2)+uint8(3)+uint8(4))/4) -- it turns out that mean() does double() first and does not convert back to uint8. So the result of the mean(uint8([1 2 3 4])) would be 2.5. Which would get you the same uint8(3) if you uint8() the result afterwards.
What is the difference between these cases? Well, consider taking the mean of uint8([128 128 128 128]). If you do it by taking uint8(128)+uint8(128)+uint8(128)+uint8(128) then you get uint8(255) because addition of uint8 "saturates" at 255. Then uint8(255)/4 would be 64.. hardly what you would expect!
But as discussed, that is not what mean() does. mean() would take sum(double(uint8([128 128 128 128])))/4 which would get you double(128) as expected.
If mean() will get you the result you expect, then why bother to manually do the double() of the image values? The answer is that you do not need to for these particular operations, but when you do the conversion yourself, it becomes more obvious to the reader that you have taken into account the properties of integer images and are taking care to get right values. If you left the values as uint8 and relied upon the fact that mean() of uint8 will automatically convert to double, then the reader might think that you "got lucky" and might spend a bunch of time studying the rest of your code in case there are places you did not get as lucky.
For example, suppose you did not convert to uint8 and your code included img - mean(img(:)) . Then the mean() is calculated in double() and so the right hand side of the subtraction is double, but the left side would still be uint8 . The uint8() would be temporarily converted to double, the subtraction would be done, the values would automatically be converted to uint8 again... and the fact that uint8() of a negative number "saturates" to 0 would come into play. The effect would be like the places where img was less than mean(img(:)) would get set to 0, not to negative numbers. Whereas if you had converted to double() before hand, you would not have to worry about that until you were at the end of the entire algorithm and ready to convert back to uint8. The reader of your code who sees you convert to double knows they do not have to worry about problems like that; the reader of your code who sees you relying on the fact that mean() of uint8 values is processed as double, needs to be skeptical and examine the details of your code in case you accidentally mixed uint8 and double because you were not paying attention.

Sign in to comment.


Akhil Thomas
Akhil Thomas on 16 May 2020
function out = blur(img,w)
% convert to double for doing calculations
imgD = double(img);
[row, col] = size(img);
out = zeros(row, col);
for ii = 1:row for jj = 1:col
% Get the indices for a submatrix
r1 = ii-w;
r2 = ii+w;
c1 = jj-w;
c2 = jj+w;
% Test that indices are valid
% If not, set to min/max that is valid
if r1 < 1 r1 = 1;
end
if r2 > row
r2 = row;
end
if c1 < 1
c1 = 1;
end
if c2 > col
c2 = col;
end
% Get the submatrix and assign the mean to the output pixel
m = imgD(r1:r2, c1:c2);
out(ii,jj) = mean(m(:));
end
end
% convert back to uint8
out = uint8(out);
end

  1 Comment

Fam Kuong
Fam Kuong on 30 May 2020
function output=blur(img,w)
[row,colum]=size(img);
img=double(img);
output=zeros(row,colum);
for i=1:row
sub_row_left=max(1,i-w);
sub_row_right=min(row,i+w);
for j=1:colum
sub_colum_top=max(1,j-w);
sub_colum_bottom=min(colum,j+w);
B=img(sub_row_left:sub_row_right,sub_colum_top:sub_colum_bottom);
aver=uint8(mean(B(:)));
output(i,j)=aver;
end
end
output=uint8(output);
end

Sign in to comment.


Shiladittya Debnath
Shiladittya Debnath on 27 Jul 2020 at 8:03
Function :
function output = blur(img,w)
B=double(img);
[m,n] = size(B);
k=2*w+1;
for i = 1:m
for j = 1:n
p=i-fix(k/2);
q=i+fix(k/2);
r=j-fix(k/2);
s=j+fix(k/2);
if p<1
p=1;
end
if q>m
q=m;
end
if r<1
r=1;
end
if s>n
s=n;
end
A=B([p:q],[r:s]);
C(i,j)=mean(A(:));
end
end
output=uint8(C);
end

  0 Comments

Sign in to comment.


Shiladittya Debnath
Shiladittya Debnath on 27 Jul 2020 at 8:04
Code to CALL YOUR FUNCTION :
img = imread('vandy.png');
output = blur(img,2);
imshow(output);

  0 Comments

Sign in to comment.