Change Range Of Displayed Pixel Values from Command Line? - image

I'm working with some MRI data in Matlab 2014b, but the data is formed of intensity values not RGB. To get around this I use the code below to form a movie out of the MRI frames (I'm working on dynamic data here)
My problem is that the images need to have altered display values for the pixels, as the default only displays between -Inf and Inf, and I need between 0 and 0.25 to get a sensible image out of my data.
Are there any ways to pass that change from the script in to the movie, and then to write to file? I can only seem to do this per image in implay, and I'd like an automated way to edit each image and then store as a frame for a movie..?
%Code for producing movie.
graymap = gray(256);
for i = 1:32
a(:,:,i) = cmunique(Reformed_Data_Colourmap(:,:,i));
end
for i = 1:32
b = im2frame(a(:,:,i),graymap);
a(:,:,1) = ((b.cdata));
image(a(:,:,1))
colormap 'gray'
%The change needs to be here, to display pixel values from 0 to 0.25, to allow for a sensible image from the MR data.
frames(1,i) = getframe;
end
movie(frames)

The solution is provided:
for i = 1:32
b = im2frame(a(:,:,i),graymap);
a(:,:,1) = ((b.cdata));
clims = [0 250];
%image(a(:,:,1),clims)
colormap 'gray'
imagesc(a(:,:,1),clims);
%set('window', [0 400])
frames(1,i) = getframe;
end
clims solves the issue.

Related

How do I read a RAW RGB image in MATLAB?

I am trying to properly convert a RAW image so that I can view it in MATLAB. Image can be downloaded here. I am using the version of the code provided in How can I read in a RAW image in MATLAB?
However, it is not working properly for me. Here is my slightly modified version below:
clear;
row=966; col=1296;
fin=fopen('C:\Users\user\Desktop\test2.raw','r');
I=fread(fin, col*row*3,'uint8=>uint8'); %// Read in as a single byte stream
I = reshape(I, [col row 3]); %// Reshape so that it's a 3D matrix - Note that this is column major
Ifinal = flipdim(imrotate(I, -90),2); % // The clever transpose
imshow(Ifinal);
fclose(fin); %// Close the file
What I get:
What I should get:
I'm not sure why it's not working for me but if I use an imaging program (ImageJ) I can correctly convert the RAW file if I select Image type as '24-bit BGR'. The pixel format of the image is 8 Bit BAYRG.
There you go:
function q43127920
row=966; col=1296;
fin=fopen('test.raw','r');
I = fread(fin, col*row*3,'ubit24=>uint32');
I = reshape(I, col, row, []);
B = uint8(bitand(bitshift(I,-00),uint32(255)));
G = uint8(bitand(bitshift(I,-08),uint32(255)));
R = uint8(bitand(bitshift(I,-16),uint32(255)));
I = cat(3,R,G,B);
Ifinal = flip(imrotate(I, -90),2);
imagesc(Ifinal);
fclose(fin);
Result:

How to transfer the .mat file to image file without any change?

