Code covered by the BSD License  

Highlights from
Manual Ground Plane Mark up and Camera Calibration

image thumbnail
from Manual Ground Plane Mark up and Camera Calibration by Ben
Can be used to crudely calibrate camera by eye and define groundplane.

CameraCalib(varargin)
function varargout = CameraCalib(varargin)
%CAMERACALIB M-file for CameraCalib.fig
%      CAMERACALIB, by itself, creates a new CAMERACALIB or raises the existing
%      singleton*.
%
%      H = CAMERACALIB returns the handle to a new CAMERACALIB or the handle to
%      the existing singleton*.
%
%      CAMERACALIB('Property','Value',...) creates a new CAMERACALIB using the
%      given property value pairs. Unrecognized properties are passed via
%      varargin to CameraCalib_OpeningFcn.  This calling syntax produces a
%      warning when there is an existing singleton*.
%
%      CAMERACALIB('CALLBACK') and CAMERACALIB('CALLBACK',hObject,...) call the
%      local function named CALLBACK in CAMERACALIB.M with the given input
%      arguments.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help CameraCalib

% Last Modified by GUIDE v2.5 29-Feb-2012 13:54:04

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @CameraCalib_OpeningFcn, ...
                   'gui_OutputFcn',  @CameraCalib_OutputFcn, ...
                   'gui_LayoutFcn',  [], ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
   gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before CameraCalib is made visible.
function CameraCalib_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   unrecognized PropertyName/PropertyValue pairs from the
%            command line (see VARARGIN)

% Choose default command line output for CameraCalib
handles.output = hObject;
%setDefaultCamera(hObject, handles)
% Update handles structure


guidata(hObject, handles);





% UIWAIT makes CameraCalib wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = CameraCalib_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;



