The menu command "Volume > Projection > Project Along Z" is really fast as compared to scripting (even with intrinsic variables). Cumulative sum (projection) of a 3D image volume of 512x512x200 in z-direction takes <0.5 sec. as compared to >8 sec. by using script. Is there a direct access this script function other than using ChooseMenuItem()?
Script example showing the difference:
// create an image of 512x512x200, assign random numbers
image img := exprsize(512, 512, 200, random());
img.SetName( "test" );
img.ShowImage();
//
number start_tick, end_tick, calc_time;
// do volume projectin with menu command : Volume>Project>Project Along Z
start_tick = GetHighResTickCount();
ChooseMenuItem( "Volume", "Project", "Project Along Z"); // do z-projection
end_tick = GetHighResTickCount();
// calculate execution time
calc_time = CalcHighResSecondsBetween( start_tick, end_tick );
// display result image
Image img_projZ1 := GetFrontImage();
img_projZ1.SetName( "Z-proj.#1 (" + calc_time.format("%.2fs") + ")");
img_projZ1.ShowImage();
// do volume project in z-direction (using intrinsic variable iplane)
image img_projZ2 := exprsize(512, 512, 0.0);
start_tick = GetHighResTickCount();
img_projZ2[icol, irow, iplane] += img; // do z-projection
end_tick = GetHighResTickCount();
// calculate execution time
calc_time = CalcHighResSecondsBetween( start_tick, end_tick );
// display result image
img_projZ2.SetName( "Z-projection#1 (" + calc_time.format("%.2fs") + ")");
img_projZ2.ShowImage();
Using intrinsic variables is not the fastest way to go about this in scripting. (It used to be in GMS 1 a long time ago.)
In fact, if you do it as a for loop over slices you are a bit faster than with the command menu - most likely due to the overheads of calling that command and tagging the results.
// create an image of 512x512x200, assign random numbers
number sx = 512
number sy = 512
number sz = 200
image img := RealImage("",8,sx,sy,sz)
img = random();
img.SetName( "test" );
img.ShowImage();
number start_tick, end_tick, calc_time;
// do volume projectin with menu command : Volume>Project>Project Along Z
start_tick = GetHighResTickCount();
ChooseMenuItem( "Volume", "Project", "Project Along Z"); // do z-projection
end_tick = GetHighResTickCount();
// calculate execution time
calc_time = CalcHighResSecondsBetween( start_tick, end_tick );
// display result image
Image img_projZ1 := GetFrontImage();
img_projZ1.SetName( "Z-proj.#1 (" + calc_time.format("%.2fs") + ")");
img_projZ1.ShowImage();
// do volume project in z-direction (using intrinsic variable iplane)
image img_projZ2 := img_projZ1.ImageClone()
img_projZ2 = 0
start_tick = GetHighResTickCount();
for(number i=0; i<sz; i++)
img_projZ2 += img.slice2(0,0,i,0,sx,1,1,sy,1)
end_tick = GetHighResTickCount();
// calculate execution time
calc_time = CalcHighResSecondsBetween( start_tick, end_tick );
// display result image
img_projZ2.SetName( "Z-projection#1 (" + calc_time.format("%.2fs") + ")");
img_projZ2.ShowImage();
However, to answer your questions for a command: GMS 3.4 has a command
called:
RealImage Project( BasicImage img, Number axis )
RealImage Project( BasicImage img, Number axis, Boolean rescale )
void Project( BasicImage img, BasicImage dst, Number axis )
void Project( BasicImage img, BasicImage dst, Number axis, Boolean rescale )
But this command is not officially documented, so it might be renamed/removed at any time.
Related
I am using cv2.VideoCapture and cv2.imwrite to convert a video into an image sequence in Google colab using this:
import cv2
vidcap = cv2.VideoCapture('video.mp4')
def getFrame(sec):
vidcap.set(cv2.CAP_PROP_POS_MSEC,sec*1000)
hasFrames,image = vidcap.read()
if hasFrames:
cv2.imwrite("image"+str(count)+".jpg", image) # save frame as JPG file
return hasFrames
sec = 0
frameRate = 0.5 #//it will capture image in each 0.5 second
count=1
success = getFrame(sec)
while success:
count = count + 1
sec = sec + frameRate
sec = round(sec, 2)
success = getFrame(sec)
Instead of writing each image to my session files, how would I add each image to a frames[] array that could be further processed?
There are some old animations that I want to reuse, but the old animation use different axis (For example: old: Face negative Z, Y as up; new: Face Y, Negative Z as up). So I fix this by grouping the animation and rotate the group so that it faces the right axis. But when I ungroup, it's only work for current frame (I turn Auto key on).
I have search several forums:
Grouping animated objects, Scaling, Ungrouping
Need help maintaining offset during ungroup
ungrouping but keeping animation
Grouping animated objects, Scaling, Ungrouping
But nothing works.
Ok, it works for the current frame when you ungroup. So to make it work for the entire animation, you can group & un-group for all the frames. Of course I won't do it by hand but I'll do it with script.
proc GetPlaybackRange(string $bone, int $outStartEndTime[])
{
float $arrKey[] = `keyframe -q $bone`;
$arrKeyLength=size($arrKey);
$outStartEndTime[0] = floor($arrKey[0]);
$outStartEndTime[1] = ceil($arrKey[$arrKeyLength-1]);
}
proc UngroupAndGroupNextFrame(int $frame, string $groupName, float $transform[])
{
currentTime $frame ;
ungroup;
currentTime ($frame + 1) ;
group -n $groupName;
xform -worldSpace -matrix
$transform[0]
$transform[1]
$transform[2]
$transform[3]
$transform[4]
$transform[5]
$transform[6]
$transform[7]
$transform[8]
$transform[9]
$transform[10]
$transform[11]
$transform[12]
$transform[13]
$transform[14]
$transform[15]
$groupName;
}
proc UnGroupForAnimation()
{
string $sel[]= `ls -sl`;
string $groupName = $sel[0];
float $transform[];
$transform = `xform -q -worldSpace -matrix $groupName`;
string $bone[] = `listRelatives -children $groupName`;
int $startEndTime[];
GetPlaybackRange($bone[0], $startEndTime);
for($i = $startEndTime[0]; $i <= $startEndTime[1]; $i++)
{
UngroupAndGroupNextFrame($i, $groupName, $transform);
}
currentTime ($startEndTime[1] + 1) ;
ungroup;
timeSliderClearKey;
print ($bone[0] + " range "+$startEndTime[0]+" : "+$startEndTime[1]);
}
UnGroupForAnimation();
Usage of the script:
Step 1. Select the group (the children of the group should be the bone)
Step 2. Run the script.
And that's it.
I've created a program for a project that tests images against one another to see whether or not it's the same image or not. I've decided to use correlation since the images I am using are styled in the same way and with this, I've been able to get everything working up to this point.
I now wish to create an array of images again, but this time, in order of their correlation. So for example, if I'm testing a 50 pence coin and I test 50 images against the 50 pence coin, I want the highest 5 correlations to be stored into an array, which can then be used for later use. But I'm unsure how to do this as each item in the array will need to have more than one variable, which will be the image location/name of the image and it's correlation percentage.
%Program Created By Ben Parry, 2016.
clc(); %Simply clears the console window
%Targets the image the user picks
inputImage = imgetfile();
%Targets all the images inside this directory
referenceFolder = 'M:\Project\MatLab\Coin Image Processing\Saved_Images';
if ~isdir(referenceFolder)
errorMessage = print('Error: Folder does not exist!');
uiwait(warndlg(errorMessage)); %Displays an error if the folder doesn't exist
return;
end
filePattern = fullfile(referenceFolder, '*.jpg');
jpgFiles = dir(filePattern);
for i = 1:length(jpgFiles)
baseFileName = jpgFiles(i).name;
fullFileName = fullfile(referenceFolder, baseFileName);
fprintf(1, 'Reading %s\n', fullFileName);
imageArray = imread(fullFileName);
imshow(imageArray);
firstImage = imread(inputImage); %Reading the image
%Converting the images to Black & White
firstImageBW = im2bw(firstImage);
secondImageBW = im2bw(imageArray);
%Finding the correlation, then coverting it into a percentage
c = corr2(firstImageBW, secondImageBW);
corrValue = sprintf('%.0f%%',100*c);
%Custom messaging for the possible outcomes
corrMatch = sprintf('The images are the same (%s)',corrValue);
corrUnMatch = sprintf('The images are not the same (%s)',corrValue);
%Looping for the possible two outcomes
if c >=0.99 %Define a percentage for the correlation to reach
disp(' ');
disp('Images Tested:');
disp(inputImage);
disp(fullFileName);
disp (corrMatch);
disp(' ');
else
disp(' ');
disp('Images Tested:');
disp(inputImage);
disp(fullFileName);
disp(corrUnMatch);
disp(' ' );
end;
imageArray = imread(fullFileName);
imshow(imageArray);
end
You can use struct() function to create structures.
Initializing an array of struct:
imStruct = struct('fileName', '', 'image', [], 'correlation', 0);
imData = repmat(imStruct, length(jpgFiles), 1);
Setting field values:
for i = 1:length(jpgFiles)
% ...
imData(i).fileName = fullFileName;
imData(i).image = imageArray;
imData(i).correlation = corrValue;
end
Extract values of correlation field and select 5 highest correlations:
corrList = [imData.correlation];
[~, sortedInd] = sort(corrList, 'descend');
selectedData = imData(sortedInd(1:5));
My project is "optical flow estimation for flame detection in videos" In that while extracting feature values, I can only retain the last intensity value of the frame.
Here is my code
function [Iy, Ix, It] = grad3D(imNew,bFineScale,bInitialize)
persistent siz gx gg imPrev;
if nargin>2 && bInitialize
[gx, gg]= makeFilters();
if bFineScale
siz = size(imNew);
imPrev= single(imNew);
else% if ~bFineScale
siz = floor(size(imNew)/2);
%initialize imPrev to half the size
imPrev = imresizeNN(single(imNew),siz);
end
end
if ~bFineScale
imNew = imresizeNN(conv2(single(imNew),gg,'same'),siz);
else imNew = single(imNew);
end
Ix = conv2(gg,gx,imNew + imPrev,'same');
Iy = conv2(gx,gg,imNew + imPrev,'same');
It = conv2(gg,gg,imNew - imPrev,'same'); %L3
% finally, store away the current image for use on next frame
imPrev = imNew;
testfeature = mean(imPrev);
save testfeature testfeature
[gx, gg]= makeFilters() x = (-1:1);
gg = single(gaussgen(0.67,3));
gx = single(-x.*gg*3);
In the highlighted coding(testfeature=mean(imprev)). I can be able to get only the intensity value of last frame extracted...But i need the values for all the extracted frames. I need the value to be stored row wise in a matrix file.
I wrote a script that returns several text boxes in a figure. The text boxes are moveable (I can drag and drop them), and their positions are predetermined by the data in an input matrix (the data from the input matrix is applied to the respective positions of the boxes by nested for loop). I want to create a matrix which is initially a copy of the input matrix, but is UPDATED as I change the positions of the boxes by dragging them around. How would I update their positions? Here's the entire script
function drag_drop=drag_drop(tsinput,infoinput)
[x,~]=size(tsinput);
dragging = [];
orPos = [];
fig = figure('Name','Docker Tool','WindowButtonUpFcn',#dropObject,...
'units','centimeters','WindowButtonMotionFcn',#moveObject,...
'OuterPosition',[0 0 25 30]);
% Setting variables to zero for the loop
plat_qty=0;
time_qty=0;
k=0;
a=0;
% Start loop
z=1:2
for idx=1:x
if tsinput(idx,4)==1
color='red';
else
color='blue';
end
a=tsinput(idx,z);
b=a/100;
c=floor(b); % hours
d=c*100;
e=a-d; % minutes
time=c*60+e; % time quantity to be used in 'position'
time_qty=time/15;
plat_qty=tsinput(idx,3)*2;
box=annotation('textbox','units','centimeters','position',...
[time_qty plat_qty 1.5 1.5],'String',infoinput(idx,z),...
'ButtonDownFcn',#dragObject,'BackgroundColor',color);
% need to new=get(box,'Position'), fill out matrix OUT of loop
end
fillmenu=uicontextmenu;
hcb1 = 'set(gco, ''BackgroundColor'', ''red'')';
hcb2 = 'set(gco, ''BackgroundColor'', ''blue'')';
item1 = uimenu(fillmenu, 'Label', 'Train Full', 'Callback', hcb1);
item2 = uimenu(fillmenu, 'Label', 'Train Empty', 'Callback', hcb2);
hbox=findall(fig,'Type','hggroup');
for jdx=1:x
set(hbox(jdx),'uicontextmenu',fillmenu);
end
end
new_arr=tsinput;
function dragObject(hObject,eventdata)
dragging = hObject;
orPos = get(gcf,'CurrentPoint');
end
function dropObject(hObject,eventdata,box)
if ~isempty(dragging)
newPos = get(gcf,'CurrentPoint');
posDiff = newPos - orPos;
set(dragging,'Position',get(dragging,'Position') + ...
[posDiff(1:2) 0 0]);
dragging = [];
end
end
function moveObject(hObject,eventdata)
if ~isempty(dragging)
newPos = get(gcf,'CurrentPoint');
posDiff = newPos - orPos;
orPos = newPos;
set(dragging,'Position',get(dragging,'Position') + [posDiff(1:2) 0 0]);
end
end
end
% Testing purpose input matrices:
% tsinput=[0345 0405 1 1 ; 0230 0300 2 0; 0540 0635 3 1; 0745 0800 4 1]
% infoinput={'AJ35 NOT' 'KL21 MAN' 'XPRES'; 'ZW31 MAN' 'KM37 NEW' 'VISTA';
% 'BC38 BIR' 'QU54 LON' 'XPRES'; 'XZ89 LEC' 'DE34 MSF' 'DERP'}
If I understand you correctly (and please post some code if I'm not), then all you need is indeed a set/get combination.
If boxHandle is a handle to the text-box object, then you get its current position by:
pos = get (boxHandle, 'position')
where pos is the output array of [x, y, width, height].
In order to set to a new position, you use:
set (boxHandle, 'position', newPos)
where newPos is the array of desired position (with the same structure as pos).
EDIT
Regarding to updating your matrix, since you have the handle of the object you move, you actually DO have access to the specific text box.
When you create each text box, set a property called 'UserData' with the associated indices of tsinput used for that box. In your nested for loop add this
set (box, 'UserData', [idx, z]);
after the box is created, and in your moveObject callback get the data by
udata = get(dragging,'UserData');
Then udata contains the indices of the elements you want to update.