How to reconstruct an image using rgb values of all pixels in Matlab - image

I am trying to read an image using imread then, save the RGB values of all of the pixels in an array. And finally, be able to recreate this image using only the RGB values.
This is the for loop that saves all of the RGB values of each pixel.
A=imread('image.jpg');
N=2500; %the image dimensions are 50x50
i=1;
rgbValues = zeros(N, 3);
for x = 1:50
for y = 1:50
rgbValues(i,:) = A(x,y,:);
i=i+1;
end
end
Now, how am I able to recreate this image if I have all of the rgb values saved.

A direct way to do this is:
ny = 50;
nx = 50;
recreatedImage = zeros(ny,nx,3, 'uint8');
for ind = 1:3
recreatedImage(:,:, ind) = ( reshape(rgbValues(:, ind), nx, ny))';
end
As Natan indicated, reshape will work also but you have to do this:
recreatedImage=reshape(rgbValues,[ny,nx,3]);
Which is, unfortunately, transposed so you will need to work it to get it rotated back up.
You might consider swapping your x and y values in your for loop so you iterate over all y and then all x values---because this is how MATLAB stores the data and you can change the above code to:
for ind = 1:3
recreatedImage(:,:, ind) = ( reshape(rgbValues(:, ind), ny, nx));
end
(edit) and then the direct reshape works as well:
rgbValuesBacktoShape=reshape(rgbValues,[50,50,3]);

Related

Best way to pad image based on the edge pixels (row-wise)