I have a image.mat of about 4MB.
The size of some image file can also be 4MB.
Can the image.mat be transferred to image file?
I tried this, but that doesn't do the trick:
load image.mat %load Iw
imshow(mat2gray(Iw))
imwrite(Iw,'image.png');
IwNew = imread('image.png');
isequal(Iw,IwNew)
The result is 0; am I misunderstanding something?
The number in Iw are very important, so Iw can not be changed.
Actually my real problem is how to store float numbers into an image?
But MATLAB does not support Tiff 6.0, so I'll have to find some workaround.
I am doing a blind watermarking,and the decimal fraction of a number in Iw is important because it involve the information about another image.So the Iw can not be changed.
Actually,Mathematica can store floating floating-point data:
But my programs are all in MATLAB.
According to Matlab documentation:
"If A is a grayscale or RGB color image of data type double or single, then imwrite assumes that the dynamic range is [0,1] and automatically scales the data by 255 before writing it to the file as 8-bit values."
In other words: imwrite performs automatic conversion from double to uint8.
if you wish to keep the values of Iw unchanged, save it as a mat file and not as an image.
If you do want to save it as an image - there is going to be some loss of information. In this case, there are two things which need to be done:
Change the dynamic range of the matrix to [0,1]. (in your case, the range is between -0.0035 to 255.0035. Also, the matrix contain inf values).
If you want to get an equality, scale IwNew by 255, and convert it to uint8.
Code:
load image.mat %load Iw
%step 1, change the dynamic range of the image to [0,1].
%One way to do it is by using mat2gray on each channel separately.
Iw(:,:,1) = mat2gray(Iw(:,:,1));
Iw(:,:,2) = mat2gray(Iw(:,:,2));
Iw(:,:,3) = mat2gray(Iw(:,:,3));
%write the image to file
imwrite(Iw,'image.png');
%read the image
IwNew=imread('image.png');
%scale it, and convert to uint 8
Iw2 = uint8(Iw*255);
%check equality
isequal(Iw2,IwNew)
Result:
ans =
1
Alternatively, if you want to convert IwNew to double, perform the following:
%conversion to double
Iw2 = double(IwNew)/255;
Notice that in this case, the matrices won't be equal to one another,
Due to the loss of information which happened during the imwrite process (conversion from double to uint8).
Instead, they will be epsilon-close to one another, where epsilon = 0.0001.
In order to test this, write the following:
%equality check
sum(abs(Iw2(:)-Iw(:))>0.0001)
Result:
ans =
0
My MATLAB (R2010a) with the image processing toolbox is perfectly capable of storing double-valued pixel values, and retrieve them without loss of data.
Here's a shameless copy of this answer:
% Some random, data of type double
A = 7.6*rand(10);
% Construct TIFF image...
t = Tiff('test.tif', 'w');
% ...with these custom parameters...
tagstruct = struct(...
'ImageLength' , size(A,1),...
'ImageWidth' , size(A,2),...
'Compression' , Tiff.Compression.None,...
'SampleFormat' , Tiff.SampleFormat.IEEEFP,... % floating point
'Photometric' , Tiff.Photometric.MinIsBlack,...
'BitsPerSample' , 64,... % 8 bytes / double
'SamplesPerPixel' , 1,...
'PlanarConfiguration', Tiff.PlanarConfiguration.Chunky);
t.setTag(tagstruct);
% ...and write it to disk.
t.write(A);
t.close();
% Read the data actually written, and check if all
% information was indeed preserved:
B = imread('test.tif');
isequal(A,B)
Result:
ans =
1
Adjust in obvious ways if you have more than 1 channel (RGB).

Image blending with mask

I'm trying to combine the two images based on the information from the mask. I'm using the color information from the background image if the mask is 0 and color information from foreground image if the mask is 1. Because the mask and both
Images are of the same size, I would like to use logical indexing of matrices to achieve this.
My attempt:
mask = imread('mask.png');
foreground = imread('fg.jpg');
background = imread('bg.jpg');
[r,c,~]=size(mask);
A = zeros(size(mask));
for i=1:r
for j=1:c
if mask(i,j) == 0
A(i,j,:) = background(i,j,:);
end
if mask(i,j) > 0
A(i,j,:) = foreground(i,j,:);
end
end
end
imshow(A);
The result looks like a flickering blue image, but I don't want that. Please help.
You can do this a bit more concisely:
f = double(foreground).*double(mask);
b = double(background).*double(~mask);
blend = f+b;
imshow(blend, []);
Using logical indexing you could also do
foreground(logical(mask)) = 0;
background(logical(~mask)) = 0;
blend = foreground+background;
The ISNOT operator '~' inverts your matrix in the second line, so you cut out the area you would like for background.
NOTE: This works for black and white (one channel). For coloured images see rayryeng's solution.
There are two problems with your code. The first problem is that you are trying to assign colour pixels to the output image A, yet this image is only two-dimensional. You want an image with three channels, not two. In addition, the output image type you are specifying is wrong. By default, the output image A is of type double, yet you are copying values into it that aren't double... most likely unsigned 8-bit integer.
As such, cast the image to the same type as the input images. Assuming both input images are the same type, initialize your A so that:
A = zeros(size(foreground), class(foreground));
This correctly makes a colour image with the same type as any of the inputs, assuming that they're both the same type.
Now, your for loop is fine, but it's better if you do this in one shot with logical indexing. If you want to use logical indexing, create a new image that's initially blank like what you've done, but then make sure your mask has three channels to match the number of channels the other images have. After, you simply need to index into each image and set the right locations accordingly:
mask = imread('mask.png');
foreground = imread('fg.jpg');
background = imread('bg.jpg');
[r,c,d]=size(mask); %// Change
%// If your mask isn't three channels, make it so
%// Change
if d ~= 3
mask = cat(3, mask, mask, mask);
end
A = zeros(size(foreground), class(foreground)); %// Change
A(mask) = foreground(mask); %// Assign pixels to foreground
A(~mask) = background(~mask); %// Assign pixels to background
imshow(A);

MATLAB: How to change pixel values after using VideoReader

