Introduction to MATLAB programming - image blur problem

Hello all,
I am trying to work through one of the problems for the 'introduction to matlab programming' course by coursera, known as the 'image blur' problem (lesson 8 - final problems, week 9). The system keeps telling me that my values are incorrect, but I am struggling to understand why? I have attached my code below. I would be very grateful if anyone could give me a helping hand.
%The code to call the function:
img = imread('vandy.png')
output = blur(img,2) % I have specified the function 'blur' below
imshow(output);
% The function:
function[output] = blur(img,w)
here = 2*w + 1;
change = w;
%setting an epmpty matrix
emptymatrix = zeros(length(img(:,1)),length(img(1,:)));
%working out the output pixel value for each corner
added = img((1):(1+change),(1):(1+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(1,1) = answer;
i = length(img(:,1));
z = 1;
added = img((i-change):(i),(z):(z+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
i = 1;
z = length(img(1,:));
added = img((i):(i+change),(z-change):(z));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
i = length(img(:,1));
z = length(img(1,:));
added = img((i-change):(i),(z-change):(z));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
% working out the pixel values for the inner square
for i = 1:length(img(:,1))
for z = 1:length(img(1,:))
if ((i + change) <= length(img(:,1))) && ((i-change) > 0) && ((z+change) <= length(img(1,:))) && ((z-change) > 0)
added = img((i-change):(i+change),(z-change):(z+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/(here*here);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
end
end
end
% working out the output pixel values for the outer rows and columns (excluding the corners)
for i = 2:(length(img(:,1))-1)
if (i-change) > 0 && (i+change) < length(img(:,1))
z = 1;
added = img((i-change):(i+change),(z):(z+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
end
end
for i = 2:(length(img(:,1))-1)
if (i-change) > 0 && (i+change) < length(img(:,1))
z = length(img(1,:));
added = img((i-change):(i+change),(z-change):(z));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
end
end
for i = 2:(length(img(1,:))-1)
if (i-change) > 0 && (i+change) < length(img(1,:))
z = 1;
added = img((z):(z+change),(i-change):(i+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(z,i) = answer;
output = uint8(emptymatrix);
end
end
for i = 2:(length(img(1,:))-1)
if (i-change) > 0 && (i+change) < length(img(1,:))
z = length(img(:,1));
added = img((z-change):(z),(i-change):(i+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(z,i) = answer;
output = uint8(emptymatrix);
end
end
end

5 Comments

ey21 - which values are considered to be incorrect? The output? The above is a lot of code to go through without knowing why it does what it does. I did try it with a jpeg and noticed that my input 260x396x3 image became a 260x1188 output image (where 1188=3*396). Are you assuming that your image inputs are 2D grayscale only? Is that true for the vandy.png that you are testing with? Or does the code need to be able to handle colour input images?
@Geoff Hayes, yes the output:
Variable output has an incorrect value. Tested with a 5x5 uint8 matrix with all 255-s in the first and last rows and columns and zeros everywhere else and w = 1
Is the message I am recieving...
Variable output has an incorrect value. Tested with the vandy.png file and w = 1
Then there is probably something wrong with your algorithm. Can you add some comments to describe what the code is doing?
@Geoff Hayes
I have attached a screenshot below for what the code is supposed to be doing.
This code here is working out the averaged pixel value for each of the corners of the n-by-n matrix:
%working out the output pixel value for each corner
added = img((1):(1+change),(1):(1+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(1,1) = answer;
i = length(img(:,1));
z = 1;
added = img((i-change):(i),(z):(z+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
i = 1;
z = length(img(1,:));
added = img((i):(i+change),(z-change):(z));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
i = length(img(:,1));
z = length(img(1,:));
added = img((i-change):(i),(z-change):(z));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
This code below works out the average pixel values for the indices (pixels) in the centre of the matrix. If the matrix is a 5-by-5 by matrix, the inner 3-by-3 square of pixel values would be calculated using the formula below:
% working out the pixel values for the inner square
for i = 1:length(img(:,1))
for z = 1:length(img(1,:))
if ((i + change) <= length(img(:,1))) && ((i-change) > 0) && ((z+change) <= length(img(1,:))) && ((z-change) > 0)
added = img((i-change):(i+change),(z-change):(z+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/(here*here);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
end
end
end
The code below is trying to work out the average value for each pixel on the outer edges of the matrix. For example, if the matrix is a 5-by-5 matrix, the code below would work out the average value for each pixel (indice) in the first and last column and row of the matrix, excluding the values of the four corners (as these have already been calculated above).
for i = 2:(length(img(:,1))-1)
if (i-change) > 0 && (i+change) < length(img(:,1))
z = 1;
added = img((i-change):(i+change),(z):(z+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
end
end
for i = 2:(length(img(:,1))-1)
if (i-change) > 0 && (i+change) < length(img(:,1))
z = length(img(1,:));
added = img((i-change):(i+change),(z-change):(z));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(i,z) = answer;
output = uint8(emptymatrix);
end
end
for i = 2:(length(img(1,:))-1)
if (i-change) > 0 && (i+change) < length(img(1,:))
z = 1;
added = img((z):(z+change),(i-change):(i+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(z,i) = answer;
output = uint8(emptymatrix);
end
end
for i = 2:(length(img(1,:))-1)
if (i-change) > 0 && (i+change) < length(img(1,:))
z = length(img(:,1));
added = img((z-change):(z),(i-change):(i+change));
addition = sum(added);
additionally = sum(addition);
mean = additionally/numel(added);
answer = uint8(mean);
emptymatrix(z,i) = answer;
output = uint8(emptymatrix);
end
end
end
Can you use imfilter() or conv2()? It would be a lot shorter.

Sign in to comment.

 Accepted Answer

ey21 - I think that you need to simplify your code. For the block that is concerned with the inner rows and columns, I've reduced it to
for i = 1:length(img(:,1))
for z = 1:length(img(1,:))
if ((i + w) <= length(img(:,1))) && ((i-w) > 0) && ((z+w) <= length(img(1,:))) && ((z-w) > 0)
submatrix = img((i-w):(i+w),(z-w):(z+w));
output(z,i) = uint8(sum(submatrix(:))/numel(submatrix));
end
end
end
There is only one sum since submatris(:) will return a column of all elements in the submatrix, and then we can just sum those elements. numel is used to return the number of elements in the submatrix so that we can do the appropriate average. I've eliminated the emptymatrix since it is redundant. (I've replaced the change with w since they are identical.)
You still have two other blocks of code, so can all of this be simplified further? I think so...so long as you choose the correct submatrix for each element in the input matrix. In fact, I think that you can do all of this work in one loop regardless as to the pixel if you choose the correct minimum and maximum row and column to create the submatrix from. The example in your assignment tells you what to do if your code is considering the pixel at (1,1) so you could use that information to determine what to do.Your code to get the submatrix of an inner pixel is
submatrix = img((i-w):(i+w),(z-w):(z+w));
because you know that i-w is valid, i+w is valid, z-w is valid, and z+w is valid. This could be made more general if you do
minValidRowIndex = max(1,i-w);
maxValidRowIndex = min(numRows,i+w);
minValidColIndex = max(1,z-w);
maxValidColIndex = min(numCols,z-w);
The above four variables can now be used to get your submatrix for any (I think) pixel. We use max and min to ensure that we never use row or column indices that are outside of the matrix.

2 Comments

@geoff hayes,
the code below seems to be more successful but not perfect yet...
function[output] = blur(img,w)
here = 2*w + 1;
change = w;
emptymatrix = zeros(length(img(:,1)),length(img(1,:)));
for z = 1:length(img(1,:))
for i = 1:length(img(:,1))
if (i + change) <= length(img(:,1)) && (i - change) >= 1 && (z + change) <= length(img(1,:)) && (z - change) >= 1
submatrix = img((i-change):(i+change),(z-change):(z+change));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif i == 1 && z == 1
submatrix = img((i):(i+change),(z):(z+change));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif i == length(img(:,1)) && z == length(img(1,:))
submatrix = img((i-change):(i),(z-change):(z));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif i == 1 && z == length(img(1,:))
submatrix = img((i):(i+change),(z-change):(z));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif i == length(img(:,1)) && z == 1
submatrix = img((i-change):(i),(z):(z+change));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif i == 1 && z-change >= 1 && z+change <= length(img(1,:))
submatrix = img((i):(i+change),(z-change):(z+change));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif i == length(img(:,1)) && z-change >= 1 && z+change <= length(img(1,:))
submatrix = img((i-change):(i),(z-change):(z+change));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif z == 1 && i-change >= 1 && i+change <= length(img(:,1))
submatrix = img((i-change):(i+change),(z):(z+change));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
elseif z == length(img(1,:)) && i-change >= 1 && i+change <= length(img(:,1))
submatrix = img((i-change):(i+change),(z-change):(z));
emptymatrix(i,z) = uint8(sum(submatrix(:))/numel(submatrix));
output = uint8(emptymatrix);
end
end
end
end
Do you really need to consider all of those cases? I really don't think that you need any if/elseif statements and so could perhaps reduce the code to simply
for z = 1:length(img(1,:)) % iterating over columns
for i = 1:length(img(:,1)) % iterating over rows
minValidRowIndex = max(1,i-w);
maxValidRowIndex = min(numRows,i+w);
minValidColIndex = max(1,z-w);
maxValidColIndex = min(numCols,z-w);
submatrix = img(minValidRowIndex:maxValidRowIndex, minValidColIndex:maxValidColIndex);
output(z,i) = uint8(sum(submatrix(:))/numel(submatrix));
end
end

Sign in to comment.

More Answers (1)

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

2 Comments

Thanks a lot. Code was easy to understand.
this answer is super easy and simple !! very good !!

Sign in to comment.

Asked:

on 8 Apr 2020

Commented:

on 24 Jan 2022

Community Treasure Hunt

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

Start Hunting!