I want to pad an object based on edge pixel to replace the zeros.
I am not sure if padarray is applicable to this, I am showing a sample code below to replicate my need. I am able to do it but I think this is not an efficient way as I am scanning each row at a time to find and pad the zeros.
%% Example code to recreate my need
image = imread('moon.tif');
[~, ncols] = size(image);
image(image <50) = 0;
image = fliplr(image(:,1:round(ncols/2)));
% figure, imshow(image,[])
BW = bwareafilt(logical(image),1);
% create bounding box
boxProps=regionprops(BW,'BoundingBox');
cords_BoundingBox = boxProps(1).BoundingBox;
% Extract sub_Image
sub_Image = imcrop(image, cords_BoundingBox);
% figure, imshow(sub_Image,[])
%% This is the part I want to use better or existing function for padding
duplicate_sub_Image = sub_Image;
[nrows, ~] = size(duplicate_sub_Image);
for nrow = 1:nrows
% current_row_inverted = fliplr(sub_Image(nrow,:));
[~,col,pad_value] = find(duplicate_sub_Image(nrow,:),1,'last');
duplicate_sub_Image(nrow,col+1:end) = pad_value;
end
figure,
subplot(131),imshow(image,[]), title('original image');
subplot(132),imshow(sub_Image,[]), title('bounding box image');
subplot(133),imshow(duplicate_sub_Image,[]), title('row padded image');
Any suggestions to improve this code or use of existing functions to address this issue?
Thanks
Here is a way without using loops:
[~,imin] = min(sub_Image, [], 2);
col = max(1, imin-1);
ind = sub2ind(size(sub_Image), (1:numel(col)).', col);
duplicate_sub_Image = sub_Image(ind) .* ~sub_Image + sub_Image;

Overlapping grayscale and RGB Images

I would like to overlap two images, one grayscale and one RGB image. I would like to impose the RGB image on top of the grayscale image, but ONLY for pixels greater than a certain value. I tried using the double function in MATLAB, but this seems to change the color scheme and I cannot recover the original RGB colors. What should I do in order to retain the original RGB image instead of mapping it to one of the MATLAB colormaps? Below is my attempt at superimposing:
pixelvalues = double(imread('hello.png'));
PixelInt = mean(pixelvalues,3);
I1 = ind2rgb(Brightfield(:,:,1), gray(256)); %Brightfield
I2 = ind2rgb(PixelInt, jet(256)); %RGB Image
imshow(I2,[])
[r,c,d] = size(I2);
I1 = I1(1:r,1:c,1:d);
% Replacing those pixels below threshold with Brightfield Image
threshold = 70;
I2R = I2(:,:,1); I2G = I2(:,:,2); I2B = I2(:,:,3);
I1R = I1(:,:,1); I1G = I1(:,:,2); I1B = I1(:,:,3);
I2R(PixelInt<threshold) = I1R(PixelInt<threshold);
I2G(PixelInt<threshold) = I1G(PixelInt<threshold);
I2B(PixelInt<threshold) = I1B(PixelInt<threshold);
I2(:,:,1) = I2R; I2(:,:,2) = I2G; I2(:,:,3) = I2B;
h = figure;
imshow(I2,[])
Original RGB Image:
Brightfield:
Overlay:
Is the content of pixelvalues what you show in your first image? If so, that image does not use a jet colormap. It has pink and white values above the red values, whereas jet stops at dark red at the upper limits. When you take the mean of those values and then generate a new RGB image with ind2rgb using the jet colormap, you're creating an inherently different image. You probably want to use pixelvalues directly in generating your overlay, like so:
% Load/create your starting images:
pixelvalues = imread('hello.png'); % Color overlay
I1 = repmat(Brightfield(:, :, 1), [1 1 3]); % Grayscale underlay
[r, c, d] = size(pixelvalues);
I1 = I1(1:r, 1:c, 1:d);
% Create image mask:
PixelInt = mean(double(pixelvalues), 3);
threshold = 70;
mask = repmat((PixelInt > threshold), [1 1 3]);
% Combine images:
I1(mask) = pixelvalues(mask);
imshow(I1);
Note that you may need to do some type conversions when loading/creating the starting images. I'm assuming 'hello.png' is a uint8 RGB image and Brightfield is of type uint8. If I load your first image as pixelvalues and your second image as I1, I get the following when running the above code:
Create a mask and use it to combine the images:
onionOrig = imread('onion.png');
onionGray = rgb2gray(onionOrig);
onionMask = ~(onionOrig(:,:,1)<100 & onionOrig(:,:,2)<100 & onionOrig(:,:,3)<100);
onionMasked(:,:,1) = double(onionOrig(:,:,1)) .* onionMask + double(onionGray) .* ~onionMask;
onionMasked(:,:,2) = double(onionOrig(:,:,2)) .* onionMask + double(onionGray) .* ~onionMask;
onionMasked(:,:,3) = double(onionOrig(:,:,3)) .* onionMask + double(onionGray) .* ~onionMask;
onionFinal = uint8(onionMasked);
imshow(onionFinal)

Plot over an image background in MATLAB

I'd like to plot a graph over an image. I followed this tutorial to Plot over an image background in MATLAB and it works fine:
% replace with an image of your choice
img = imread('myimage.png');
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
% make data to plot - just a line.
x = min_x:max_x;
y = (6/8)*x;
imagesc([min_x max_x], [min_y max_y], img);
hold on;
plot(x,y,'b-*','linewidth',1.5);
But when I apply the procedure to my study case, it doesn't work. I'd like to do something like:
I = imread('img_png.png'); % here I load the image
DEM = GRIDobj('srtm_bigtujunga30m_utm11.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000);
% with the last 3 lines I calculated the stream network on a geographic area using the TopoToolBox
imagesc(I);
hold on
plot(S)
The aim is to plot the stream network over the satellite image of the same area.
The only difference between the two examples that doesn't let the code working is in the plot line, in the first case "plot(x,y)" works, in the other one "plot(S)" doesn't.
Thanks guys.
This is the satellite image, imagesc(I)
It is possible that the plot method of the STREAMobj performs it's own custom plotting including creating new figures, axes, toggling hold states, etc. Because you can't easily control what their plot routine does, it's likely easier to flip the order of your plotting so that you plot your stuff after the toolbox plots the STREAMobj. This way you have completely control over how your image is added.
% Plot the STREAMobj
hlines = plot(S);
% Make sure we plot on the same axes
hax = ancestor(hlines, 'axes');
% Make sure that we can add more plot objects
hold(hax, 'on')
% Plot your image data on the same axes
imagesc(I, 'Parent', hax)
Maybe I am preaching to the choir or overlooking something here but the example you used actually mapped the image to the data range of the plot, hence the lines:
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
imagesc([min_x max_x], [min_y max_y], img);
where you directly plot your image
imagesc(I);
If now your data coordinates and your image coordinates are vastly different you either see one or the other.
Thanks guys, I solved in this way:
I = imread('orto.png'); % satellite image loading
DEM = GRIDobj('demF1.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000); % Stream network extraction
x = S.x; % [node attribute] x-coordinate vector
y = S.y; % [node attribute] y-coordinate vector
min_x = min(x);
max_x = max(x);
min_y = min(y);
max_y = max(y);
imagesc([min_x max_x], [min_y max_y], I);
hold on
plot(S);
Here's the resulting image: stream network over the satellite image
Actually the stream network doesn't match the satellite image just because I'm temporarily using different images and DEM.

Mid line through a set of dicom images in matlab

I have a set of Dicom images on matlab and i would like to add a midline going through all the images
I am outputting the images via imshow3d function
thanks
Edit: here's what i have, the random points are not in the middle they just run through the image
>> clc;
>>clear;
>>%imports dicom images
>>run DicomImport.m;
>>%random points for shortest distance test
>>a = [1 10 200];
>>b = [500 512 300];
>>ab = b - a;
>>n = max(abs(ab)) + 1;
>>s = repmat(linspace(0, 1, n)', 1, 3);
>>for d = 1:3
>> s(:, d) = s(:, d) * ab(d) + a(d);
>>end
>>s = round(s);
>>Z = 593;
>>N = 512;
>>X = zeros(N, N, Z);
>>X(sub2ind(size(X), s(:, 1), s(:, 2), s(:, 3))) = 1;
>>C = find(X);
>>ans.Img(C) = 5000;
>> %shows image
>>imshow3D(ans.Img);
So it looks like ans.Img contains the 3D matrix consisting of your image stack. It looks like you've got something going, but allow me to do this a bit differently. Basically, you need to generate a set of coordinates where we can access the image stack and draw a vertical line in the middle of the each image in the image stack. Do something like this. First get the dimensions of the stack, then determine the halfway point for the columns. Next, generate a set of coordinates that will draw a line down the middle for one image. After you do this, repeat this for the rest of the slices and get the column major indices for these:
%// Get dimensions
[rows,cols,slices] = size(ans.Img);
%// Get halfway point for columns
col_half = floor(cols/2);
%// Generate coordinates for vertical line for one slice
coords_middle_row = (1:rows).';
coords_middle_col = repmat(col_half, rows, 1);
%// Generate column major indices for the rest of the slices:
ind = sub2ind(size(ans.Img), repmat(coords_middle_row, slices, 1), ...
repmat(coords_middle_col, slices, 1), ...
reshape(kron(1:slices, ones(rows, 1)), [], 1));
%// Set the pixels accordingly
ans.Img(ind) = 5000;
This code is quite similar to the answer I provided to one of your earlier question; i.e. I don't use imshow3D but the framework is similar and simpler to modify in order to suit your need. In this case, upon pressing a pushbutton a line appears at the middle of the stack and you can scroll through it with the slider. I hope this can be of help.
function LineDicom(~)
clc
clear
close all
%// Load demo data
S = load('mri');
%// Get dimensions and number of slices.
ImageHeight = S.siz(1); %// Not used here
ImageWidth = S.siz(2); %// Not used here
NumSlices = S.siz(3);
S.D = squeeze(S.D);
%// Create GUI
hFig = figure('Position',[100 100 400 400],'Units','normalized');
%// create axes with handle
handles.axes1 = axes('Position', [0.2 0.2 0.6 0.6]);
%// create y slider with handle
handles.y_slider = uicontrol('style', 'Slider', 'Min', 1, 'Max', NumSlices, 'Value',1, 'Units','normalized','position', [0.08 0.2 0.08 0.6], 'callback', #(s,e) UpdateY);
handles.SlideryListener = addlistener(handles.y_slider,'Value','PostSet',#(s,e) YListenerCallBack);
%// Create pusbutton to draw line
handles.DrawLineButton= uicontrol('style', 'push','position', [40 40 100 30],'String','Draw line', 'callback', {#DrawLine,handles});
%// Flag to know whether pushbutton has been pushed
handles.LineDrawn = false;
%// Show 1st slice
imshow(S.D(:,:,1))
guidata(hFig,handles);
%// Listeners callbacks followed by sliders callbacks. Used to display each
%// slice smoothly.
function YListenerCallBack
handles = guidata(hFig);
%// Get current slice
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
%// If button was button, draw line
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
function UpdateY(~)
handles = guidata(hFig); %// Get handles.
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
%// Pushbutton callback to draw line.
function DrawLine(~,~,handles)
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
handles.LineDrawn = true;
guidata(hFig,handles);
end
end
Sample output:
and after moving the slider up:
Is this what you meant? If not I'll remove that answer haha and sorry.

Applying SAD on image using matlab

Hello so I have an original image and I cropped a part of that image(template) and wrote a code with SAD algorithim to detect on the original image the part i cropped (template) where it exists and draw a rectangle on it.
The code doesnt have any errors , but the rectangle draw doesnt match the template , so I guess the 'output ' variable is the problem can you please help me
I2=imread('img.PNG');
I2=rgb2gray(I2);
[r,c]= size(I2);
%padding the image
%padding
B = padarray(I2,[24 24],'replicate' ,'both');
%imshow(B);
%creating template
temp=imread('crop_img.PNG');
temp= rgb2gray(temp);
%imshow(temp)
size(temp)
output = zeros (size(I2));
K = size(temp)
x=1;
y=1;
for i = 25 : r-24
for j = 25: c-24
%dif = temp -I2(i:i+47,j:j+47) ;
K = imabsdiff(temp,B(i-24:i+24,j-24:j+24));
output(i-24, j-24) = sum (K(:));
end
end
%gettting min value in output
min_value = output(1,1)
for i=1 : r
for j=1 :c
if(output(i,j)<min_value)
min_value=output(i,j);
row=i;
col=j;
end
end
end
row
col
output(1,465)
output(6,200)
%draw rectangle on matching area
%Create the shape inserter object.
shapeInserter = vision.ShapeInserter;
%Define the rectangle dimensions as [x y width height].
rectangle = int32([row col 24 24]);
%Draw the rectangle and display the result.
J = step(shapeInserter, I2, rectangle);
imshow(J);
There is an issue with image coordinates vs. matrix coordinates - you need to flip your row and column variables. Also, with shapeInserter, the coordinates are for the corner of the rectangle, so to make something centred on your output, you'd need something along the lines of:
rectangle = uint8([col-12 row-12 24 24]);
In MATLAB, it is usually not required to loop over every pixel of an image - it's much more efficient to work on the whole image at once. For example, you don't need a loop here:
min_value = output(1,1)
for i=1 : r
for j=1 :c
if(output(i,j)<min_value)
min_value=output(i,j);
row=i;
col=j;
end
end
end
This can be replaced by:
min_value = min(output(:));
[row,col] = find(output==min_value,1,'first');

Resources