% --- Executes on button press in toggleDisplayAxis.
function toggleDisplayAxis_Callback(hObject, eventdata, handles)
% hObject    handle to toggleDisplayAxis (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of toggleDisplayAxis
refreshImage(handles)

% --- Executes on button press in toggleDispGrid.
function toggleDispGrid_Callback(hObject, eventdata, handles)
% hObject    handle to toggleDispGrid (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of toggleDispGrid
refreshImage(handles);

% --- Executes on button press in toggleDispScale.
function toggleDispScale_Callback(hObject, eventdata, handles)
% hObject    handle to toggleDispScale (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of toggleDispScale
refreshImage(handles);

% --- Executes on button press in pbLoadImage.
function pbLoadImage_Callback(hObject, eventdata, handles)
% hObject    handle to pbLoadImage (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename, pathname]=uigetfile(['*'],'Select image to load');

if filename ~= 0
   % = guidata(handles.figure1);
    handles.Image = imread([pathname filename]);
    handles.ImSize = size(handles.Image);
    handles.ImLoaded = 1;
    handles.P1 = [0,0,0]';
    handles.P2 = [0,0,1]';
    handles.Origin = [0,0,0]';
    handles.offset = [handles.ImSize(1)/2, handles.ImSize(2)/2];
    handles.R = [1 0 0 0; 0 1 0 0; 0 0 1 0];
   
    guidata(hObject, handles);
    setDefaultCamera(hObject, handles);
     handles = guidata(hObject);
    refreshImage(handles);
    
end

function setDefaultCamera(hObject, handles)

focalLength = sscanf(get(handles.edtFocalLength, 'String'), '%f');
SensorHeight = sscanf(get(handles.edtSensorHeight, 'String'), '%f');
conversionFactor = handles.ImSize(1)/SensorHeight;

handles.F = [conversionFactor*focalLength 0 handles.ImSize(2)/2.0; 0 conversionFactor*focalLength handles.ImSize(1)/2.0; 0 0 1];

guidata(hObject, handles);

function Test_ButtonDownFcn(hObject)



pos = get(gca, 'CurrentPoint');
handles = guidata(gcf);
depth = sscanf(get(handles.edtDepth, 'String'), '%f');

if (get(handles.cbEdit, 'Value'))
    handles.offset = [pos(1,2), pos(1,1)];

    if (get(handles.cbP1, 'Value'))
        X = getPosition(pos(1,2), pos(1,1), depth, handles.F);
        handles.P1 = X;
    end
    if (get(handles.cbP2, 'Value'))
         X = getPosition(pos(1,2), pos(1,1), depth, handles.F);
        handles.P2 = X;
    end
    if (get(handles.cbOrigin, 'Value'))
        X = getPosition(pos(1,2), pos(1,1), depth, handles.F);
        handles.Origin = X;
    end
    guidata(hObject, handles);
    handles = guidata(hObject);
    refreshImage(handles);
end

function refreshImage(handles)
hold on;
cla;
h = imshow(handles.Image, 'Parent', handles.axes1);
hold on;
set(h,'ButtonDownFcn', 'CameraCalib(''Test_ButtonDownFcn'',gcbo)');

%set(h,'HitTest','off')

set(handles.cbP1, 'String', ['P1 = [' num2str(handles.P1(1)) ',' num2str(handles.P1(2)) ',' num2str(handles.P1(3)) ']']);
 set(handles.cbP2, 'String', ['P2 = [' num2str(handles.P2(1)) ',' num2str(handles.P2(2)) ',' num2str(handles.P2(3)) ']']);
 set(handles.cbOrigin, 'String', ['Origin = [' num2str(handles.Origin(1)) ',' num2str(handles.Origin(2)) ',' num2str(handles.Origin(3)) ']']);

 
 handles.R = updateR(handles);
 
P = handles.F*handles.R;
ImDims = handles.ImSize;

if get(handles.toggleDispScale,'Value')
    depth = sscanf(get(handles.edtDepth, 'String'), '%f');
    tickWidth = sscanf(get(handles.edtTickSep, 'String'), '%f');
    
    [xScale, yScale] = buildScaleXY(handles.F, depth, tickWidth, handles.offset(2), handles.offset(1), ImDims);
    plot(xScale(1,:), xScale(2,:),'.r');
    plot(yScale(1,:), yScale(2,:), '.g');
end

if get(handles.toggleDispGrid,'Value')
    
    tickWidth = sscanf(get(handles.edtTickGP, 'String'), '%f');
    length = sscanf(get(handles.edtLength, 'String'), '%f');
     height = sscanf(get(handles.edtHeight, 'String'), '%f');
    [xLines, yLines] = buildGridXY(P, tickWidth, length, height, handles);
    plot([xLines(1,1:end/2); xLines(1,end/2+1:end)], [xLines(2,1:end/2); xLines(2,end/2+1:end)],'r');
     plot([yLines(1,1:end/2); yLines(1,end/2+1:end)], [yLines(2,1:end/2); yLines(2,end/2+1:end)],'r');
    %plot(yScale(1,:), yScale(2,:), '.g');
end

if get(handles.toggleDisplayAxis,'Value')
    [aX aY aZ] = buildGridAxis(P);
    plot(aX(1,:),aX(2,:), 'r');
    text(aX(1,2),aX(2,2),'x');

    
    plot(aY(1,:),aY(2,:), 'g');
    text(aY(1,2),aY(2,2),'y');
    
    plot(aZ(1,:),aZ(2,:), 'b');
    text(aZ(1,2),aZ(2,2),'z');
    %plot(yScale(1,:), yScale(2,:), '.g');
end

function X = getPosition(yPos, xPos, depth, F)

Y = [xPos; yPos; 1];
R = [F(:,1), F(:,2) F(:,3)*depth];
X = inv(R)*Y;
X = X/X(3);
X(3) = depth;

function [X Y Z] = buildGridAxis(P)

x = [1000, 0,0]';

Axis3 = ones(4,4);
Axis3(1:3,1) = 0;
Axis3(1:3,2) = x;

y = [0, 1000, 0]';
Axis3(1:3,3) = y;

z = [0,0,1000]';
Axis3(1:3,4) = z;

Axis2 = zeros(3,4);
for i = 1:4
    Axis2(:,i) = P*Axis3(:,i);
end 
Axis2 = Axis2./(Axis2(ones(3,1)*3,:));

X = Axis2([1:2],[1,2]);
Y = Axis2([1:2],[1,3]);
Z = Axis2([1:2],[1,4]);


function R = updateR(handles)
x = [1, 0,0]';
y = handles.P2-handles.P1;
y(1) = 0;
y = y/norm(y);
z = cross(x,y);
R = [x, y, z];
c = handles.Origin;
R = [R, c];

function [xLines, yLines] = buildGridXY(P, tickWidth, length, height, handles)

%calc X and Y coord

ticks = 0:tickWidth:height;



nTicks = size(ticks,2);

xAxis = zeros(4, nTicks*2);
xAxis(4,:) = 1.0;
xAxis(2, 1:end/2) = ticks;
xAxis(2, end/2+1:end) = ticks;
xAxis(1, end/2+1:end) = length;

xLines = zeros(3,nTicks*2);
for i = 1:nTicks*2
    xLines(:,i) = P*xAxis(:,i);
end
xLines = xLines./(xLines(ones(3,1)*3, :));


% now do y axis
ticks = 0:tickWidth:length;

%ticks(4,:) = 1;

nTicks = size(ticks,2);

yAxis = zeros(4, nTicks*2);
yAxis(4,:) = 1.0;
yAxis(1, 1:end/2) = ticks;
yAxis(1, end/2+1:end) = ticks;
yAxis(2, end/2+1:end) = height;

yLines = zeros(3,nTicks*2);
for i = 1:nTicks*2
    yLines(:,i) = P*yAxis(:,i);
end
yLines = yLines./(yLines(ones(3,1)*3, :));

function [xScale, yScale] = buildScaleXY(F, depth, tickWidth, xOfset, YOfset, ImDims)

scales = F(1)*tickWidth/depth;

xScale = 0:abs(scales):ImDims(2);
[val pos] =  min(abs(xScale - xOfset));
xScale = xScale - (xScale(pos) - xOfset);
xScale(xScale < 0) = [];
xScale(xScale > ImDims(2)) = [];
xScale(2,:) = YOfset;



yScale = 0:abs(scales):ImDims(1);
[val pos] =  min(abs(yScale - YOfset));
yScale = yScale - min(yScale(pos)- YOfset);

yScale(2,:) = yScale;
yScale(:,yScale(2,:) < 0) = [];
yScale(:, yScale(2,:) > ImDims(1)) = [];
yScale(1,:) = xOfset;

% --- Executes on button press in pbSaveCalibration.
function pbSaveCalibration_Callback(hObject, eventdata, handles)
% hObject    handle to pbSaveCalibration (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
[filename, pathname] = UIPUTFILE('*.mat', 'Save Calibration Data', 'Image1.mat');

if (filename ~= 0)
   Camera.F = handles.F;
    handles.R = updateR(handles);
   Camera.R = handles.R;
   Camera.P = handles.F*handles.R;
   
   Camera.length = sscanf(get(handles.edtLength, 'String'), '%f');
   Camera.height = sscanf(get(handles.edtHeight, 'String'), '%f');
   Camera.focalLength = sscanf(get(handles.edtFocalLength, 'String'), '%f');
   Camera.sensorHeight = sscanf(get(handles.edtSensorHeight, 'String'), '%f');
   Camera.conversionFactor = handles.ImSize(1)/Camera.sensorHeight;
   
   save([pathname filename], 'Camera');
   
end

% --- Executes on button press in cbEdit.
function cbEdit_Callback(hObject, eventdata, handles)
% hObject    handle to cbEdit (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of cbEdit



function edtFocalLength_Callback(hObject, eventdata, handles)
% hObject    handle to edtFocalLength (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtFocalLength as text
%        str2double(get(hObject,'String')) returns contents of edtFocalLength as a double
setDefaultCamera(hObject, handles);
handles = guidata(hObject);
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtFocalLength_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtFocalLength (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called





function edtTickSep_Callback(hObject, eventdata, handles)
% hObject    handle to edtTickSep (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtTickSep as text
%        str2double(get(hObject,'String')) returns contents of edtTickSep as a double
setDefaultCamera(hObject, handles);
handles = guidata(hObject);
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtTickSep_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtTickSep (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end





function edtSensorHeight_Callback(hObject, eventdata, handles)
% hObject    handle to edtSensorHeight (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtSensorHeight as text
%        str2double(get(hObject,'String')) returns contents of edtSensorHeight as a double
setDefaultCamera(hObject, handles);
handles = guidata(hObject);
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtSensorHeight_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtSensorHeight (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function edtDepth_Callback(hObject, eventdata, handles)
% hObject    handle to edtDepth (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtDepth as text
%        str2double(get(hObject,'String')) returns contents of edtDepth as a double
setDefaultCamera(hObject, handles);
handles = guidata(hObject);
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtDepth_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtDepth (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on scroll wheel click while the figure is in focus.
function figure1_WindowScrollWheelFcn(hObject, eventdata, handles)
% hObject    handle to figure1 (see GCBO)
% eventdata  structure with the following fields (see FIGURE)
%	VerticalScrollCount: signed integer indicating direction and number of clicks
%	VerticalScrollAmount: number of lines scrolled for each click
% handles    structure with handles and user data (see GUIDATA)


P = handles.F*handles.R;

if (get(handles.cbEdit, 'Value'))
    depth = sscanf(get(handles.edtDepth, 'String'), '%f');
    depthInc = sscanf(get(handles.edtDepthInc, 'String'), '%f');
     
    depth = depth+ eventdata.VerticalScrollCount*depthInc;
    set(handles.edtDepth, 'String', num2str(depth));
    
    
    if (get(handles.cbP1, 'Value'))
        X = getPosition(handles.offset(1), handles.offset(2), depth, handles.F);
        handles.P1 = X;
    end
    if (get(handles.cbP2, 'Value'))
         X = getPosition(handles.offset(1), handles.offset(2), depth, handles.F);
        handles.P2 = X;
    end
    
    if (get(handles.cbOrigin, 'Value'))
         X = getPosition(handles.offset(1), handles.offset(2), depth, handles.F);
        handles.Origin = X;
    end
    guidata(hObject, handles);
    handles = guidata(hObject);
    refreshImage(handles);
    
    
end

function edtDepthInc_Callback(hObject, eventdata, handles)
% hObject    handle to edtDepthInc (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtDepthInc as text
%        str2double(get(hObject,'String')) returns contents of edtDepthInc as a double
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtDepthInc_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtDepthInc (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on mouse press over axes background.
function axes1_ButtonDownFcn(hObject, eventdata, handles)
% hObject    handle to axes1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
if get(handles.toggleDispScale,'Value')
   handles.offset = a; 
    
end



function edtTickGP_Callback(hObject, eventdata, handles)
% hObject    handle to edtTickGP (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtTickGP as text
%        str2double(get(hObject,'String')) returns contents of edtTickGP as a double
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtTickGP_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtTickGP (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function edtLength_Callback(hObject, eventdata, handles)
% hObject    handle to edtLength (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtLength as text
%        str2double(get(hObject,'String')) returns contents of edtLength as a double
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtLength_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtLength (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in cbP1.
function cbP1_Callback(hObject, eventdata, handles)
% hObject    handle to cbP1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of cbP1


% --- Executes on button press in cbP2.
function cbP2_Callback(hObject, eventdata, handles)
% hObject    handle to cbP2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of cbP2


% --- Executes on button press in cbOrigin.
function cbOrigin_Callback(hObject, eventdata, handles)
% hObject    handle to cbOrigin (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of cbOrigin



function edtHeight_Callback(hObject, eventdata, handles)
% hObject    handle to edtHeight (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of edtHeight as text
%        str2double(get(hObject,'String')) returns contents of edtHeight as a double
refreshImage(handles);

% --- Executes during object creation, after setting all properties.
function edtHeight_CreateFcn(hObject, eventdata, handles)
% hObject    handle to edtHeight (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

Contact us