I'm trying to read a video file using VideoReader and change some pixel values and save it back to the video file. I can easily change the matrix values but how do I save it back into the video file?
obj = VideoReader('DemoClip.asf');
imageData = read(obj);
imageData(17,32,:) = 65;
Here is a way to do it using videoWriter. The code is commented; if something is unclear please ask. I used the demo xylophone.mp4 file from Mathworks.
clear
clc
close all
xyloObj = VideoReader('xylophone.mp4');
imageData = read(xyloObj);
%// Open writer object
writerObj = VideoWriter('NewVideo.avi');
open(writerObj);
%// Show 1st frame
hIm = imshow(imageData(:,:,:,1));
for k = 1:size(imageData,4)
%// Change pixel values
imageData(1:200,1:200,:,k) = uint8(0);
%// Refresh cdata property. Faster than calling repetitevely imshow
set(hIm,'CData',imageData(:,:,:,k));
drawnow
frame = getframe;
%// Write to video file
writeVideo(writerObj,frame);
end
close(writerObj);
Sample frame of the resulting video:

image stack display in matlab using a slider

I have a 3 dimension matrix of data (a stack of images across a dimension, time for example.
I want to display an image, and have a slider below to navigate across the images.
I wrote a piece of code which works, but it's bulky and kinda ugly I think...I want to write a clean function and so I would like to know if anyone know of a cleaner, nicer way to do it.
Here is my code:
interv = [min max]; % interval for image visualization
imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv);
title('My Title');
xlabel('X (cm)');
ylabel('Y (cm)');
pos = get(gca,'position');
% slider position
Newpos = [pos(1) pos(2)-0.1 pos(3) 0.05];
pp = 1;
% callback slider
S = ['pp=floor(get(gcbo,''value''));imagesc(Temps_visu,X*100,squeeze(X,Y,MyMatrix(:,:,1)),interv));' ...
'set_axes_elasto;title(''My Title'');disp(pp);'];
Mz = size(MyMatrix,3);
% Creating Uicontrol
h = uicontrol('style','slider',...
'units','normalized',...
'position',Newpos,...
'callback',S,...
'min',1,'max',Mz,...
'value',pp,...
'sliderstep',[1/(Mz-1) 10/(Mz-1)]);
Here is a way to do it using a listener object for smooth visualization of your stack. I made up a dummy stack using grayscale variations of the same image (i.e. only 4 frames) but the principle will be the same for your application. Notice that I use imshow to display the images, but using imagesc as you do won't cause any problem.
The code is commented so hopefully this is clear enough. If not please don't hesitate to ask for help!
Code:
function SliderDemo
clc
clear all
NumFrames = 4; %// Check below for dummy 4D matrix/image sequence
hFig = figure('Position',[100 100 500 500],'Units','normalized');
handles.axes1 = axes('Units','normalized','Position',[.2 .2 .6 .6]);
%// Create slider and listener object for smooth visualization
handles.SliderFrame = uicontrol('Style','slider','Position',[60 20 400 50],'Min',1,'Max',NumFrames,'Value',1,'SliderStep',[1/NumFrames 2/NumFrames],'Callback',#XSliderCallback);
handles.SliderxListener = addlistener(handles.SliderFrame,'Value','PostSet',#(s,e) XListenerCallBack);
handles.Text1 = uicontrol('Style','Text','Position',[180 420 60 30],'String','Current frame');
handles.Edit1 = uicontrol('Style','Edit','Position',[250 420 100 30],'String','1');
%// Create dummy image sequence, here 4D sequence of grayscale images.
MyImage = imread('peppers.png');
MyMatrix = cat(4,rgb2gray(MyImage),MyImage(:,:,1),MyImage(:,:,2),MyImage(:,:,3));
%// Use setappdata to store the image stack and in callbacks, use getappdata to retrieve it and use it. Check the docs for the calling syntax.
setappdata(hFig,'MyMatrix',MyMatrix); %// You could use %//setappdata(0,'MyMatrix',MyMatrix) to store in the base workspace.
%// Display 1st frame
imshow(MyMatrix(:,:,:,1))
%// IMPORTANT. Update handles structure.
guidata(hFig,handles);
%// Listener callback, executed when you drag the slider.
function XListenerCallBack
%// Retrieve handles structure. Used to let MATLAB recognize the
%// edit box, slider and all UI components.
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
%// Get current frame
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
%// Display appropriate frame.
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
%// Slider callback; executed when the slider is release or you press
%// the arrows.
function XSliderCallback(~,~)
handles = guidata(gcf);
%// Here retrieve MyMatrix using getappdata.
MyMatrix = getappdata(hFig,'MyMatrix');
CurrentFrame = round((get(handles.SliderFrame,'Value')));
set(handles.Edit1,'String',num2str(CurrentFrame));
imshow(MyMatrix(:,:,:,CurrentFrame),'Parent',handles.axes1);
guidata(hFig,handles);
end
end
The figure looks like this:
Hope that helps!

Resources