source: trunk/src/geometry_calib.m @ 1012

Last change on this file since 1012 was 1011, checked in by sommeria, 6 years ago

series REFRESH improved

File size: 65.1 KB
Line 
1%'geometry_calib': associated to the GUI geometry_calib to perform geometric calibration from a set of reference points
2%------------------------------------------------------------------------
3% function hgeometry_calib = geometry_calib(inputfile,pos)
4%
5%OUTPUT:
6% hgeometry_calib=current handles of the GUI geometry_calib.fig
7%
8%INPUT:
9% inputfile: (optional) name of an xml file containing coordinates of reference points
10% pos: (optional) 4 element vector setting the 'Position' of the GUI
11
12%=======================================================================
13% Copyright 2008-2017, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
14%   http://www.legi.grenoble-inp.fr
15%   Joel.Sommeria - Joel.Sommeria (A) legi.cnrs.fr
16%
17%     This file is part of the toolbox UVMAT.
18%
19%     UVMAT is free software; you can redistribute it and/or modify
20%     it under the terms of the GNU General Public License as published
21%     by the Free Software Foundation; either version 2 of the license,
22%     or (at your option) any later version.
23%
24%     UVMAT is distributed in the hope that it will be useful,
25%     but WITHOUT ANY WARRANTY; without even the implied warranty of
26%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27%     GNU General Public License (see LICENSE.txt) for more details.
28%=======================================================================
29
30function varargout = geometry_calib(varargin)
31% GEOMETRY_CALIB M-file for geometry_calib.fig
32%      GEOMETRY_CALIB, by itself, creates a MenuCoord GEOMETRY_CALIB or raises the existing
33%      singleton*.
34%
35%      H = GEOMETRY_CALIB returns the handle to a MenuCoord GEOMETRY_CALIB or the handle to
36%      the existing singleton*.
37%
38%      GEOMETRY_CALIB('CALLBACK',hObject,eventData,handles,...) calls the local
39%      function named CALLBACK in GEOMETRY_CALIB.M with the given input arguments.
40%
41%      GEOMETRY_CALIB('Property','Value',...) creates a MenuCoord GEOMETRY_CALIB or raises the
42%      existing singleton*.  Starting from the left, property value pairs are
43%      applied to the GUI before geometry_calib_OpeningFunction gets called.  An
44%      unrecognized property name or invalid value makes property application
45%      stop.  All inputs are passed to geometry_calib_OpeningFcn via varargin.
46%
47%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
48%      instance to run (singleton)".
49%
50% See also: GUIDE, GUIDATA, GUIHANDLES
51
52% Edit the above text to modify the response to help geometry_calib
53
54% Last Modified by GUIDE v2.5 16-Apr-2015 17:29:02
55
56% Begin initialization code - DO NOT edit
57gui_Singleton = 1;
58gui_State = struct('gui_Name',       mfilename, ...
59                   'gui_Singleton',  gui_Singleton, ...
60                   'gui_OpeningFcn', @geometry_calib_OpeningFcn, ...
61                   'gui_OutputFcn',  @geometry_calib_OutputFcn, ...
62                   'gui_LayoutFcn',  [] , ...
63                   'gui_Callback',   []);
64if nargin
65   [pp,ff]=fileparts(which(varargin{1})); % name of the input file
66   if strcmp(ff,mfilename)% if we are activating a sub-function of geometry_calib
67   % ~isempty(regexp(varargin{1},'_Callback','once'))
68    gui_State.gui_Callback = str2func(varargin{1});
69   end
70end
71
72if nargout
73    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
74else
75    gui_mainfcn(gui_State, varargin{:});
76end
77% End initialization code - DO NOT edit
78
79
80% --- Executes just before geometry_calib is made visible.
81%INPUT:
82%handles: handles of the geometry_calib interface elements
83% PlotHandles: set of handles of the elements contolling the plotting
84% parameters on the uvmat interface (obtained by 'get_plot_handle.m')
85%------------------------------------------------------------------------
86function geometry_calib_OpeningFcn(hObject, eventdata, handles,inputfile)
87%------------------------------------------------------------------------
88% Choose default command line output for geometry_calib
89
90handles.output = hObject;
91
92% Update handles structure
93guidata(hObject, handles);
94set(hObject,'DeleteFcn',{@closefcn})%
95%set(hObject,'WindowButtonDownFcn',{'mouse_alt_gui',handles}) % allows mouse action with right button (zoom for uicontrol display)
96
97%% position
98set(0,'Unit','pixels')
99ScreenSize=get(0,'ScreenSize');% get the size of the screen, to put the fig on the upper right
100Left=ScreenSize(3)- 460; %right edge close to the right, with margin=40 (GUI width=420 px)
101if ScreenSize(4)>920
102    Height=840;%default height of the GUI
103    Bottom=ScreenSize(4)-Height-40; %put fig at top right
104else
105    Height=ScreenSize(4)-80;
106    Bottom=40; % GUI lies o the screen bottom (with margin =40)
107end
108set(handles.calib_type,'Position',[1 Height-40 194 30])%  rank 1
109set(handles.APPLY,'Position',[197 Height-40 110 30])%  rank 1
110set(handles.REPLICATE,'Position',[309 Height-40 110 30])%  rank 1
111set(handles.Intrinsic,'Position',[1 Height-40-2-92 418 92])%  rank 2
112set(handles.Extrinsic,'Position',[1 Height-40-4-92-75 418 75])%  rank 3
113set(handles.PointLists,'Position',[1 Height-40-6-92-75-117 418 117]) %  rank 4
114set(handles.CheckEnableMouse,'Position',[3 Height-362 208 30])%  rank 5
115set(handles.PLOT,'Position',[3 Height-394 120 30])%  rank 6
116set(handles.Copy,'Position',[151 Height-394 120 30])%  rank 6
117set(handles.ClearAll,'Position',[297 Height-394 120 30])%  rank 6
118set(handles.ClearPoint,'Position',[297 Height-362 120 30])%  rank 6
119set(handles.CoordLine,'Position',[211 Height-362 86 30])%  rank 6
120set(handles.phys_title,'Position',[38 Height-426 125 20])%  rank 7
121set(handles.CoordUnit,'Position',[151 Height-426 120 30])%  rank 7
122set(handles.px_title,'Position',[272 Height-426 125 20])%  rank 7
123set(handles.ListCoord,'Position',[1 20 418 Height-446])% rank 8
124set(handles.geometry_calib,'Position',[Left Bottom 420 Height])
125
126%set menu of calibration options
127set(handles.calib_type,'String',{'rescale';'linear';'3D_linear';'3D_quadr';'3D_extrinsic'})
128if exist('inputfile','var')&& ~isempty(inputfile)
129    [RootPath,SubDir,RootFile,tild,tild,tild,tild,FileExt]=fileparts_uvmat(inputfile);
130    struct.XmlInputFile=find_imadoc(RootPath,SubDir,RootFile,FileExt);
131    set(handles.ListCoord,'Data',[])
132    if exist(struct.XmlInputFile,'file')
133        Heading=loadfile(handles,struct.XmlInputFile);% load data from the xml file and fill the GUI
134        if isfield(Heading,'Campaign')&& ischar(Heading.Campaign)
135            struct.Campaign=Heading.Campaign;
136        end
137    end   
138    set(hObject,'UserData',struct)
139end
140
141%------------------------------------------------------------------------
142% --- Outputs from this function are returned to the command line.
143function varargout = geometry_calib_OutputFcn(~, eventdata, handles)
144%------------------------------------------------------------------------
145% Get default command line output from handles structure
146varargout{1} = handles.output;
147varargout{2}=handles;
148%
149%------------------------------------------------------------------------
150% executed when closing: set the parent interface button to value 0
151function closefcn(gcbo,eventdata)
152%------------------------------------------------------------------------
153huvmat=findobj(allchild(0),'Name','uvmat');
154if ~isempty(huvmat)
155    handles=guidata(huvmat);
156    set(handles.MenuCalib,'Checked','off')
157    hobject=findobj(handles.PlotAxes,'tag','calib_points');
158    if ~isempty(hobject)
159        delete(hobject)
160    end
161    hobject=findobj(handles.PlotAxes,'tag','calib_marker');
162    if ~isempty(hobject)
163        delete(hobject)
164    end   
165end
166
167%------------------------------------------------------------------------
168% --- Executes on button press APPLY (used to launch the calibration).
169function APPLY_Callback(hObject, eventdata, handles)
170set(handles.CheckEnableMouse,'Value',0)% desactivate mouse (to avoid spurious creation of new points)
171
172%------------------------------------------------------------------------
173%% look for the GUI uvmat and check for an image as input
174set(handles.APPLY,'BackgroundColor',[1 1 0])% paint APPLY button in yellow to show activation
175huvmat=findobj(allchild(0),'Name','uvmat');% look for the GUI uvmat
176hhuvmat=guidata(huvmat);%handles of elements in the GUI uvmat
177if ~strcmp(get(hhuvmat.Scalar,'Visible'),'on')
178    msgbox_uvmat('ERROR','An image needs to be opened in uvmat for calibration')
179  return
180end
181
182RootPath='';
183if ~isempty(hhuvmat.RootPath)&& ~isempty(hhuvmat.RootFile)
184    RootPath=get(hhuvmat.RootPath,'String');% path to the currently displayed image
185    SubDirBase=regexprep(get(hhuvmat.SubDir,'String'),'\..+$','');
186    outputfile=[fullfile(RootPath,SubDirBase) '.xml'];%xml file associated with the currently displayed image
187else
188    question={'save the calibration data and point coordinates in'};
189    def={fullfile(RootPath,'ObjectCalib.xml')};
190    options.Resize='on';
191    answer=inputdlg(question,'',1,def,options);
192    outputfile=answer{1};
193end
194
195%% read coordinates of the calibration poinnts: Coord(:,1-3) in phys, Coord(:,4-5) image
196Coord=get(handles.ListCoord,'Data');
197
198 
199%% read the type of calibration
200calib_cell=get(handles.calib_type,'String');
201val=get(handles.calib_type,'Value');
202CalibFcn=['calib_' calib_cell{val}];
203
204%% read the intrinsic parameters
205Intrinsic.Npx=str2num(get(hhuvmat.num_Npx,'String'));
206Intrinsic.Npy=str2num(get(hhuvmat.num_Npy,'String'));
207Intrinsic.coord_files=get(handles.ListCoordFiles,'String');
208Intrinsic.fx=str2num(get(handles.fx,'String'));
209Intrinsic.fy=str2num(get(handles.fy,'String'));
210Intrinsic.kc=str2num(get(handles.kc,'String'));
211Intrinsic.Cx=str2num(get(handles.Cx,'String'));
212Intrinsic.Cy=str2num(get(handles.Cy,'String'));
213if isempty(Intrinsic.kc)
214    Intrinsic.kc=0;
215end
216if isempty(Intrinsic.Cx)||isempty(Intrinsic.Cy)
217    Intrinsic.Cx=Intrinsic.Npx/2;
218    Intrinsic.Cy=Intrinsic.Npy/2;
219end 
220
221%% Apply calibration
222[GeometryCalib,index,ind_removed,Z_plane]=calibrate(Coord,CalibFcn,Intrinsic);% apply calibration
223
224%% record the coordinate unit
225unitlist=get(handles.CoordUnit,'String');
226unit=unitlist{get(handles.CoordUnit,'value')};
227GeometryCalib.CoordUnit=unit;
228
229%% record the coordinates of the calibration points
230GeometryCalib.SourceCalib.PointCoord=Coord;
231
232%% display calibration results on the GUI geometry_calib
233display_intrinsic(GeometryCalib,handles)%display calibration intrinsic parameters
234display_extrinsic(GeometryCalib,handles)%display calibration extrinsic parameters
235%     (rotation and translation of camera with  respect to the phys coordinates)
236
237%% store the calibration data, by default in the xml file of the currently displayed image
238answer=msgbox_uvmat('INPUT_Y-N',{'store calibration data';...
239    ['Error rms (along x,y)=' num2str(GeometryCalib.ErrorRms) ' pixels'];...
240    ['Error max (along x,y)=' num2str(GeometryCalib.ErrorMax) ' pixels'];
241    [num2str(numel(ind_removed)) ' points removed']});
242if strcmp(answer,'Yes') %store the calibration data
243    if strcmp(calib_cell{val}(1:2),'3D')%set the plane position for 3D (projection) calibration
244        msgbox_uvmat('CONFIRMATION',{['The current image series is assumed by default in the plane of the calib points z=' num2str(Z_plane) ] ; 'can be modified by MenuSetSlice in the upper bar menu of uvmat'})
245        GeometryCalib.SliceCoord=Z_plane'*[0 0 1];
246    end   
247else
248    GeometryCalib=[];
249    index=1;
250end
251
252if isempty(GeometryCalib) % if calibration cancelled
253    set(handles.APPLY,'BackgroundColor',[1 0 1])
254else   % if calibration confirmed
255   
256    %% copy the xml file from the old location if appropriate, then update with the calibration parameters
257    if ~exist(outputfile,'file') && ~isempty(SubDirBase)
258        oldxml=[fullfile(RootPath,SubDirBase,get(hhuvmat.RootFile,'String')) '.xml'];
259        if exist(oldxml,'file')
260            [success,message]=copyfile(oldxml,outputfile);%copy the old xml file to a new one with the new convention
261        end
262    end
263    errormsg=update_imadoc(GeometryCalib,outputfile,'GeometryCalib');% introduce the calibration data in the xml file
264    if ~strcmp(errormsg,'')
265        msgbox_uvmat('ERROR',errormsg);
266    end
267   
268    %% display image with new calibration in the currently opened uvmat interface
269    FieldList=get(hhuvmat.FieldName,'String');
270    val=get(hhuvmat.FieldName,'Value');
271    if strcmp(FieldList{val},'image')
272        set(hhuvmat.CheckFixLimits,'Value',0)% put FixedLimits option to 'off' to plot the whole image
273        UserData=get(handles.geometry_calib,'UserData');
274        UserData.XmlInputFile=outputfile;%save the current xml file name
275        set(handles.geometry_calib,'UserData',UserData)
276        uvmat('InputFileREFRESH_Callback',hObject,eventdata,hhuvmat); %file input with xml reading  in uvmat, show the image in phys coordinates
277        PLOT_Callback(hObject, eventdata, handles)
278        set(handles.CoordLine,'string',num2str(index))
279        Coord=get(handles.ListCoord,'Data');
280        update_calib_marker(Coord(index,:)); %indicate the point with max deviations from phys coord to calibration
281        figure(handles.geometry_calib)% put the GUI geometry_calib in front
282        set(handles.APPLY,'BackgroundColor',[1 0 0]) % set APPLY button to red color
283    else
284        msgbox_uvmat('WARNING','open the image to see the effect of the new calibration')
285    end
286end
287
288%------------------------------------------------------------------------
289% --- Executes on button press in REPLICATE
290function REPLICATE_Callback(hObject, eventdata, handles)
291%------------------------------------------------------------------------
292set(handles.CheckEnableMouse,'Value',0)% desactivate mouse (to avoid spurious creation of new points)
293
294%% look for the GUI uvmat and check for an image as input
295huvmat=findobj(allchild(0),'Name','uvmat');
296hhuvmat=guidata(huvmat);%handles of elements in the GUI uvmat
297
298%% read coordinates of the calibration poinnts: Coord(:,1-3) in phys, Coord(:,4-5) image
299Coord=get(handles.ListCoord,'Data');
300 
301%% read the type of calibration
302calib_cell=get(handles.calib_type,'String');
303val=get(handles.calib_type,'Value');
304CalibFcn=['calib_' calib_cell{val}];
305
306%% read the intrinsic parameters
307Intrinsic.Npx=str2num(get(hhuvmat.num_Npx,'String'));
308Intrinsic.Npy=str2num(get(hhuvmat.num_Npy,'String'));
309Intrinsic.coord_files=get(handles.ListCoordFiles,'String');
310Intrinsic.fx=str2num(get(handles.fx,'String'));
311Intrinsic.fy=str2num(get(handles.fy,'String'));
312Intrinsic.kc=str2num(get(handles.kc,'String'));
313Intrinsic.Cx=str2num(get(handles.Cx,'String'));
314Intrinsic.Cy=str2num(get(handles.Cy,'String'));
315if isempty(Intrinsic.kc)
316    Intrinsic.kc=0;
317end
318if isempty(Intrinsic.Cx)||isempty(Intrinsic.Cy)
319    Intrinsic.Cx=Intrinsic.Npx/2;
320    Intrinsic.Cy=Intrinsic.Npy/2;
321end
322
323%% apply to cropped images if requested
324answer=msgbox_uvmat('INPUT_Y-N','apply to cropped images?');
325if strcmp(answer,'Yes')
326    prompt = {'npy_lower'};
327    dlg_title = 'remove image the npy_lower image lines (removal of the upper linedoes not change calibration)';
328    num_lines= 1;
329    def     = {'0'};
330    answer = inputdlg(prompt,dlg_title,num_lines,def);
331    npy_crop=str2num(answer{1});
332    Intrinsic.Npy=Intrinsic.Npy-npy_crop; %size of the filtering window
333    Coord(:,5)=Coord(:,5)-npy_crop;% shift the image ordinates of the calibration points by removing the lower band
334end
335
336%% Apply calibration
337[GeometryCalib,index,ind_removed,Z_plane]=calibrate(Coord,CalibFcn,Intrinsic);% apply calibration
338
339
340%% record the coordinate unit
341unitlist=get(handles.CoordUnit,'String');
342unit=unitlist{get(handles.CoordUnit,'value')};
343GeometryCalib.CoordUnit=unit;
344
345%% record the coordinates of the calibration points
346GeometryCalib.SourceCalib.PointCoord=Coord;
347
348%% display calibration results on the GUI geometry_calib
349display_intrinsic(GeometryCalib,handles)%display calibration intrinsic parameters
350display_extrinsic(GeometryCalib,handles)%display calibration extrinsic parameters
351%     (rotation and translation of camera with  respect to the phys coordinates)
352
353%% store the calibration data, by default in the xml file of the currently displayed image
354answer=msgbox_uvmat('INPUT_Y-N',{'store calibration data';...
355    ['Error rms (along x,y)=' num2str(GeometryCalib.ErrorRms) ' pixels'];...
356    ['Error max (along x,y)=' num2str(GeometryCalib.ErrorMax) ' pixels'];...
357    [num2str(numel(ind_removed)) ' points removed']});
358if strcmp(answer,'Yes') %store the calibration data
359    if strcmp(calib_cell{val}(1:2),'3D')%set the plane position for 3D (projection) calibration
360        msgbox_uvmat('CONFIRMATION',{['The current image series is assumed by default in the plane of the calib points z=' num2str(Z_plane) ] ; 'can be modified by MenuSetSlice in the upper bar menu of uvmat'})
361        GeometryCalib.SliceCoord=Z_plane'*[0 0 1];
362    end   
363else
364    GeometryCalib=[];
365    index=1;
366end
367
368%% open the GUI browse_data
369CalibData=get(handles.geometry_calib,'UserData');%read the calibration image source on the interface userdata
370if isfield(CalibData,'XmlInputFile')
371    InputDir=fileparts(fileparts(CalibData.XmlInputFile));
372end
373DataSeries=uigetfile_uvmat('open a folder of images to calibrate',InputDir,'uigetdir');
374%SubProject=uigetfile_uvmat('open folder of subproject to calibrate',InputDir,'uigetdir');
375OutPut=browse_data(DataSeries);
376nbcalib=0;
377for ilist=1:numel(OutPut.Experiment)
378    SubDirBase=regexprep(OutPut.DataSeries{1},'\..+$','');
379    XmlName=fullfile(OutPut.Campaign,OutPut.Experiment{ilist},[SubDirBase '.xml']);
380    dispmessage=' created with calibration parameters';
381    % copy the xml file from the old location if appropriate, then update with the calibration parameters
382    if ~exist(XmlName,'file') && ~isempty(SubDirBase)
383        oldxml=fullfile(OutPut.Campaign,OutPut.Experiment{ilist},SubDirBase,[get(hhuvmat.RootFile,'String') '.xml']);
384        if exist(oldxml,'file')
385            [success,message]=copyfile(oldxml,XmlName);%copy the old xml file to a new one with the new convention
386            dispmessage=' updated with calibration parameters';
387        end
388    end
389    errormsg=update_imadoc(GeometryCalib,XmlName,'GeometryCalib');% introduce the calibration data in the xml file
390    if ~strcmp(errormsg,'')
391        msgbox_uvmat('ERROR',errormsg);
392    else
393        display([XmlName dispmessage])
394        nbcalib=nbcalib+1;
395    end
396end
397msgbox_uvmat('CONFIMATION',[SubDirBase ' calibrated for ' num2str(nbcalib) ' experiments']);
398
399%------------------------------------------------------------------------
400% --- activate calibration and store parameters in ouputfile .
401function [GeometryCalib,ind_max,ind_removed,Z_plane]=calibrate(Coord,CalibFcn,Intrinsic)
402%------------------------------------------------------------------------
403
404index=[];
405GeometryCalib=[];
406% apply the calibration, whose type is selected in  handles.calib_type
407if ~isempty(Coord)
408    GeometryCalib=feval(CalibFcn,Coord,Intrinsic);
409else
410    msgbox_uvmat('ERROR','No calibration points, abort')
411end
412if isempty(GeometryCalib)
413    return
414end
415Z_plane=[];
416
417% estimate calibration error rms and max
418X=Coord(:,1);
419Y=Coord(:,2);
420Z=Coord(:,3);
421x_ima=Coord(:,4);
422y_ima=Coord(:,5);
423[Xpoints,Ypoints]=px_XYZ(GeometryCalib,X,Y,Z);
424GeometryCalib.ErrorRms(1)=sqrt(mean((Xpoints-x_ima).*(Xpoints-x_ima)));
425GeometryCalib.ErrorRms(2)=sqrt(mean((Ypoints-y_ima).*(Ypoints-y_ima)));
426[ErrorMax(1),index(1)]=max(abs(Xpoints-x_ima));
427[ErrorMax(2),index(2)]=max(abs(Ypoints-y_ima));
428[tild,ind_dim]=max(ErrorMax);
429ind_max=index(ind_dim); % mark the index with maximum deviation
430
431% detect bad calibration points, marked by indices ind_bad, if the
432% difference of actual image coordinates and those given by calibration is
433% greater than 2 pixels and greater than 4 rms.
434check_x=abs(Xpoints-x_ima)>max(2,3*GeometryCalib.ErrorRms(1));
435check_y=abs(Ypoints-y_ima)>max(2,3*GeometryCalib.ErrorRms(2));
436ind_removed=find(check_x | check_y)
437% repeat calibration without the excluded points:
438if ~isempty(ind_removed)
439    Coord(ind_removed,:)=[];
440    GeometryCalib=feval(CalibFcn,Coord,Intrinsic);
441    X=Coord(:,1);
442    Y=Coord(:,2);
443    Z=Coord(:,3);
444    x_ima=Coord(:,4);
445    y_ima=Coord(:,5);
446    [Xpoints,Ypoints]=px_XYZ(GeometryCalib,X,Y,Z);
447    GeometryCalib.ErrorRms(1)=sqrt(mean((Xpoints-x_ima).*(Xpoints-x_ima)));
448    GeometryCalib.ErrorRms(2)=sqrt(mean((Ypoints-y_ima).*(Ypoints-y_ima)));
449end
450GeometryCalib.ErrorMax=ErrorMax;
451%set the Z position of the reference plane used for calibration
452if isequal(max(Z),min(Z))%Z constant
453    Z_plane=Z(1);
454    GeometryCalib.NbSlice=1;
455    GeometryCalib.SliceCoord=[0 0 Z_plane];
456end
457
458
459%------------------------------------------------------------------------
460% --- determine the parameters for a calibration by an affine function (rescaling and offset, no rotation)
461function GeometryCalib=calib_rescale(Coord,Intrinsic)
462%------------------------------------------------------------------------
463X=Coord(:,1);
464Y=Coord(:,2);% Z not used
465x_ima=Coord(:,4);
466y_ima=Coord(:,5);
467[px]=polyfit(X,x_ima,1);
468[py]=polyfit(Y,y_ima,1);
469% T_x=px(2);
470% T_y=py(2);
471GeometryCalib.CalibrationType='rescale';
472GeometryCalib.fx_fy=[px(1) py(1)];%.fx_fy corresponds to pxcm along x and y
473GeometryCalib.CoordUnit=[];% default value, to be updated by the calling function
474GeometryCalib.Tx_Ty_Tz=[px(2)/px(1) py(2)/py(1) 1];
475GeometryCalib.omc=[0 0 0];
476
477%------------------------------------------------------------------------
478% --- determine the parameters for a calibration by a linear transform matrix (rescale and rotation)
479function GeometryCalib=calib_linear(Coord,Intrinsic)
480%------------------------------------------------------------------------
481X=Coord(:,1);
482Y=Coord(:,2);% Z not used
483x_ima=Coord(:,4);
484y_ima=Coord(:,5);
485XY_mat=[ones(size(X)) X Y];
486a_X1=XY_mat\x_ima; %transformation matrix for X
487a_Y1=XY_mat\y_ima;%transformation matrix for X
488R=[a_X1(2),a_X1(3);a_Y1(2),a_Y1(3)];
489epsilon=sign(det(R));
490norm=abs(det(R));
491GeometryCalib.CalibrationType='linear';
492if (a_X1(2)/a_Y1(3))>0
493    GeometryCalib.fx_fy(1)=sqrt((a_X1(2)/a_Y1(3))*norm);
494else
495    GeometryCalib.fx_fy(1)=-sqrt(-(a_X1(2)/a_Y1(3))*norm);
496end
497GeometryCalib.fx_fy(2)=(a_Y1(3)/a_X1(2))*GeometryCalib.fx_fy(1);
498GeometryCalib.CoordUnit=[];% default value, to be updated by the calling function
499GeometryCalib.Tx_Ty_Tz=[a_X1(1)/GeometryCalib.fx_fy(1) a_Y1(1)/GeometryCalib.fx_fy(2) 1];
500R(1,:)=R(1,:)/GeometryCalib.fx_fy(1);
501R(2,:)=R(2,:)/GeometryCalib.fx_fy(2);
502R=[R;[0 0]];
503GeometryCalib.R=[R [0;0;-epsilon]];
504GeometryCalib.omc=(180/pi)*[acos(GeometryCalib.R(1,1)) 0 0];
505
506%------------------------------------------------------------------------
507% --- determine the tsai parameters for a view normal to the grid plane
508% NOT USED
509function GeometryCalib=calib_normal(Coord,Intrinsic)
510%------------------------------------------------------------------------
511Calib.fx=str2num(get(handles.fx,'String'));
512Calib.fy=str2num(get(handles.fy,'String'));
513Calib.kc=str2num(get(handles.kc,'String'));
514Calib.Cx=str2num(get(handles.Cx,'String'));
515Calib.Cy=str2num(get(handles.Cy,'String'));
516%default
517if isempty(Calib.fx)
518    Calib.fx=25/0.012;
519end
520if isempty(Calib.fy)
521    Calib.fy=25/0.012;
522end
523if isempty(Calib.kc)
524    Calib.kc=0;
525end
526if isempty(Calib.Cx)||isempty(Calib.Cy)
527    huvmat=findobj(allchild(0),'Tag','uvmat');
528    hhuvmat=guidata(huvmat);
529    Calib.Cx=str2num(get(hhuvmat.num_Npx,'String'))/2;
530    Calib.Cx=str2num(get(hhuvmat.num_Npy,'String'))/2;
531end   
532%tsai parameters
533Calib.dpx=0.012;%arbitrary
534Calib.dpy=0.012;
535Calib.sx=Calib.fx*Calib.dpx/(Calib.fy*Calib.dpy);
536Calib.f=Calib.fy*Calib.dpy;
537Calib.kappa1=Calib.kc/(Calib.f*Calib.f);
538
539%initial guess
540X=Coord(:,1);
541Y=Coord(:,2);
542Zmean=mean(Coord(:,3));
543x_ima=Coord(:,4)-Calib.Cx;
544y_ima=Coord(:,5)-Calib.Cy;
545XY_mat=[ones(size(X)) X Y];
546a_X1=XY_mat\x_ima; %transformation matrix for X
547a_Y1=XY_mat\y_ima;%transformation matrix for Y
548R=[a_X1(2),a_X1(3),0;a_Y1(2),a_Y1(3),0;0,0,-1];% rotation+ z axis reversal (upward)
549norm=sqrt(det(-R));
550calib_param(1)=0;% quadratic distortion
551calib_param(2)=a_X1(1);
552calib_param(3)=a_Y1(1);
553calib_param(4)=Calib.f/(norm*Calib.dpx)-R(3,3)*Zmean;
554calib_param(5)=angle(a_X1(2)+1i*a_X1(3));
555display(['initial guess=' num2str(calib_param)])
556
557%optimise the parameters: minimisation of error
558calib_param = fminsearch(@(calib_param) error_calib(calib_param,Calib,Coord),calib_param);
559
560GeometryCalib.CalibrationType='tsai_normal';
561GeometryCalib.focal=Calib.f;
562GeometryCalib.dpx_dpy=[Calib.dpx Calib.dpy];
563GeometryCalib.Cx_Cy=[Calib.Cx Calib.Cy];
564GeometryCalib.sx=Calib.sx;
565GeometryCalib.kappa1=calib_param(1);
566GeometryCalib.CoordUnit=[];% default value, to be updated by the calling function
567GeometryCalib.Tx_Ty_Tz=[calib_param(2) calib_param(3) calib_param(4)];
568alpha=calib_param(5);
569GeometryCalib.R=[cos(alpha) sin(alpha) 0;-sin(alpha) cos(alpha) 0;0 0 -1];
570
571%------------------------------------------------------------------------
572function GeometryCalib=calib_3D_linear(Coord,Intrinsic)
573%------------------------------------------------------------------------
574coord_files=Intrinsic.coord_files;
575if ischar(Intrinsic.coord_files)
576    coord_files={coord_files};
577end
578if isempty(coord_files{1}) || isequal(coord_files,{''})
579    coord_files={};
580end
581%retrieve the calibration points stored in the files listed in the popup list ListCoordFiles
582x_1=Coord(:,4:5)';%px coordinates of the ref points
583
584nx=Intrinsic.Npx;
585ny=Intrinsic.Npy;
586x_1(2,:)=ny-x_1(2,:);%reverse the y image coordinates
587X_1=Coord(:,1:3)';%phys coordinates of the ref points
588n_ima=numel(coord_files)+1;
589if ~isempty(coord_files)
590    msgbox_uvmat('CONFIRMATION',['The xy coordinates of the calibration points in ' num2str(n_ima) ' planes will be used'])
591    for ifile=1:numel(coord_files)
592    t=xmltree(coord_files{ifile});
593    s=convert(t);%convert to matlab structure
594        if isfield(s,'GeometryCalib')
595            if isfield(s.GeometryCalib,'SourceCalib')
596                if isfield(s.GeometryCalib.SourceCalib,'PointCoord')
597                PointCoord=s.GeometryCalib.SourceCalib.PointCoord;
598                Coord_file=zeros(length(PointCoord),5);%default
599                for i=1:length(PointCoord)
600                    line=str2num(PointCoord{i});
601                    Coord_file(i,4:5)=line(4:5);%px x
602                    Coord_file(i,1:3)=line(1:3);%phys x
603                end
604                eval(['x_' num2str(ifile+1) '=Coord_file(:,4:5)'';']);
605                eval(['x_' num2str(ifile+1) '(2,:)=ny-x_' num2str(ifile+1) '(2,:);' ]);
606                eval(['X_' num2str(ifile+1) '=Coord_file(:,1:3)'';']);
607                end
608            end
609        end
610    end
611end
612n_ima=numel(coord_files)+1;
613est_dist=[0;0;0;0;0];
614est_aspect_ratio=0;
615est_fc=[1;1];
616center_optim=0;
617path_uvmat=which('uvmat');% check the path detected for source file uvmat
618path_UVMAT=fileparts(path_uvmat); %path to UVMAT
619run(fullfile(path_UVMAT,'toolbox_calib','go_calib_optim'));% apply fct 'toolbox_calib/go_calib_optim'
620if exist('Rc_1','var')
621    GeometryCalib.CalibrationType='3D_linear';
622    GeometryCalib.fx_fy=fc';
623    GeometryCalib.Cx_Cy=cc';
624    GeometryCalib.kc=kc(1);
625    GeometryCalib.CoordUnit=[];% default value, to be updated by the calling function
626    GeometryCalib.Tx_Ty_Tz=Tc_1';
627    GeometryCalib.R=Rc_1;
628    GeometryCalib.R(2,1:3)=-GeometryCalib.R(2,1:3);%inversion of the y image coordinate
629    GeometryCalib.Tx_Ty_Tz(2)=-GeometryCalib.Tx_Ty_Tz(2);%inversion of the y image coordinate
630    GeometryCalib.Cx_Cy(2)=ny-GeometryCalib.Cx_Cy(2);%inversion of the y image coordinate
631    GeometryCalib.omc=(180/pi)*omc_1;%angles in degrees
632    GeometryCalib.ErrorRMS=[];
633    GeometryCalib.ErrorMax=[];
634else
635    msgbox_uvmat('ERROR',['calibration function ' fullfile('toolbox_calib','go_calib_optim') ' did not converge: use multiple views or option 3D_extrinsic'])
636    GeometryCalib=[];
637end
638
639%------------------------------------------------------------------------
640function GeometryCalib=calib_3D_quadr(Coord,Intrinsic)
641%------------------------------------------------------------------
642
643path_uvmat=which('uvmat');% check the path detected for source file uvmat
644path_UVMAT=fileparts(path_uvmat); %path to UVMAT
645huvmat=findobj(allchild(0),'Tag','uvmat');
646hhuvmat=guidata(huvmat);
647if ~strcmp(get(hhuvmat.Scalar,'Visible'),'on')
648    msgbox_uvmat('ERROR','An image needs to be opened in uvmat for calibration')
649  return
650end
651% check_cond=0;
652
653coord_files=Intrinsic.coord_files;
654
655if ischar(coord_files)
656    coord_files={coord_files};
657end
658if isempty(coord_files{1}) || isequal(coord_files,{''})
659    coord_files={};
660end
661
662%retrieve the calibration points stored in the files listed in the popup list ListCoordFiles
663x_1=Coord(:,4:5)';%px coordinates of the ref points
664nx=str2num(get(hhuvmat.num_Npx,'String'));
665ny=str2num(get(hhuvmat.num_Npy,'String'));
666x_1(2,:)=ny-x_1(2,:);%reverse the y image coordinates
667X_1=Coord(:,1:3)';%phys coordinates of the ref points
668n_ima=numel(coord_files)+1;
669if ~isempty(coord_files)
670    msgbox_uvmat('CONFIRMATION',['The xy coordinates of the calibration points in ' num2str(n_ima) ' planes will be used'])
671    for ifile=1:numel(coord_files)
672    t=xmltree(coord_files{ifile});
673    s=convert(t);%convert to matlab structure
674        if isfield(s,'GeometryCalib')
675            if isfield(s.GeometryCalib,'SourceCalib')
676                if isfield(s.GeometryCalib.SourceCalib,'PointCoord')
677                PointCoord=s.GeometryCalib.SourceCalib.PointCoord;
678                Coord_file=zeros(length(PointCoord),5);%default
679                for i=1:length(PointCoord)
680                    line=str2num(PointCoord{i});
681                    Coord_file(i,4:5)=line(4:5);%px x
682                    Coord_file(i,1:3)=line(1:3);%phys x
683                end
684                eval(['x_' num2str(ifile+1) '=Coord_file(:,4:5)'';']);
685                eval(['x_' num2str(ifile+1) '(2,:)=ny-x_' num2str(ifile+1) '(2,:);' ]);
686                eval(['X_' num2str(ifile+1) '=Coord_file(:,1:3)'';']);
687                end
688            end
689        end
690    end
691end
692n_ima=numel(coord_files)+1;
693est_dist=[1;0;0;0;0];
694est_aspect_ratio=1;
695center_optim=0;
696run(fullfile(path_UVMAT,'toolbox_calib','go_calib_optim'));% apply fct 'toolbox_calib/go_calib_optim'
697
698if exist('Rc_1','var')
699    GeometryCalib.CalibrationType='3D_quadr';
700    GeometryCalib.fx_fy=fc';
701    GeometryCalib.Cx_Cy=cc';
702    GeometryCalib.kc=kc(1);
703    GeometryCalib.CoordUnit=[];% default value, to be updated by the calling function
704    GeometryCalib.Tx_Ty_Tz=Tc_1';
705    GeometryCalib.R=Rc_1;
706    GeometryCalib.R(2,1:3)=-GeometryCalib.R(2,1:3);%inversion of the y image coordinate
707    GeometryCalib.Tx_Ty_Tz(2)=-GeometryCalib.Tx_Ty_Tz(2);%inversion of the y image coordinate
708    GeometryCalib.Cx_Cy(2)=ny-GeometryCalib.Cx_Cy(2);%inversion of the y image coordinate
709    GeometryCalib.omc=(180/pi)*omc_1;%angles in degrees
710    GeometryCalib.ErrorRMS=[];
711    GeometryCalib.ErrorMax=[];
712else
713    msgbox_uvmat('ERROR',['calibration function ' fullfile('toolbox_calib','go_calib_optim') ' did not converge: use multiple views or option 3D_extrinsic'])
714    GeometryCalib=[];
715end
716
717%------------------------------------------------------------------------
718function GeometryCalib=calib_3D_extrinsic(Coord, Intrinsic)
719%------------------------------------------------------------------
720path_uvmat=which('geometry_calib');% check the path detected for source file uvmat
721path_UVMAT=fileparts(path_uvmat); %path to UVMAT
722x_1=double(Coord(:,4:5)');%image coordinates
723X_1=double(Coord(:,1:3)');% phys coordinates
724huvmat=findobj(allchild(0),'Tag','uvmat');
725hhuvmat=guidata(huvmat);
726if ~strcmp(get(hhuvmat.Scalar,'Visible'),'on')
727    msgbox_uvmat('ERROR','An image needs to be opened in uvmat for calibration')
728  return
729end
730ny=str2double(get(hhuvmat.num_Npy,'String'));
731x_1(2,:)=ny-x_1(2,:);%reverse the y image coordinates
732n_ima=1;
733GeometryCalib.CalibrationType='3D_extrinsic';
734fx=Intrinsic.fx;
735fy=Intrinsic.fy;
736Cx=Intrinsic.Cx;
737Cy=Intrinsic.Cy;
738kc=Intrinsic.kc;
739errormsg='';
740if isempty(fx)
741    errormsg='focal length fx needs to be introduced';
742elseif isempty(fy)
743    errormsg='focal length fy needs to be introduced';
744elseif isempty(Cx)
745    errormsg='shift Cx to image centre needs to be introduced';
746elseif isempty(Cy)
747    errormsg='shift Cy to image centre needs to be introduced';
748end
749if ~isempty(errormsg)
750    GeometryCalib=[];
751    msgbox_uvmat('ERROR',errormsg)
752    return
753end
754GeometryCalib.fx_fy(1)=fx;
755GeometryCalib.fx_fy(2)=fy;
756GeometryCalib.Cx_Cy(1)=Cx;
757GeometryCalib.Cx_Cy(2)=Cy;
758GeometryCalib.kc=kc;
759fct_path=fullfile(path_UVMAT,'toolbox_calib');
760addpath(fct_path)
761GeometryCalib.Cx_Cy(2)=ny-GeometryCalib.Cx_Cy(2);%reverse Cx_Cy(2) for calibration (inversion of px ordinate)
762[omc,Tc1,Rc1,H,x,ex,JJ] = compute_extrinsic(x_1,X_1,...
763   (GeometryCalib.fx_fy)',GeometryCalib.Cx_Cy',[GeometryCalib.kc 0 0 0 0]);
764rmpath(fct_path);
765GeometryCalib.CoordUnit=[];% default value, to be updated by the calling function
766GeometryCalib.Tx_Ty_Tz=Tc1';
767%inversion of z axis
768GeometryCalib.R=Rc1;
769GeometryCalib.R(2,1:3)=-GeometryCalib.R(2,1:3);%inversion of the y image coordinate
770GeometryCalib.Tx_Ty_Tz(2)=-GeometryCalib.Tx_Ty_Tz(2);%inversion of the y image coordinate
771GeometryCalib.Cx_Cy(2)=ny-GeometryCalib.Cx_Cy(2);%inversion of the y image coordinate
772GeometryCalib.omc=(180/pi)*omc';
773
774%------------------------------------------------------------------------
775%function GeometryCalib=calib_tsai_heikkila(Coord)
776% TEST: NOT IMPLEMENTED
777%------------------------------------------------------------------
778% path_uvmat=which('uvmat');% check the path detected for source file uvmat
779% path_UVMAT=fileparts(path_uvmat); %path to UVMAT
780% path_calib=fullfile(path_UVMAT,'toolbox_calib_heikkila');
781% addpath(path_calib)
782% npoints=size(Coord,1);
783% Coord(:,1:3)=10*Coord(:,1:3);
784% Coord=[Coord zeros(npoints,2) -ones(npoints,1)];
785% [par,pos,iter,res,er,C]=cacal('dalsa',Coord);
786% GeometryCalib.CalibrationType='tsai';
787% GeometryCalib.focal=par(2);
788
789
790%------------------------------------------------------------------------
791% --- determine the rms of calibration error
792function ErrorRms=error_calib(calib_param,Calib,Coord)
793%------------------------------------------------------------------------
794%calib_param: vector of free calibration parameters (to optimise)
795%Calib: structure of the given calibration parameters
796%Coord: list of phys coordinates (columns 1-3, and pixel coordinates (columns 4-5)
797Calib.f=25;
798Calib.dpx=0.012;
799Calib.dpy=0.012;
800Calib.sx=1;
801Calib.Cx=512;
802Calib.Cy=512;
803Calib.kappa1=calib_param(1);
804Calib.Tx=calib_param(2);
805Calib.Ty=calib_param(3);
806Calib.Tz=calib_param(4);
807alpha=calib_param(5);
808Calib.R=[cos(alpha) sin(alpha) 0;-sin(alpha) cos(alpha) 0;0 0 -1];
809
810X=Coord(:,1);
811Y=Coord(:,2);
812Z=Coord(:,3);
813x_ima=Coord(:,4);
814y_ima=Coord(:,5);
815[Xpoints,Ypoints]=px_XYZ(Calib,X,Y,Z);
816ErrorRms(1)=sqrt(mean((Xpoints-x_ima).*(Xpoints-x_ima)));
817ErrorRms(2)=sqrt(mean((Ypoints-y_ima).*(Ypoints-y_ima)));
818ErrorRms=mean(ErrorRms);
819
820
821%------------------------------------------------------------------------
822% --- Executes on button press in STORE.
823function STORE_Callback(hObject, eventdata, handles)
824%------------------------------------------------------------------------
825Coord=get(handles.ListCoord,'Data');
826%Object=read_geometry_calib(Coord_cell);
827unitlist=get(handles.CoordUnit,'String');
828unit=unitlist{get(handles.CoordUnit,'value')};
829GeometryCalib.CoordUnit=unit;
830GeometryCalib.SourceCalib.PointCoord=Coord(:,1:5);
831huvmat=findobj(allchild(0),'Name','uvmat');
832hhuvmat=guidata(huvmat);%handles of elements in the GUI uvmat
833% RootPath='';
834% RootFile='';
835if ~isempty(hhuvmat.RootPath)&& ~isempty(hhuvmat.RootFile)
836%     testhandle=1;
837    RootPath=get(hhuvmat.RootPath,'String');
838    RootFile=get(hhuvmat.RootFile,'String');
839    filebase=[fullfile(RootPath,RootFile) '~'];
840    while exist([filebase '.xml'],'file')
841        filebase=[filebase '~'];
842    end
843    outputfile=[filebase '.xml'];
844    errormsg=update_imadoc(GeometryCalib,outputfile,'GeometryCalib');
845    if ~strcmp(errormsg,'')
846        msgbox_uvmat('ERROR',errormsg);
847    end
848    listfile=get(handles.ListCoordFiles,'string');
849    if isequal(listfile,{''})
850        listfile={outputfile};
851    else
852        listfile=[listfile;{outputfile}];%update the list of coord files
853    end
854    set(handles.ListCoordFiles,'string',listfile);
855end
856ClearAll_Callback(hObject, eventdata, handles)% clear the current list and point plots
857
858% --------------------------------------------------------------------
859% --- Executes on button press in ClearAll: clear the list of calibration points
860function ClearAll_Callback(hObject, eventdata, handles)
861% --------------------------------------------------------------------
862set(handles.ListCoord,'Data',[])
863PLOT_Callback(hObject, eventdata, handles)
864update_calib_marker([]);%remove circle marker
865set(handles.APPLY,'backgroundColor',[1 0 0])% set APPLY button to red color: no calibration wanted without points
866set(handles.CheckEnableMouse,'value',1); %activate mouse to pick new points
867
868%------------------------------------------------------------------------
869% --- Executes on button press in CLEAR LIST
870function CLEAR_Callback(hObject, eventdata, handles)
871%------------------------------------------------------------------------
872set(handles.ListCoordFiles,'Value',1)
873set(handles.ListCoordFiles,'String',{''})
874
875%------------------------------------------------------------------------
876% --- Executes on selection change in CheckEnableMouse.
877function CheckEnableMouse_Callback(hObject, eventdata, handles)
878%------------------------------------------------------------------------
879choice=get(handles.CheckEnableMouse,'Value');
880if choice
881    huvmat=findobj(allchild(0),'tag','uvmat');
882    if ishandle(huvmat)
883        hhuvmat=guidata(huvmat);
884        set(hhuvmat.MenuRuler,'checked','off')%desactivate ruler
885        if get(hhuvmat.CheckEditObject,'Value')
886            set(hhuvmat.CheckEditObject,'Value',0)
887            uvmat('CheckEditObject_Callback',hhuvmat.CheckEditObject,[],hhuvmat)
888        end
889        set(hhuvmat.MenuRuler,'checked','off')%desactivate ruler
890    end
891end
892
893% --------------------------------------------------------------------
894function MenuHelp_Callback(hObject, eventdata, handles)
895web('http://servforge.legi.grenoble-inp.fr/projects/soft-uvmat/wiki/UvmatHelp#GeometryCalib')
896
897% --------------------------------------------------------------------
898function MenuSetScale_Callback(hObject, eventdata, handles)
899
900answer=msgbox_uvmat('INPUT_TXT','scale pixel/cm?','');
901%create test points
902huvmat=findobj(allchild(0),'Name','uvmat');%find the current uvmat interface handle
903hhuvmat=guidata(huvmat);
904if ~strcmp(get(hhuvmat.Scalar,'Visible'),'on')
905    msgbox_uvmat('ERROR','An image needs to be opened in uvmat for calibration')
906    return
907end
908set(handles.calib_type,'Value',1)% set calib option to 'rescale'
909npx=str2num(get(hhuvmat.num_Npx,'String'))/2;
910npy=str2num(get(hhuvmat.num_Npy,'String'))/2;
911Xima=[0.25*npx 0.75*npx 0.75*npx 0.25*npx]';
912Yima=[0.25*npy 0.25*npy 0.75*npy 0.75*npy]';
913x=Xima/str2num(answer);
914y=Yima/str2num(answer);
915Coord=[x y zeros(4,1) Xima Yima zeros(4,1)];
916set(handles.ListCoord,'Data',Coord)
917set(handles.APPLY,'BackgroundColor',[1 0 1])
918set(handles.CheckEnableMouse,'value',0); %desactivate mouse to avoid spurious points
919
920%------------------------------------------------------------------------
921function MenuCreateGrid_Callback(hObject, eventdata, handles)
922%------------------------------------------------------------------------
923CalibData=get(handles.geometry_calib,'UserData');
924Tinput=[];%default
925if isfield(CalibData,'grid')
926    Tinput=CalibData.grid;
927end
928[T,CalibData.grid]=create_grid(Tinput);%display the GUI create_grid
929set(handles.geometry_calib,'UserData',CalibData)
930
931%grid in phys space
932Coord=get(handles.ListCoord,'Data');
933Coord(1:size(T,1),1:3)=T;%update the existing list of phys coordinates from the GUI create_grid
934set(handles.ListCoord,'Data',Coord)
935set(handles.APPLY,'BackgroundColor',[1 0 1])
936set(handles.CheckEnableMouse,'value',0); %desactivate mouse to avoid spurious points
937
938% -----------------------------------------------------------------------
939% --- automatic grid dectection from local maxima of the images
940function MenuDetectGrid_Callback(hObject, eventdata, handles)
941%------------------------------------------------------------------------
942%% read the four last point coordinates in pixels
943Coord=get(handles.ListCoord,'Data');%read list of coordinates on geometry_calib
944nbpoints=size(Coord,1); %nbre of calibration points
945if nbpoints~=4
946    msgbox_uvmat('ERROR','four points must have be selected by the mouse to delimitate the phys grid area; the Ox axis will be defined by the two first points')
947    return
948end
949% corners_X=(Coord(end:-1:end-3,4)); %pixel absissa of the four corners
950% corners_Y=(Coord(end:-1:end-3,5));
951corners_X=(Coord(:,4)); %pixel absissa of the four corners
952corners_Y=(Coord(:,5));
953
954%%%%%%
955%   corners_X=1000*[1.5415  1.7557 1.7539 1.5415]';
956%   corners_Y=1000*[1.1515 1.1509 1.3645  1.3639]';
957
958%reorder the last two points (the two first in the list) if needed
959angles=angle((corners_X-corners_X(1))+1i*(corners_Y-corners_Y(1)));
960if abs(angles(4)-angles(2))>abs(angles(3)-angles(2))
961      X_end=corners_X(4);
962      Y_end=corners_Y(4);
963      corners_X(4)=corners_X(3);
964      corners_Y(4)=corners_Y(3);
965      corners_X(3)=X_end;
966      corners_Y(3)=Y_end;
967end
968
969%% initiate the grid in phys coordinates
970CalibData=get(handles.geometry_calib,'UserData');%get information stored on the GUI geometry_calib
971grid_input=[];%default
972if isfield(CalibData,'grid')
973    grid_input=CalibData.grid;%retrieve the previously used grid
974end
975[T,CalibData.grid,CalibData.grid.CheckWhite,CalibData.grid.FilterWindow]=create_grid(grid_input,'detect_grid');%display the GUI create_grid, read the set of phys coordinates T
976set(handles.geometry_calib,'UserData',CalibData)%store the phys grid parameters for later use
977X=[CalibData.grid.x_0 CalibData.grid.x_1 CalibData.grid.x_0 CalibData.grid.x_1]';%corner absissa in the phys coordinates (cm)
978Y=[CalibData.grid.y_0 CalibData.grid.y_0 CalibData.grid.y_1 CalibData.grid.y_1]';%corner ordinates in the phys coordinates (cm)
979
980%% read the current image, displayed in the GUI uvmat
981huvmat=findobj(allchild(0),'Name','uvmat');
982UvData=get(huvmat,'UserData');
983A=UvData.Field.A;%currently displayed image
984npxy=size(A);
985
986%% calculate transform matrices for plane projection: rectangle assumed to be viewed in perspective
987% reference: http://alumni.media.mit.edu/~cwren/interpolator/ by Christopher R. Wren
988B = [ X Y ones(size(X)) zeros(4,3)        -X.*corners_X -Y.*corners_X ...
989      zeros(4,3)        X Y ones(size(X)) -X.*corners_Y -Y.*corners_Y ];
990B = reshape (B', 8 , 8 )';
991D = [ corners_X , corners_Y ];
992D = reshape (D', 8 , 1 );
993l = (B' * B)\B' * D;
994Amat = reshape([l(1:6)' 0 0 1 ],3,3)';
995C = [l(7:8)' 1];
996
997%% transform grid image into 'phys' coordinates
998GeometryCalib.CalibrationType='3D_linear';
999GeometryCalib.fx_fy=[1 1];
1000GeometryCalib.Tx_Ty_Tz=[Amat(1,3) Amat(2,3) 1];
1001GeometryCalib.R=[Amat(1,1),Amat(1,2),0;Amat(2,1),Amat(2,2),0;C(1),C(2),0];
1002GeometryCalib.CoordUnit='cm';
1003path_uvmat=which('uvmat');% check the path detected for source file uvmat
1004path_UVMAT=fileparts(path_uvmat); %path to UVMAT
1005addpath(fullfile(path_UVMAT,'transform_field'))
1006Data.ListVarName={'Coord_y','Coord_x','A'};
1007Data.VarDimName={'Coord_y','Coord_x',{'Coord_y','Coord_x'}};
1008if ndims(A)==3
1009    A=mean(A,3);
1010end
1011Data.A=A-min(min(A));
1012Data.Coord_y=[npxy(1)-0.5 0.5];
1013Data.Coord_x=[0.5 npxy(2)];
1014Data.CoordUnit='pixel';
1015Calib.GeometryCalib=GeometryCalib;
1016DataOut=phys(Data,Calib);
1017rmpath(fullfile(path_UVMAT,'transform_field'))
1018Amod=DataOut.A;% current image expressed in 'phys' coord
1019Rangx=DataOut.Coord_x;% x coordinates of first and last pixel centres in phys
1020Rangy=DataOut.Coord_y;% y coordinates of first and last pixel centres in phys
1021if CalibData.grid.CheckWhite
1022    Amod=double(Amod);%case of white grid markers: will look for image maxima
1023else
1024    Amod=-double(Amod);%case of black grid markers: will look for image minima
1025end
1026
1027%%%%%%filterfor i;proved detection of dots
1028if ~isequal(CalibData.grid.FilterWindow,0)
1029    %definition of the cos shape matrix filter
1030    FilterBoxSize_x=CalibData.grid.FilterWindow;
1031    FilterBoxSize_y=CalibData.grid.FilterWindow;
1032    ix=1/2-FilterBoxSize_x/2:-1/2+FilterBoxSize_x/2;%
1033    iy=1/2-FilterBoxSize_y/2:-1/2+FilterBoxSize_y/2;%
1034    %del=np/3;
1035    %fct=exp(-(ix/del).^2);
1036    fct2_x=cos(ix/((FilterBoxSize_x-1)/2)*pi/2);
1037    fct2_y=cos(iy/((FilterBoxSize_y-1)/2)*pi/2);
1038    %Mfiltre=(ones(5,5)/5^2);
1039    Mfiltre=fct2_y'*fct2_x;
1040    Mfiltre=Mfiltre/(sum(sum(Mfiltre)));%normalize filter
1041   
1042    if ndims(Amod)==3
1043        Amod=filter2(Mfiltre,sum(Amod,3));%filter the input image, after summation on the color component (for color images)
1044    else
1045        Amod=filter2(Mfiltre,Amod);
1046    end
1047end
1048%%%%%%%%%%%%%%
1049
1050
1051%% detection of local image extrema in each direction
1052Dx=(Rangx(2)-Rangx(1))/(npxy(2)-1); %x mesh in real space
1053Dy=(Rangy(2)-Rangy(1))/(npxy(1)-1); %y mesh in real space
1054ind_range_x=ceil(abs(GeometryCalib.R(1,1)*CalibData.grid.Dx/3));% range of search of image ma around each point obtained by linear interpolation from the marked points
1055ind_range_y=ceil(abs(GeometryCalib.R(2,2)*CalibData.grid.Dy/3));% range of search of image ma around each point obtained by linear interpolation from the marked points
1056nbpoints=size(T,1);
1057TIndex=ones(size(T));% image indices corresponding to point coordinates
1058%look for image maxima around each expected grid point
1059for ipoint=1:nbpoints
1060    i0=1+round((T(ipoint,1)-Rangx(1))/Dx);% x index of the expected point in the phys image Amod
1061    j0=1+round((T(ipoint,2)-Rangy(1))/Dy);% y index of the expected point in the phys image Amod
1062    j0min=max(j0-ind_range_y,1);% min y index selected for the subimage (cut at the edge to avoid index <1)
1063    j0max=min(j0+ind_range_y,size(Amod,1));% max y index selected for the subimage (cut at the edge to avoid index > size)
1064    i0min=max(i0-ind_range_x,1);% min x index selected for the subimage (cut at the edge to avoid index <1)
1065    i0max=min(i0+ind_range_x,size(Amod,2));% max x index selected for the subimage (cut at the edge to avoid index > size)
1066    Asub=Amod(j0min:j0max,i0min:i0max); %subimage used to find brigthness extremum
1067    x_profile=sum(Asub,1);%profile of subimage summed over y
1068    y_profile=sum(Asub,2);%profile of subimage summed over x
1069
1070    [tild,ind_x_max]=max(x_profile);% index of max for the x profile
1071    [tild,ind_y_max]=max(y_profile);% index of max for the y profile
1072    %sub-pixel improvement using moments
1073    x_shift=0;
1074    y_shift=0;
1075    if ind_x_max+2<=numel(x_profile) && ind_x_max-2>=1
1076        Atop=x_profile(ind_x_max-2:ind_x_max+2);% extract x profile around the max
1077        x_shift=sum(Atop.*[-2 -1 0 1 2])/sum(Atop);
1078    end
1079    if ind_y_max+2<=numel(y_profile) && ind_y_max-2>=1
1080        Atop=y_profile(ind_y_max-2:ind_y_max+2);% extract y profile around the max
1081        y_shift=sum(Atop.*[-2 -1 0 1 2]')/sum(Atop);
1082    end
1083        %%%%
1084%     if ipoint==9
1085%                 figure(11)
1086%   imagesc(Asub)
1087%     figure(12)
1088%     plot(x_profile,'r')
1089%     hold on
1090%     plot(y_profile,'b')
1091%     grid on
1092%     end
1093    %%%%
1094    TIndex(ipoint,1)=(i0min+ind_x_max-1+x_shift);% x position of the maximum (in index of Amod)
1095    TIndex(ipoint,2)=(j0min+ind_y_max-1+y_shift);% y position of the maximum (in index of Amod)
1096end
1097Tmod(:,1)=(TIndex(:,1)-1)*Dx+Rangx(1);
1098Tmod(:,2)=(TIndex(:,2)-1)*Dy+Rangy(1);
1099%Tmod=T(:,(1:2))+Delta;% 'phys' coordinates of the detected points
1100[Xpx,Ypx]=px_XYZ(GeometryCalib,Tmod(:,1),Tmod(:,2));% image coordinates of the detected points
1101Coord=[T Xpx Ypx zeros(size(T,1),1)];
1102set(handles.ListCoord,'Data',Coord)
1103PLOT_Callback(hObject, eventdata, handles)
1104set(handles.APPLY,'BackgroundColor',[1 0 1])
1105set(handles.CheckEnableMouse,'value',0); %desactivate mouse to avoid spurious points
1106
1107
1108%-----------------------------------------------------------------------
1109function MenuTranslatePoints_Callback(hObject, eventdata, handles)
1110%-----------------------------------------------------------------------
1111%hcalib=get(handles.calib_type,'parent');%handles of the GUI geometry_calib
1112CalibData=get(handles.geometry_calib,'UserData');
1113Tinput=[];%default
1114if isfield(CalibData,'translate')
1115    Tinput=CalibData.translate;
1116end
1117T=translate_points(Tinput);%display translate_points GUI and get shift parameters
1118CalibData.translate=T;
1119set(handles.geometry_calib,'UserData',CalibData)
1120%translation
1121Coord=get(handles.ListCoord,'Data');
1122Coord(:,1)=T(1)+Coord(:,1);
1123Coord(:,2)=T(2)+Coord(:,2);
1124Coord(:,3)=T(3)+Coord(:,3);
1125set(handles.ListCoord,'Data',Coord);
1126set(handles.APPLY,'BackgroundColor',[1 0 1])
1127
1128% --------------------------------------------------------------------
1129function MenuRotatePoints_Callback(hObject, eventdata, handles)
1130%hcalib=get(handles.calib_type,'parent');%handles of the GUI geometry_calib
1131CalibData=get(handles.geometry_calib,'UserData');
1132Tinput=[];%default
1133if isfield(CalibData,'rotate')
1134    Tinput=CalibData.rotate;
1135end
1136T=rotate_points(Tinput);%display rotate_points GUI to introduce rotation parameters
1137CalibData.rotate=T;
1138set(handles.geometry_calib,'UserData',CalibData)
1139%-----------------------------------------------------
1140%rotation
1141Phi=T(1);
1142O_x=0;%default
1143O_y=0;%default
1144if numel(T)>=2
1145    O_x=T(2);%default
1146end
1147if numel(T)>=3
1148    O_y=T(3);%default
1149end
1150Coord=get(handles.ListCoord,'Data');
1151r1=cos(pi*Phi/180);
1152r2=-sin(pi*Phi/180);
1153r3=sin(pi*Phi/180);
1154r4=cos(pi*Phi/180);
1155x=Coord(:,1)-O_x;
1156y=Coord(:,2)-O_y;
1157Coord(:,1)=r1*x+r2*y;
1158Coord(:,2)=r3*x+r4*y;
1159set(handles.ListCoord,'Data',Coord)
1160set(handles.APPLY,'BackgroundColor',[1 0 1])
1161
1162% --------------------------------------------------------------------
1163function MenuFlip_x_Callback(hObject, eventdata, handles)
1164Coord=get(handles.ListCoord,'Data');
1165Coord(:,1)=-Coord(:,1);
1166set(handles.ListCoord,'Data',Coord)
1167
1168% --------------------------------------------------------------------
1169function MenuFlip_y_Callback(hObject, eventdata, handles)
1170Coord=get(handles.ListCoord,'Data');
1171Coord(:,2)=-Coord(:,2);
1172set(handles.ListCoord,'Data',Coord)
1173
1174% --------------------------------------------------------------------
1175function MenuImportPoints_Callback(hObject, eventdata, handles)
1176fileinput=browse_xml(hObject, eventdata, handles);
1177if isempty(fileinput)
1178    return
1179end
1180[s,errormsg]=imadoc2struct(fileinput,'GeometryCalib');
1181if ~isfield(s,'GeometryCalib')
1182    msgbox_uvmat('ERROR','invalid input file: no geometry_calib data')
1183    return
1184end
1185GeometryCalib=s.GeometryCalib;
1186if ~(isfield(GeometryCalib,'SourceCalib')&&isfield(GeometryCalib.SourceCalib,'PointCoord'))
1187        msgbox_uvmat('ERROR','invalid input file: no calibration points')
1188    return
1189end
1190Coord=GeometryCalib.SourceCalib.PointCoord;
1191Coord=[Coord zeros(size(Coord,1),1)];
1192set(handles.ListCoord,'Data',Coord)
1193PLOT_Callback(handles.geometry_calib, [], handles)
1194set(handles.APPLY,'BackgroundColor',[1 0 1])
1195set(handles.CheckEnableMouse,'value',0); %desactivate mouse to avoid modifications by default
1196
1197% -----------------------------------------------------------------------
1198function MenuImportIntrinsic_Callback(hObject, eventdata, handles)
1199%------------------------------------------------------------------------
1200fileinput=browse_xml(hObject, eventdata, handles);
1201if isempty(fileinput)
1202    return
1203end
1204[s,errormsg]=imadoc2struct(fileinput,'GeometryCalib');
1205GeometryCalib=s.GeometryCalib;
1206display_intrinsic(GeometryCalib,handles)
1207
1208% -----------------------------------------------------------------------
1209function MenuImportAll_Callback(hObject, eventdata, handles)
1210%------------------------------------------------------------------------
1211fileinput=browse_xml(hObject, eventdata, handles);
1212if ~isempty(fileinput)
1213    loadfile(handles,fileinput)
1214end
1215set(handles.CheckEnableMouse,'value',0); %desactivate mouse to avoid modifications by default
1216
1217% -----------------------------------------------------------------------
1218% --- Executes on menubar option Import/Grid file: introduce previous grid files
1219function MenuGridFile_Callback(hObject, eventdata, handles)
1220% -----------------------------------------------------------------------
1221inputfile=browse_xml(hObject, eventdata, handles);
1222listfile=get(handles.ListCoordFiles,'String');
1223if isequal(listfile,{''})
1224    listfile={inputfile};
1225else
1226    listfile=[listfile;{inputfile}];%update the list of coord files
1227end
1228set(handles.ListCoordFiles,'String',listfile);
1229
1230
1231%------------------------------------------------------------------------
1232function fileinput=browse_xml(hObject, eventdata, handles)
1233%------------------------------------------------------------------------
1234fileinput=[];%default
1235oldfile=''; %default
1236UserData=get(handles.geometry_calib,'UserData');
1237if isfield(UserData,'XmlInputFile')
1238    oldfile=UserData.XmlInputFile;
1239end
1240[FileName, PathName, filterindex] = uigetfile( ...
1241       {'*.xml;*.mat', ' (*.xml,*.mat)';
1242       '*.xml',  '.xml files '; ...
1243        '*.mat',  '.mat matlab files '}, ...
1244        'Pick a file',oldfile);
1245fileinput=[PathName FileName];%complete file name
1246testblank=findstr(fileinput,' ');%look for blanks
1247if ~isempty(testblank)
1248    msgbox_uvmat('ERROR','forbidden input file name or path: no blank character allowed')
1249    return
1250end
1251sizf=size(fileinput);
1252if (~ischar(fileinput)||~isequal(sizf(1),1)),return;end
1253UserData.XmlInputFile=fileinput;
1254set(handles.geometry_calib,'UserData',UserData)%record current file foer further use of browser
1255
1256% -----------------------------------------------------------------------
1257function Heading=loadfile(handles,fileinput)
1258%------------------------------------------------------------------------
1259Heading=[];%default
1260[s,errormsg]=imadoc2struct(fileinput,'Heading','GeometryCalib');
1261if ~isempty(errormsg)
1262    msgbox_uvmat('ERROR',errormsg)
1263    return
1264end
1265if ~isempty(s.Heading)
1266    Heading=s.Heading;
1267end
1268
1269GeometryCalib=s.GeometryCalib;
1270fx=1;fy=1;Cx=0;Cy=0;kc=0; %default
1271CoordCell={};
1272Tabchar={};%default
1273val_cal=1;%default
1274if ~isempty(GeometryCalib)
1275    % choose the calibration option
1276    if isfield(GeometryCalib,'CalibrationType')
1277        calib_list=get(handles.calib_type,'String');
1278        for ilist=1:numel(calib_list)
1279            if strcmp(calib_list{ilist},GeometryCalib.CalibrationType)
1280                val_cal=ilist;
1281                break
1282            end
1283        end
1284    end
1285    display_intrinsic(GeometryCalib,handles)%intrinsic param
1286    %extrinsic param
1287    if isfield(GeometryCalib,'Tx_Ty_Tz')
1288        Tx_Ty_Tz=GeometryCalib.Tx_Ty_Tz;
1289        set(handles.Tx,'String',num2str(GeometryCalib.Tx_Ty_Tz(1),4))
1290        set(handles.Ty,'String',num2str(GeometryCalib.Tx_Ty_Tz(2),4))
1291        set(handles.Tz,'String',num2str(GeometryCalib.Tx_Ty_Tz(3),4))
1292    end
1293    if isfield(GeometryCalib,'omc')
1294        set(handles.Phi,'String',num2str(GeometryCalib.omc(1),4))
1295        set(handles.Theta,'String',num2str(GeometryCalib.omc(2),4))
1296        set(handles.Psi,'String',num2str(GeometryCalib.omc(3),4))
1297    end
1298    if isfield(GeometryCalib,'SourceCalib')&& isfield(GeometryCalib.SourceCalib,'PointCoord')
1299        calib=GeometryCalib.SourceCalib.PointCoord;
1300        Coord=[calib zeros(size(calib,1),1)];
1301        set(handles.ListCoord,'Data',Coord)
1302    end
1303    PLOT_Callback(handles.geometry_calib, [], handles)
1304    set(handles.APPLY,'BackgroundColor',[1 0 1])
1305end
1306set(handles.calib_type,'Value',val_cal)
1307
1308if isempty(CoordCell)% allow mouse action by default in the absence of input points
1309    set(handles.CheckEnableMouse,'Value',1)
1310    set(handles.CheckEnableMouse,'BackgroundColor',[1 1 0])
1311else % does not allow mouse action by default in the presence of input points
1312    set(handles.CheckEnableMouse,'Value',0)
1313    set(handles.CheckEnableMouse,'BackgroundColor',[0.7 0.7 0.7])
1314end
1315
1316%------------------------------------------------------------------------
1317%---display calibration intrinsic parameters
1318function display_intrinsic(GeometryCalib,handles)
1319%------------------------------------------------------------------------
1320fx=[];
1321fy=[];
1322if isfield(GeometryCalib,'fx_fy')
1323    fx=GeometryCalib.fx_fy(1);
1324    fy=GeometryCalib.fx_fy(2);
1325end
1326Cx_Cy=[0 0];%default
1327if isfield(GeometryCalib,'Cx_Cy')
1328    Cx_Cy=GeometryCalib.Cx_Cy;
1329end
1330kc=0;
1331if isfield(GeometryCalib,'kc')
1332    kc=GeometryCalib.kc; %* GeometryCalib.focal*GeometryCalib.focal;
1333end
1334set(handles.fx,'String',num2str(fx,5))
1335set(handles.fy,'String',num2str(fy,5))
1336set(handles.Cx,'String',num2str(Cx_Cy(1),'%1.1f'))
1337set(handles.Cy,'String',num2str(Cx_Cy(2),'%1.1f'))
1338set(handles.kc,'String',num2str(kc,'%1.4f'))
1339
1340%------------------------------------------------------------------------
1341% ---display calibration extrinsic parameters
1342function display_extrinsic(GeometryCalib,handles)
1343%------------------------------------------------------------------------
1344set(handles.Tx,'String',num2str(GeometryCalib.Tx_Ty_Tz(1),4))
1345set(handles.Ty,'String',num2str(GeometryCalib.Tx_Ty_Tz(2),4))
1346set(handles.Tz,'String',num2str(GeometryCalib.Tx_Ty_Tz(3),4))
1347set(handles.Phi,'String',num2str(GeometryCalib.omc(1),4))
1348set(handles.Theta,'String',num2str(GeometryCalib.omc(2),4))
1349set(handles.Psi,'String',num2str(GeometryCalib.omc(3),4))
1350
1351%------------------------------------------------------------------------
1352% --- executes when user attempts to close geometry_calib.
1353function geometry_calib_CloseRequestFcn(hObject, eventdata, handles)
1354%------------------------------------------------------------------------
1355delete(hObject); % closes the figure
1356
1357%------------------------------------------------------------------------
1358% --- executes on button press in PLOT.
1359%------------------------------------------------------------------------
1360function PLOT_Callback(hObject, eventdata, handles)
1361huvmat=findobj(allchild(0),'Name','uvmat');%find the current uvmat interface handle
1362hhuvmat=guidata(huvmat); %handles of GUI elements in uvmat
1363h_menu_coord=findobj(huvmat,'Tag','TransformName');
1364menu=get(h_menu_coord,'String');
1365choice=get(h_menu_coord,'Value');
1366option='';
1367if iscell(menu)
1368    option=menu{choice};
1369end
1370Coord=get(handles.ListCoord,'Data');
1371if ~isempty(Coord)
1372    if isequal(option,'phys')
1373        Coord_plot=Coord(:,1:3);
1374    elseif isempty(option);%optionoption,'px')||isequal(option,'')
1375        Coord_plot=Coord(:,4:5);
1376    else
1377        msgbox_uvmat('ERROR','the choice in menu_coord of uvmat must be blank or phys ')
1378    end
1379end
1380
1381set(0,'CurrentFigure',huvmat)
1382set(huvmat,'CurrentAxes',hhuvmat.PlotAxes)
1383hh=findobj('Tag','calib_points');
1384if  ~isempty(Coord) && isempty(hh)
1385    hh=line(Coord_plot(:,1),Coord_plot(:,2),'Color','m','Tag','calib_points','LineStyle','none','Marker','+','MarkerSize',10);
1386elseif isempty(Coord)%empty list of points, suppress the plot
1387    delete(hh)
1388else
1389    set(hh,'XData',Coord_plot(:,1))
1390    set(hh,'YData',Coord_plot(:,2))
1391end
1392pause(.1)
1393figure(handles.geometry_calib)
1394
1395%------------------------------------------------------------------------
1396% --- Executes on button press in Copy: display Coord on the Matlab work space
1397%------------------------------------------------------------------------
1398function Copy_Callback(hObject, eventdata, handles)
1399global Coord
1400evalin('base','global Coord')%make CurData global in the workspace
1401Coord=get(handles.ListCoord,'Data');
1402display('coordinates of calibration points (phys,px,marker) :')
1403evalin('base','Coord') %display CurData in the workspace
1404commandwindow; %brings the Matlab command window to the front
1405
1406%------------------------------------------------------------------------
1407% --- Executes when selected cell(s) is changed in ListCoord.
1408%------------------------------------------------------------------------
1409function ListCoord_CellSelectionCallback(hObject, eventdata, handles)
1410if ~isempty(eventdata.Indices)
1411    iline=eventdata.Indices(1);% selected line number
1412    set(handles.CoordLine,'String',num2str(iline))
1413     Data=get(handles.ListCoord,'Data');
1414     update_calib_marker(Data(iline,:))
1415end
1416
1417%------------------------------------------------------------------------
1418% --- Executes when entered data in editable cell(s) in ListCoord.
1419%------------------------------------------------------------------------
1420function ListCoord_CellEditCallback(hObject, eventdata, handles)
1421
1422Input=str2num(eventdata.EditData);%pasted input
1423Coord=get(handles.ListCoord,'Data');
1424iline=eventdata.Indices(1);% selected line number
1425if size(Coord,1)<iline+numel(Input)
1426    Coord=[Coord ; zeros(iline+numel(Input)-size(Coord,1),6)];% append zeros to fit the new column
1427end
1428Coord(iline:iline+numel(Input)-1,eventdata.Indices(2))=Input';
1429set(handles.ListCoord,'Data',Coord)
1430PLOT_Callback(hObject, eventdata, handles)
1431
1432%------------------------------------------------------------------------
1433% --- 'key_press_fcn:' function activated when a key is pressed on the keyboard
1434%------------------------------------------------------------------------
1435function ListCoord_KeyPressFcn(hObject, eventdata, handles)
1436iline=str2num(get(handles.CoordLine,'String'));
1437xx=double(get(handles.geometry_calib,'CurrentCharacter'));%get the keyboard character
1438if ismember(xx,[28 29 30 31])% directional arrow
1439    Coord=get(handles.ListCoord,'Data');
1440    switch xx
1441        case 30 % arrow upward
1442            iline=iline-1;
1443        case 31% arrow downward
1444            iline=iline+1;
1445    end
1446    if iline>=1 && iline<=size(Coord,1)
1447        set(handles.CoordLine,'String',num2str(iline))
1448        update_calib_marker(Coord(iline,1:5))% show the point corresponding to the selected line
1449    end
1450else
1451    set(handles.APPLY,'BackgroundColor',[1 0 1])% paint APPLY in magenta to indicate that the table content has be modified
1452    if ismember(xx,[127 31])% delete, or downward
1453        Coord=get(handles.ListCoord,'Data');
1454        iline=str2double(get(handles.CoordLine,'String'));
1455        if isequal(xx, 31)
1456            if isequal(iline,size(Coord,1))% arrow downward
1457                Coord=[Coord;zeros(1,size(Coord,2))];
1458            end
1459        else
1460            Coord(iline,:)=[];% suppress the current line
1461        end
1462        set(handles.ListCoord,'Data',Coord);
1463    end
1464end
1465
1466%------------------------------------------------------------------------
1467% --- update the plot of calibration points
1468%------------------------------------------------------------------------
1469% draw a circle around the point defined by the input coordinates Coord as given by line in the table Listcoord
1470function update_calib_marker(Coord)
1471
1472%% read config on uvmat
1473huvmat=findobj(allchild(0),'Name','uvmat');%find the current uvmat interface handle
1474hhuvmat=guidata(huvmat);
1475hhh=findobj(hhuvmat.PlotAxes,'Tag','calib_marker');
1476if numel(Coord)<5
1477    if ~isempty(hhh)
1478        delete(hhh)%delete the circle marker in case of no valid input
1479    end
1480    return
1481end
1482menu=get(hhuvmat.TransformName,'String');
1483choice=get(hhuvmat.TransformName,'Value');
1484option='';
1485if iscell(menu)
1486    option=menu{choice};
1487end
1488
1489%% read appropriate coordinates (px or phys) in the table ListCoord
1490if isequal(option,'phys') % use phys coord
1491    XCoord=Coord(1);
1492    YCoord=Coord(2);
1493elseif isempty(option)% use coord in pixels
1494    XCoord=Coord(4);
1495    YCoord=Coord(5);
1496else
1497    msgbox_uvmat('ERROR','the choice in menu_coord of uvmat must be blank or phys ')
1498    return
1499end
1500
1501%% adjust the plot limits if needed
1502xlim=get(hhuvmat.PlotAxes,'XLim');
1503ylim=get(hhuvmat.PlotAxes,'YLim');
1504ind_range=max(abs(xlim(2)-xlim(1)),abs(ylim(end)-ylim(1)))/25;%defines the size of the circle marker
1505check_xlim=0;
1506if XCoord>xlim(2)
1507    xlim=xlim+XCoord-xlim(2)+ind_range;% translate plot limit
1508    check_xlim=1;
1509elseif XCoord<xlim(1)
1510    xlim=xlim-XCoord+xlim(1)-ind_range;% translate plot limit
1511    check_xlim=1;
1512end
1513if check_xlim
1514    set(hhuvmat.PlotAxes,'XLim',xlim);
1515    set(hhuvmat.num_MaxX,'String',num2str(xlim(2)));
1516    set(hhuvmat.num_MinX,'String',num2str(xlim(1)));
1517end
1518check_ylim=0;
1519if YCoord>ylim(2)
1520    ylim=ylim+YCoord-ylim(2)+ind_range;% translate plot limit
1521    check_ylim=1;
1522elseif YCoord<ylim(1)
1523    ylim=ylim-YCoord+ylim(1)-ind_range;% translate plot limit
1524    check_ylim=1;
1525end
1526if check_ylim
1527    set(hhuvmat.PlotAxes,'YLim',ylim);
1528    set(hhuvmat.num_MaxY,'String',num2str(ylim(2)));
1529    set(hhuvmat.num_MinY,'String',num2str(ylim(1)));
1530end
1531
1532%% plot a circle around the selected point
1533if isempty(hhh)
1534    set(0,'CurrentFig',huvmat)
1535    set(huvmat,'CurrentAxes',hhuvmat.PlotAxes)
1536    rectangle('Curvature',[1 1],...
1537        'Position',[XCoord-ind_range/2 YCoord-ind_range/2 ind_range ind_range],'EdgeColor','m',...
1538        'LineStyle','-','Tag','calib_marker');
1539else
1540    set(hhh,'Position',[XCoord-ind_range/2 YCoord-ind_range/2 ind_range ind_range])
1541end
1542
1543%------------------------------------------------------------------------
1544% --- Executes on button press in ClearPoint: remove the selected line in the table Coord
1545%------------------------------------------------------------------------
1546function ClearPoint_Callback(hObject, eventdata, handles)
1547
1548Coord=get(handles.ListCoord,'Data');
1549iline=str2num(get(handles.CoordLine,'String'));
1550if isempty(iline)
1551    msgbox_uvmat('WARNING','no line suppressed, select a line in the table')
1552else
1553    answer=msgbox_uvmat('INPUT_Y-N',['suppress line ' num2str(iline) '?']);
1554    if isequal(answer,'Yes')
1555        Coord(iline,:)=[];
1556        set(handles.APPLY,'BackgroundColor',[1 0 1])
1557        set(handles.ListCoord,'Data',Coord);
1558        set(handles.CoordLine,'String','')
1559        PLOT_Callback(hObject,eventdata,handles)
1560        update_calib_marker([]);%remove circle marker
1561    end
1562end
1563
1564
1565
Note: See TracBrowser for help on using the repository browser.