Difference between revisions of "Optitrak + Projector touch table/surface"
Line 3: | Line 3: | ||
== Matlab scripts == | == Matlab scripts == | ||
In place of the matlab code for reading in optitrak data, the following matlab | ===Setting the optitrak plane in matlab === | ||
In place of the matlab code for reading in optitrak data, the following matlab function can be used to: | |||
# read in data sent from the optitrak system, and furthermore | # read in data sent from the optitrak system, and furthermore | ||
Line 10: | Line 11: | ||
This function should be called before opening a main window with psychtoolbox. | This function should be called before opening a main window with psychtoolbox. | ||
function [touch_plane_info, client] = opti_setup_touch_plane_srt | |||
%This gives an error (freezes) if the NET assembly is already loaded. In | |||
%that case you need to quit Matlab and start over | |||
if ~IsAssemblyAdded('NatNetML') | |||
Opti = NET.addAssembly('C:\Users\Jim Enns\Documents\MATLAB\NatNetSDK2.2\NatNetSDK\lib\NatNetML.dll'); | |||
end | |||
client = NatNetML.NatNetClientML(1); | |||
%client.Initialize('142.103.0.167','142.103.0.167'); | |||
client.Initialize('142.103.251.175','142.103.251.175'); | |||
data = client.GetLastFrameOfData; | |||
reply = 'N'; | |||
while ~strcmpi(reply,'Y') | |||
answer = {}; | |||
while isempty(answer) | |||
prompt={'Pixel Coords: '}; | |||
name='Lower Left Corner'; | |||
numlines=[1,35]; %this width allows for title to be seen | |||
defaultanswer={'[0 768]'}; | |||
answer=inputdlg(prompt,name,numlines,defaultanswer); | |||
%convert from string to number data for output variables | |||
if ~isempty(answer) | |||
OriginPixelCoords = str2num(answer{1}); | |||
end | |||
end | |||
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y]; | |||
Question = {'LOWER LEFT pre coordinate transform:'... | |||
''... | |||
'Marker 1: ' num2str(pDataDest(1:3))... | |||
''... | |||
'Accept?'... | |||
''}; | |||
ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes'); | |||
switch ButtonName | |||
case 'Yes' | |||
orig_pos = pDataDest; | |||
reply = 'Y'; | |||
case 'No' | |||
reply = 'N'; | |||
case 'Quit' | |||
%quit opto too? | |||
%need to pass quit flag so this actually works? | |||
transform_info = []; | |||
clear all; close all; Screen('CloseAll'); | |||
disp('*** Exiting Program ***'); | |||
return | |||
end | |||
end | |||
%take a point on +ve x axis | |||
reply='N'; | |||
while ~strcmpi(reply,'Y') | |||
answer = {}; | |||
while isempty(answer) | |||
prompt={'Pixel Coords: '}; | |||
name='Lower Right Corner'; | |||
numlines=[1,35]; %this width allows for title to be seen | |||
defaultanswer={'[1024 768]'}; | |||
answer=inputdlg(prompt,name,numlines,defaultanswer); | |||
%convert from string to number data for output variables | |||
if ~isempty(answer) | |||
XAxisPixelCoords = str2num(answer{1}); | |||
end | |||
end | |||
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y]; | |||
Question = {'LOWER RIGHT pre coordinate transform:'... | |||
''... | |||
'Marker 1: ' num2str(pDataDest(1:3))... | |||
''... | |||
'Accept?'... | |||
''}; | |||
ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes'); | |||
switch ButtonName | |||
case 'Yes' | |||
x_axis = pDataDest; | |||
reply = 'Y'; | |||
case 'No' | |||
reply = 'N'; | |||
case 'Quit' | |||
%quit opto too? | |||
%need to pass quit flag so this actually works? | |||
clear all; close all; Screen('CloseAll'); | |||
disp('*** Exiting Program ***'); | |||
return | |||
end | |||
end | |||
% point on the xy plane | |||
reply='N'; | |||
while ~strcmpi(reply,'Y') | |||
answer = {}; | |||
while isempty(answer) | |||
prompt={'Pixel Coords: '}; | |||
name='Upper Left Corner'; | |||
numlines=[1,35]; %this width allows for title to be seen | |||
defaultanswer={'[0 0]'}; | |||
answer=inputdlg(prompt,name,numlines,defaultanswer); | |||
%convert from string to number data for output variables | |||
if ~isempty(answer) | |||
YAxisPixelCoords = str2num(answer{1}); | |||
end | |||
end | |||
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y]; | |||
Question = {'UPPER LEFT pre coordinate transform:'... | |||
''... | |||
'Marker 1: ' num2str(pDataDest(1:3))... | |||
''... | |||
'Accept?'... | |||
''}; | |||
ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes'); | |||
switch ButtonName | |||
case 'Yes' | |||
y_axis = pDataDest; | |||
reply = 'Y'; | |||
case 'No' | |||
reply = 'N'; | |||
case 'Quit' | |||
%quit opto too? | |||
%need to pass quit flag so this actually works? | |||
clear all; close all; Screen('CloseAll'); | |||
disp('*** Exiting Program ***'); | |||
return | |||
end | |||
end | |||
% finish the screen rect (event though this is redundant for establishing | |||
% the plane) | |||
reply='N'; | |||
while ~strcmpi(reply,'Y') | |||
answer = {}; | |||
while isempty(answer) | |||
prompt={'Pixel Coords: '}; | |||
name='Upper Right Corner'; | |||
numlines=[1,35]; %this width allows for title to be seen | |||
defaultanswer={'[1024 0]'}; | |||
answer=inputdlg(prompt,name,numlines,defaultanswer); | |||
%convert from string to number data for output variables | |||
if ~isempty(answer) | |||
OppCornerPixelCoords = str2num(answer{1}); | |||
end | |||
end | |||
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y]; | |||
Question = {'UPPER RIGHT pre coordinate transform:'... | |||
''... | |||
'Marker 1: ' num2str(pDataDest(1:3))... | |||
''... | |||
'Accept?'... | |||
''}; | |||
ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes'); | |||
switch ButtonName | |||
case 'Yes' | |||
opp_corner = pDataDest; | |||
reply = 'Y'; | |||
case 'No' | |||
reply = 'N'; | |||
case 'Quit' | |||
%quit opto too? | |||
%need to pass quit flag so this actually works? | |||
clear all; close all; Screen('CloseAll'); | |||
disp('*** Exiting Program ***'); | |||
return | |||
end | |||
end | |||
%Create the Coordinate Systesm | |||
[T_opto_plane,T_plane_opto]=MakeCoordSystem(orig_pos,x_axis,y_axis); | |||
%Display the new transformed coordinate system | |||
disp('Points in Local Coordinate System are:') | |||
[new_orig]=transform4(T_opto_plane, orig_pos) | |||
[new_x_axis]=transform4(T_opto_plane, x_axis) | |||
[new_y_axis]=transform4(T_opto_plane, y_axis) | |||
[new_opp_corner]=transform4(T_opto_plane, opp_corner) | |||
touch_plane_info.T_opto_plane = double(T_opto_plane); | |||
touch_plane_info.T_plane_opto = double(T_plane_opto); | |||
touch_plane_info.opto_rect = double([new_orig; new_x_axis; new_y_axis; new_opp_corner]); | |||
touch_plane_info.pixel_rect = double([OriginPixelCoords; XAxisPixelCoords; YAxisPixelCoords; OppCornerPixelCoords]); | |||
touch_plane_info.old_opto_rect = double([orig_pos; x_axis; y_axis; opp_corner]); | |||
%calculate the pixel to opto conversion | |||
mm1 = double((new_x_axis(1) - new_orig(1))/(XAxisPixelCoords(1) - OriginPixelCoords(1)) * 1000); | |||
mm2 = double((new_opp_corner(1) - new_y_axis(1))/(OppCornerPixelCoords(1) - YAxisPixelCoords(1)) * 1000); | |||
mm3 = double(-(new_orig(2) - new_y_axis(2))/(OriginPixelCoords(2) - YAxisPixelCoords(2)) * 1000); | |||
mm4 = double(-(new_x_axis(2) - new_opp_corner(2))/(XAxisPixelCoords(2) - OppCornerPixelCoords(2)) * 1000); | |||
touch_plane_info.mmPerPixel = mean ([mm1 mm2 mm3 mm4]); |
Revision as of 18:36, 19 April 2012
Matlab scripts
Setting the optitrak plane in matlab
In place of the matlab code for reading in optitrak data, the following matlab function can be used to:
- read in data sent from the optitrak system, and furthermore
- set the table top plane, as understood by the Optitrak, into variables for reference in matlab, and
- transform the native coordinate system of the optitrak (x z y) into another, possibly more familiar coordinate system (x y z).
This function should be called before opening a main window with psychtoolbox.
function [touch_plane_info, client] = opti_setup_touch_plane_srt
%This gives an error (freezes) if the NET assembly is already loaded. In %that case you need to quit Matlab and start over
if ~IsAssemblyAdded('NatNetML') Opti = NET.addAssembly('C:\Users\Jim Enns\Documents\MATLAB\NatNetSDK2.2\NatNetSDK\lib\NatNetML.dll'); end
client = NatNetML.NatNetClientML(1); %client.Initialize('142.103.0.167','142.103.0.167'); client.Initialize('142.103.251.175','142.103.251.175'); data = client.GetLastFrameOfData;
reply = 'N';
while ~strcmpi(reply,'Y')
answer = {}; while isempty(answer) prompt={'Pixel Coords: '}; name='Lower Left Corner'; numlines=[1,35]; %this width allows for title to be seen defaultanswer={'[0 768]'}; answer=inputdlg(prompt,name,numlines,defaultanswer);
%convert from string to number data for output variables if ~isempty(answer) OriginPixelCoords = str2num(answer{1}); end end
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y];
Question = {'LOWER LEFT pre coordinate transform:'... ... 'Marker 1: ' num2str(pDataDest(1:3))... ... 'Accept?'... }; ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes');
switch ButtonName case 'Yes' orig_pos = pDataDest; reply = 'Y'; case 'No' reply = 'N'; case 'Quit' %quit opto too? %need to pass quit flag so this actually works? transform_info = []; clear all; close all; Screen('CloseAll'); disp('*** Exiting Program ***'); return end
end
%take a point on +ve x axis reply='N'; while ~strcmpi(reply,'Y')
answer = {}; while isempty(answer) prompt={'Pixel Coords: '}; name='Lower Right Corner'; numlines=[1,35]; %this width allows for title to be seen defaultanswer={'[1024 768]'}; answer=inputdlg(prompt,name,numlines,defaultanswer);
%convert from string to number data for output variables if ~isempty(answer) XAxisPixelCoords = str2num(answer{1}); end end
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y];
Question = {'LOWER RIGHT pre coordinate transform:'... ... 'Marker 1: ' num2str(pDataDest(1:3))... ... 'Accept?'... }; ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes');
switch ButtonName case 'Yes' x_axis = pDataDest; reply = 'Y'; case 'No' reply = 'N'; case 'Quit' %quit opto too? %need to pass quit flag so this actually works? clear all; close all; Screen('CloseAll'); disp('*** Exiting Program ***'); return end end
% point on the xy plane reply='N'; while ~strcmpi(reply,'Y')
answer = {}; while isempty(answer) prompt={'Pixel Coords: '}; name='Upper Left Corner'; numlines=[1,35]; %this width allows for title to be seen defaultanswer={'[0 0]'}; answer=inputdlg(prompt,name,numlines,defaultanswer);
%convert from string to number data for output variables if ~isempty(answer) YAxisPixelCoords = str2num(answer{1}); end end
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y];
Question = {'UPPER LEFT pre coordinate transform:'... ... 'Marker 1: ' num2str(pDataDest(1:3))... ... 'Accept?'... }; ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes');
switch ButtonName case 'Yes' y_axis = pDataDest; reply = 'Y'; case 'No' reply = 'N'; case 'Quit' %quit opto too? %need to pass quit flag so this actually works? clear all; close all; Screen('CloseAll'); disp('*** Exiting Program ***'); return end end
% finish the screen rect (event though this is redundant for establishing % the plane) reply='N'; while ~strcmpi(reply,'Y')
answer = {}; while isempty(answer) prompt={'Pixel Coords: '}; name='Upper Right Corner'; numlines=[1,35]; %this width allows for title to be seen defaultanswer={'[1024 0]'}; answer=inputdlg(prompt,name,numlines,defaultanswer);
%convert from string to number data for output variables if ~isempty(answer) OppCornerPixelCoords = str2num(answer{1}); end end
pDataDest = [data.OtherMarkers(1).x data.OtherMarkers(1).z data.OtherMarkers(1).y];
Question = {'UPPER RIGHT pre coordinate transform:'... ... 'Marker 1: ' num2str(pDataDest(1:3))... ... 'Accept?'... }; ButtonName = questdlg(Question, 'Data Check', 'Yes', 'No', 'Quit', 'Yes');
switch ButtonName case 'Yes' opp_corner = pDataDest; reply = 'Y'; case 'No' reply = 'N'; case 'Quit' %quit opto too? %need to pass quit flag so this actually works? clear all; close all; Screen('CloseAll'); disp('*** Exiting Program ***'); return end end
%Create the Coordinate Systesm [T_opto_plane,T_plane_opto]=MakeCoordSystem(orig_pos,x_axis,y_axis);
%Display the new transformed coordinate system disp('Points in Local Coordinate System are:') [new_orig]=transform4(T_opto_plane, orig_pos) [new_x_axis]=transform4(T_opto_plane, x_axis) [new_y_axis]=transform4(T_opto_plane, y_axis) [new_opp_corner]=transform4(T_opto_plane, opp_corner)
touch_plane_info.T_opto_plane = double(T_opto_plane); touch_plane_info.T_plane_opto = double(T_plane_opto); touch_plane_info.opto_rect = double([new_orig; new_x_axis; new_y_axis; new_opp_corner]); touch_plane_info.pixel_rect = double([OriginPixelCoords; XAxisPixelCoords; YAxisPixelCoords; OppCornerPixelCoords]); touch_plane_info.old_opto_rect = double([orig_pos; x_axis; y_axis; opp_corner]);
%calculate the pixel to opto conversion mm1 = double((new_x_axis(1) - new_orig(1))/(XAxisPixelCoords(1) - OriginPixelCoords(1)) * 1000); mm2 = double((new_opp_corner(1) - new_y_axis(1))/(OppCornerPixelCoords(1) - YAxisPixelCoords(1)) * 1000); mm3 = double(-(new_orig(2) - new_y_axis(2))/(OriginPixelCoords(2) - YAxisPixelCoords(2)) * 1000); mm4 = double(-(new_x_axis(2) - new_opp_corner(2))/(XAxisPixelCoords(2) - OppCornerPixelCoords(2)) * 1000); touch_plane_info.mmPerPixel = mean ([mm1 mm2 mm3 mm4]);