Octave script loop only runs once - image

I have a script that reads images, overlays scatterplot points on them, and then combines all of the resulting images into a movie. I have run into some difficulty translating the script to work in Octave though. I have worked out all of the kinks, except that my loop only runs once. I.e. The video created is only one frame long. I suspect that this may have something to do with gcf? ALthough I've been looking at it so long that I think it might just be something simple i'm missing. Any thoughts would be much appreciated.
The loop is:
for i = 1:subsamp:numel(dd)
if (mod(i,100)==0)
fprintf('frame %d/%d\n', i, numel(dd));
end
% read current image and trim its width and height to a multiple of 4
img = imread([img_dir,'/',dd(i).name]);
trim_x = mod(size(img,2),4);
trim_y = mod(size(img,1),4);
img = img(1:end-trim_y,1:end-trim_x);
% display current image
set(0,'CurrentFigure',hnd);
imshow(img);
% if there is truth for this frame, show it
which_block = map(i);
if (which_block > 0)
% grab data chunk for this frame
block = truth(starts(which_block):ends(which_block),:);
pts = block(:,7:8);
ids = block(:,2);
% overlay tracks and ids
hold on;
scatter(pts(:,1),pts(:,2),5);
hold off;
end
% add this frame to movie file
getframe(img);
mov = addframe(mov,frame);
end
and the "getframe()" function at the end is one I found elsewhere online. It looks like this:
function frame = getframe (h)
print ("tmp.fig", "-djpg");
frame = im2double (imread ("tmp.fig"));
## Truncate to even size to accomodate addframe()
if (mod (size (frame, 1), 2) > 0); frame = frame(2:end, :, :); endif
if (mod (size (frame, 2), 2) > 0); frame = frame(:, 2:end, :); endif
endfunction
Again, if you notice anything that could be stopping this from iterating through every frame it's much appreciated. Thanks!!

Related

Failing to print current figure

Here is an attempt of creating a simple animation by generating frames as a sequence of figures, saved in .png format1:
clc
clear
close all
% don't display plot : produces error.
%set(0, 'defaultfigurevisible', 'off');
% number of frames.
N = 2;
% generate data sets.
x = linspace(0, 6 * pi, 1000);
y = sin(x);
% run animation.
for i = 1 : N
% create figure.
clf
% hold on % produces error.
plot(x, y, x(i), y(i), 'ro')
% plot(x(i), y(i), 'ro')
grid on
axis tight
title( sprintf( 'Sine Wave at (%f, %f)', x(i), y(i) ) )
xlabel('x')
ylabel('y')
drawnow
% create frame name: fr00001.png, etc.
framename = sprintf('output/fr%05d.png', i);
% save current figure in file: output.
print(framename);
end
However, the only thing I get is:
Mesa warning: couldn't open dxtn.dll, software DXTn compression/decompression unavailableGL2PS error: Incorrect viewport (x=0, y=240883432, width=0, height=240885832)error: gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERRORerror: called fromopengl_print at line 172 column 7print at line 519 column 14sinewave at line 48 column 3
Any recommendation would be appreciated.
Note: the commented lines are intentionally left.
1. Later on to be stitched into a movie in .avi format with the help of an encoder.
Executed on Octave-4.2.1 on Windows 10
What helps1 is to use print() with a graphics handle to the figure and to define the file names (.png) including the absolute path of the directory in which they will be stored. Noticing that sub-directory is denoted with \ rather than /, moreover, it needs an additional \ escape character to be valid. Then the following code:
N = 1000;
x = linspace(0, 6*pi, N);
y = sin(x);
abspath = 'D:\\...\\Project\\output\\';
fh = figure();
for i = 1 : N
clf
hold on
plot(x, y);
plot(x(i), y(i), 'ro')
grid on
axis tight
title( sprintf( 'Sine Wave at (%f, %f)', x(i), y(i) ) )
xlabel('x')
ylabel('y')
drawnow
framename = sprintf('%sfr%04d.png', abspath, i);
print(fh, framename);
end
produces 1000 frames, which when2 stitched together give:
1. It still crashes unexpectedly after few hundred plots.
2. The first 100 .png files are converted to a .gif with the use of imagemagick's command: magick convert -delay 10 -loop 0 *png output.gif.

How to show all the lines I draw by imfreehand

I am using a code that allows me to draw freehand on the image. The code is as below:
I = imread('peppers.png');
imshow(I);
for i=1:3
M = imfreehand(gca,'Closed',0);
F = false(size(M.createMask));
end
P0 = M.getPosition;
D = round([0; cumsum(sum(abs(diff(P0)),2))]);
P = interp1(D,P0,D(1):.5:D(end));
P = unique(round(P),'rows');
S = sub2ind(size(I),P(:,2),P(:,1));
F(S) = true;
figure;
imshow(F);
imwrite(F,'line.jpg')
Picture 1
Picture 2
Using above code, I can draw freehand as I wish on the photo (Picture 1). But in the output figure (Picture 2), it shows only the last figure I've drawn. I want to show all freehand figures that I've drawn. Can anyone suggest me how shall I improve the codes so whatever I draw on pic1 will be shown on pic2. Thanks.
It's simply a matter of the end of your loop (i.e. the end syntax) so that you are setting the mask after each iteration. What you are doing instead is capturing all of the strokes, but you are resetting the mask that contains the stroke at each iteration. Therefore you only capture the stroke of the last iteration.
You'll need to fix this and once you do, you will also need an external mask variable that remembers each stroke as you make it then this is the final mask variable you save in the end.
My edits to your code are seen below delineated in comments:
close all;
I = imread('peppers.png');
figure;
imshow(I);
%// New - Create external mask variable that remembers each stroke in the loop
mask = false(size(I,1), size(I,2));
for i=1:3
M = imfreehand(gca,'Closed',0);
F = false(size(M.createMask));
P0 = M.getPosition;
D = round([0; cumsum(sum(abs(diff(P0)),2))]);
P = interp1(D,P0,D(1):.5:D(end));
P = unique(round(P),'rows');
S = sub2ind(size(I),P(:,2),P(:,1));
F(S) = true;
%// Save stroke into external mask
mask = mask | F;
end %// Move end statement here
%// Show mask then save
figure;
imshow(mask);
imwrite(mask,'line.jpg');
The logical OR operation (i.e. |) updates the mask with each stroke as you loop through and make new ones. When I make the above modifications, I now get this image when I tried to replicate your strokes right before it gets saved:

To show/join Two Images Simultaneously in Matlab's slider?

I cannot make too big file (like tried here) so I need to show only portions at a time.
However, I cannot make the transfer from one file to another smooth in Matlab.
I am trying to expand the solution of the thread To refresh imshow in Matlab? for two images. The problem is the ending of image A and start of the image B. Now, I have an interruption in the flow, which I do not like because I cannot show two images at the same time without an interruption.
In the example here, it is not needed to filter the axes.
Code
iterationCounter=1;
hFig=figure('Menubar','none', 'NumberTitle','off', 'Color','k');
while(iterationCounter < 7)
filenamePng=fullfile(homedir, '/Images/Raw/', iterationCounter, '.png');
imgRGB=imread(filenamePng);
% https://stackoverflow.com/a/29952648/54964
%%// create sliding-window video
len = 40*2^3;
signal = imgRGB(:,1:end,:);
hImg = imshow(signal(:,1:1+len,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
M = size(signal,2);
for k=1:M-len
set(hImg, 'CData',signal(:,k:k+len,:))
writeVideo(vid, getframe());
end
iterationCounter=iterationCounter+1;
end
close(vid);
Output for Image A and Image B
where there is an interruption in the slider after each image.
The picture is just a screenshot of two images: beginning and ending of the slider. The blue area is just OS X GUI but still indicates that there is a gap and interruption between the start and end.
How can show/join two images simultaneously in Matlab's slider?
In order to display multiple images side by side in this scrolling window, I think the easiest approach is to actually load all of the images upfront into an array that is [nRows x (nColumns * nImages) x 3] and then just use the original code to scroll through this.
hFig=figure('Menubar','none', 'NumberTitle','off', 'Color','k');
signal = [];
% Load all the images into one "long" image
for k = 1:7
filename = fullfile(homedir, sprintf('%d.png', k));
img = imread(filename);
signal = cat(2, signal, img);
end
%%// create sliding-window video
windowWidth = 320; % Width in pixels
hImg = imshow(signal(:,1:1 + windowWidth,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
M = size(signal,2);
for k = 1:(M - windowWidth)
set(hImg, 'CData',signal(:,k:k + windowWidth,:))
writeVideo(vid, getframe());
end
close(vid);
The command imagesc is a low-level image command where Suever's proposal does not work.
A general approach to remove padding/margins/background is to use
<plot imshow imagesc ...>
set(gca,'position',[0 0 1 1],'units','normalized')

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.

improve performance of octave plot with many lines

I wonder if there is a faster approach to create a 3D plot of multiple lines. See below for a function that simulates my current approach with some dummy data. Essentially, what I'm doing, is plotting multiple 2D lines next to each other in a 3D space to quickly compare them. Each individual line is colored by its final y value.
function test_plotmany(lines = 1000, points = 100)
# this data comes from a numeric simulation, here I just fill
# it with some dummy values - ignore this
t = [1:points];
data = [];
for i = t;
data(end + 1, :) = [1:lines] .* i;
endfor
# now the actually interesting part that I want to speed up, if possible
tic;
tsize = size(t, 2);
const = ones(tsize, 1);
lines = [1:size(data, 2)];
colors = jet(size(lines, 2));
colormap(colors);
cIdx = 1;
figure
hold on;
for i = lines;
plot3(t, data(1, i) .* const, data(:, i), 'Color', colors(cIdx, :));
cIdx = cIdx + 1;
endfor
xlabel("Foo");
ylabel("Bar");
zlabel("Baz");
grid("on");
view(45, 45);
set(gca, 'XScale', 'linear', 'YScale', 'log', 'ZScale', 'log');
cb = colorbar;
caxis([min(data(tsize, :)), max(data(tsize, :))]);
set(get(cb, 'ylabel'), 'string', 'Something');
hold off;
toc;
endfunction
The outcome for test_plotmany(100, 100) is shown below, and took already 2s. The size of a real data set I have to deal with can be simulated with test_plotmany(10000, 100), which takes minutes on my machine to create.
Is there anything I can do differently to speed this up? Is there maybe a way to create a 3D matrix or such and hand that over to a 3D plot function to recreate my graph? Or could I use multiple threads to render the graph?
Any help would be appreciated, thanks!
Note: I'm using GNU Octave, version 3.8.1 on Linux 3.16.1-1-ARCH with a Intel(R) Core(TM) i3-2310M CPU # 2.10GHz. In Octave, I use the fltk graphics_toolkit - gnuplot does not work for the above at all for me (colors are wrong, cannot interact with the graph to rotate, zoom or pan it).

Resources