I'm using Octave 5.2 and can create a 640 x 480 x 3 image from an array of RGB values using meshgrid
and reshape
but is there a better way of doing this? (code is below) I tried using cat
and imresize with nearest
but the array is 640x480 not 640x480x3 and it creates black squares due to the fact the array is not in a 640x480x3 format can this be worked around to get the colored bar image?.
f(:,:,1)=[255;0;0;0;0];
f(:,:,2)=[0;255;0;0;255];
f(:,:,3)=[0;0;255;0;2];
num_of_colors=numel(f(:,:,1));
img_resize_height=640
img_resize_height_tmp=round(img_resize_height/num_of_colors); %create the height wanted
%1) create size of array wanted
[r_im_tmp_x r_im_tmp_y]=meshgrid((f(:,:,1)),1:img_resize_height_tmp)
[g_im_tmp_x g_im_tmp_y]=meshgrid((f(:,:,2)),1:img_resize_height_tmp);
[b_im_tmp_x b_im_tmp_y]=meshgrid((f(:,:,3)),1:img_resize_height_tmp);
%2) reshape grid to evenly space out colors (in one column)
r_resize_tmp=reshape(r_im_tmp_x,[1,numel(r_im_tmp_x)])';
g_resize_tmp=reshape(g_im_tmp_x,[1,numel(g_im_tmp_x)])';
b_resize_tmp=reshape(b_im_tmp_x,[1,numel(b_im_tmp_x)])';
%3 make array size wanted 480
img_resize_len=480;
r_resize_tmp2=repmat(r_resize_tmp,([1,img_resize_len]));
g_resize_tmp2=repmat(g_resize_tmp,([1,img_resize_len]));
b_resize_tmp2=repmat(b_resize_tmp,([1,img_resize_len]));
img_resize_rgb(:,:,1)=r_resize_tmp2;
img_resize_rgb(:,:,2)=g_resize_tmp2;
img_resize_rgb(:,:,3)=b_resize_tmp2;
figure(1);
imshow(img_resize_rgb);
The image it creates is correct there just seems like there may be a simpler / better way to code this.
I tried using imresize
command to do the same thing to improve the code. (see code below).
pkg load image
f(:,:,1)=[255;0;0;0;0];
f(:,:,2)=[0;255;0;0;255];
f(:,:,3)=[0;0;255;0;2];
height_wanted=640;
width_wanted=480;
repmat_rgb=cat(2,f,f); %add another column to array to get imresize to work
reshaped_output = imresize(repmat_rgb, [height_wanted, width_wanted],'nearest'); %reshape swatch to large output
imshow(reshaped_output);
The image created is incorrect and black and white (most likely due to the array being 640x480 instead of 640x480x3 (how can I fix this?)
It looks like a bug in imresize
implementation of Octave image package (in MATLAB the code is working).
When the input of imresize
is RGB (3D matrix), the output should also be RGB (3D matrix).
In your example the output is Grayscale (2D matrix instead of 3D matrix).
It is a bug in imresize
implementation!
The function is "open source", and we can debug it using the debugger.
Executing the code step by step (stepping into imresize
) get us to the following piece of code:
elseif (strcmpi (method, "nearest") && all ([int_row_scale int_col_scale]))
## we are matlab incompatible here on purpose. We can the stuff here in 2
## ways. With interp2 or by clever indexing. Indexing is much much faster
## than interp2 but they return different results (the way we are doing it
## at least). Matlab does the same as we are doing if the both columns and
## rows go the same direction but if they increase one and decrease the
## other, then they return the same as if we were using interp2. We are
## smarter and use indexing even in that case but then the results differ
if (int_row_scale == 1)
row_idx = (1:rows (im))(ones (1, scale_rows), :);
elseif (int_row_scale == -1)
row_idx = ceil (linspace (floor (1/(scale_rows * 2)) + 1, inRows, outRows));
endif
if (int_col_scale == 1)
col_idx = (1:columns (im))(ones (scale_cols, 1), :);
elseif (int_col_scale == -1)
col_idx = ceil (linspace (floor (1/(scale_cols * 2)) + 1, inCols, outCols));
endif
im = im(row_idx, col_idx);
The bug is in the last line of the above part.
Instead of im = im(row_idx, col_idx);
it should be:
im = im(row_idx, col_idx, :);
In case you don't want to edit the "image package" code, you may use the following workaround:
Resize each color channel and concatenate the resized channels.
Replace reshaped_output = imresize(repmat_rgb, [height_wanted, width_wanted], 'nearest');
with:
out_r = imresize(repmat_rgb(:, :, 1), [height_wanted, width_wanted], 'nearest');
out_g = imresize(repmat_rgb(:, :, 2), [height_wanted, width_wanted], 'nearest');
out_b = imresize(repmat_rgb(:, :, 3), [height_wanted, width_wanted], 'nearest');
reshaped_output = cat(3, out_r, out_g, out_b);
Note:
The class of f
is double
, and the range of the values supposed to be [0, 1].
All values above 1
are clipped to 1
when using imshow
.
You may initialize f
to:
f(:,:,1)=[1;0;0;0;0];
f(:,:,2)=[0;1;0;0;1];
f(:,:,3)=[0;0;1;0;1];
Or cast to uint8
:
f(:,:,1)=[255;0;0;0;0];
f(:,:,2)=[0;255;0;0;255];
f(:,:,3)=[0;0;255;0;255];
f = uint8(f);