2

I have just started learning image-processing and Matlab and I'm trying to scale down an image using an average of 4 pixels. That means that for every 4 original pixels I calculate the average and produce 1 output pixel. So far I have the following code:

img = imread('bird.jpg');
row_size = size(img, 1);
col_size = size(img, 2);
res = zeros(floor(row_size/2), floor(col_size/2));
figure, imshow(img);
for i = 1:2:row_size
    for j = 1:2:col_size
        num = mean([img(i, j), img(i, j+1), img(i+1, j), img(i+1, j+1)]);
        res(round(i/2), round(j/2)) = num;
    end
end
figure, imshow(uint8(res));

This code manages to scale down the image but it converts it to grayscale. I understand that I probably have to calculate the average of the RGB components for the output pixel but I don't know how to access them, calculate the average and insert them to the result matrix.

Leos313
  • 5,152
  • 6
  • 40
  • 69
formap
  • 35
  • 1
  • 5
  • 1
    Have a look in the work-space and see the variable img. It should be at least a NxMx3 matrix where N and M are the dimensions of the image. You can access to every element as ever for every matrix in Matlab. Try to use the command "who" and "whos" as well – Leos313 Oct 11 '16 at 11:38
  • Can you please write what you obtain if you do A=size(img)? which values inside A? – Leos313 Oct 11 '16 at 11:49
  • Possible duplicate of [Resizing an Image in MATLAB](http://stackoverflow.com/questions/6183155/resizing-an-image-in-matlab) – Leos313 Oct 12 '16 at 10:18

3 Answers3

4

In Matlab, an RGB image is treated as a 3D array. You can check it with:

depth_size = size(img, 3)

depth_size =

     3

The loop solution, as you have done, is explained in Sardar_Usama's answer. However, in Matlab it is recommended to avoid loops whenever you want to gain speed.

This is a vectorized solution to scale down an RGB image by a factor of n:

img = imread('bird.jpg');
n = 2; % n can only be integer
[row_size, col_size] = size(img(:, :, 1));

% getting rid of extra rows and columns that won't be counted in averaging:
I = img(1:n*floor(row_size / n), 1:n*floor(col_size / n), :);
[r, ~] = size(I(:, :, 1));

% separating and re-ordering the three colors of image in a way ...
% that averaging could be done with a single 'mean' command:
R = reshape(permute(reshape(I(:, :, 1), r, n, []), [2, 1, 3]), n*n, [], 1);
G = reshape(permute(reshape(I(:, :, 2), r, n, []), [2, 1, 3]), n*n, [], 1);
B = reshape(permute(reshape(I(:, :, 3), r, n, []), [2, 1, 3]), n*n, [], 1);

% averaging and reshaping the colors back to the image form:
R_avg = reshape(mean(R), r / n, []);
G_avg = reshape(mean(G), r / n, []);
B_avg = reshape(mean(B), r / n, []);

% concatenating the three colors together:
scaled_img = cat(3, R_avg, G_avg, B_avg); 

% casting the result to the class of original image
scaled_img = cast(scaled_img, 'like', img); 

Benchmarking:

If you want to know why vectorized solutions are more popular, take a look at how long it takes to process an RGB 768 x 1024 image with the two methods:

------------------- With vectorized solution:
Elapsed time is 0.024690 seconds.

------------------- With nested loop solution:
Elapsed time is 6.127933 seconds.

So there is more than 2 orders of magnitude difference of speed between the two solutions.

Community
  • 1
  • 1
Erfan
  • 1,897
  • 13
  • 23
1

Another possible solution can be using the function blockproc as mentioned at this link. This will also avoid for loops.

Ruchir
  • 845
  • 2
  • 10
  • 24
0

You can take care of that using the modified code below:

img = imread('bird.jpg');
row_size = size(img, 1);
col_size = size(img, 2);
figure, imshow(img);

res = zeros(floor(row_size/2), floor(col_size/2), 3); %Pre-allocation
for p = 1:2:row_size
    for q = 1:2:col_size
        num = mean([img(p, q,:), img(p, q+1,:), img(p+1, q,:), img(p+1, q+1,:)]);
        res(round(p/2), round(q/2),:) = num;
    end
end
figure, imshow(uint8(res));

I took a sample image of 1200x1600x3 uint8 which is converted to 600x800x3 uint8 by the above code which is correct because (1200*1600)/4 = 480000 and 600*800 = 480000

P.S : I changed the variable names i and j to p and q respectively since i and j are reserved for imaginary numbers.

Community
  • 1
  • 1
Sardar Usama
  • 19,536
  • 9
  • 36
  • 58