ToF - Het Vlaams Innovatienetwerk

Transcription

ToF - Het Vlaams Innovatienetwerk
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Karel de Grote-Hogeschool Antwerpen vzw
Departement Industriële Wetenschappen en Technologie
Campus Hoboken, Salesianenlaan 30.
Technologie Transfer Project 100191: RGBd, ToF ! (2010-2012).
Industrial
Logic brings you from A to B …
creativity brings you anywhere …
but this takes its ‘time of flight’ … ToF.
(inspired by … )
Industrial VisionLab:
A. Einstein.
[email protected]
and
[email protected]
1
Association University and University Colleges Antwerp.
Tetra: RGBd, TOF!
Nr. 100191 .
RGBd, ToF !
Final Report IWT 2012.
www.innovatienetwerk.be/projects/1583
Organisationcompany
Contact person
Tel: 00 32
Project input
Industrieel VisieLab
http://project.iwtkdg.be
[email protected] 03 354 50 39
[email protected]
[email protected]
[email protected]
[email protected]
Jef Celen
[email protected]
[email protected]
03 613 17 62
Project leader.
Mathematician.
Project cooperator.
Team Leader.
PR Support .
Project advisor.
[email protected]
03 265 24 64
Project support
Publication.
Vision & Robotics 2011.
[email protected]
[email protected]
03 265 30 36
03 213 92 63
Valorisation
Innovation center.
[email protected]
[email protected]
03 265 23 12
0495 38 80 86
Representative from
‘Healthcare’
[email protected]
[email protected]
[email protected]
Karel [email protected]
[email protected] Koenraad Van de Veere
[email protected] Tor-Björn Johansson
03
03
03
09
IWT (Vlaanderen)
www.iwt.be/tetra
Active Perception Lab
www.ua.ac.be/apl
VisionLab UA
www.visielab.ua.ac.be
Interfacedienst
Universiteit Antwerpen
Centrum voor
Zorgtechnologie (CZT).
www.czt.ua.ac.be
Artesis Hogeschool
Ingenieurskamer VIK
www.vik.be
Phaer + ViiV.
www.phaer.be
Acro Diepenbeek
www.acro.be
EAVISE
www.eavise.be
Egemin
www.egemin.be
Hero Technologies
www.hero-technologies.be
HMC-International NV
www.hmc-products.com
Data Vision (MESA)
www.datvision.be
MESA Imaging
Ifm electronics n.v.
www.ifm.be
Iris-Vision
www.iris-vision.nl
www.optrima.com
Optrima NV Brussels
Softkinetic.
DEVISA bvba
www.sdvision.be
Vision & Robotics 2012
Microcentrum NL
Vision & Robotics (PR)
Vision++ , Heverlee
www.visionplusplus.com
Bedelec
Melexis
Voxdale
UA + Genicap
VIM
UA + VisieLab
Underwater Navigation
Caeleste
02 432 42 95
03 265 46 70
79
11
11
02
52
11
05
10
0474 57 81 57
[email protected]
Toon Goedemé: (De Nayer) Lessius
Hogeschool.
[email protected]
[email protected]
[email protected]
[email protected]
Tim Godden / Michel Vleminckx.
Deinze (Aalter) Hans Fraeyman
[email protected]
[email protected] (Johan de Vits)
[email protected]
011 27 88 20
015 31 69 44
0498/581507
03 641 12 10
03 641 18 58
03 827 43 93
0473 445 239
09 381 09 52
03 780 17 62
00 41445081824
02 481 02 20
[email protected]
Marc Everaert [email protected]
Dietmar Serbée ([email protected] )
René Stevens ( [email protected] )
[email protected]
[email protected] (Ilse ravyse)
www.softkinetic-optrima.com
Stefan de Vilder
[email protected]
www.vision-robotics.nl
Els Van De Ven. Seminar Manager
[email protected]
Liam Van Koert (Hoofdredacteur)
[email protected]
+31 (0)575 495 159
02 888 42 60
02 888 42 91
0486 84 18 29
+31402969922
Cooperation
KdG + Artesis .
Education Vision
VIK-Vorming. ie-net.
ViiV:
Vlaams Innovatieplatform
voor industriële visie.
Embedded technology
Case Studies AGV.
Case Studis Robotics
Case Study
Wheelchair Navigation
Company projects.
MESA
Industrial ToF cameras.
Studiedag.
Fotonic ToF camera’s
Indoor & Outdoor.
iisu. Local alternative for
‘Project Natal en Kinect
van XBox 360’ , Microsoft.
Clients SDVision.
Multiple view.
Vision Trade,
the Netherlands.
31 6 17588265
[email protected]
Geert Caenen & Kurt Cornelis
Industrial VisionLab:
213
259
259
265
016 40 53 07
Knowhow sharing.
Cases AGV
Case Automotive
Case Sewerage
Case Peppers
Case Mobility
Case Mice Observations
Case Robot Navigation
Case Distanza camera
[email protected]
and
[email protected]
2
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Introduction
This report gives an overview of many experiments carried out during the tetra project ‘RGBd,
ToF!’. It is written in order to convince companies that the so called Time of Flight
measurements can help them in a lot of applications. As far as we can imagine thousands of
new applications will arise in the next decade. Companies who like it to be helped can contact us.
Some programs aren’t given in full version since they belong to the IP of the lab. Of
course we can negociate about the valorization of this programs. Beside this program a
lot of other programs are available from other contract research and the paper we work
out around the practical calibration of time of flight cameras in real live circumstances.
In part 1 we present a lot of aspects on a step by step basis. Programs are more or less
independant from each other. Part 2 is more application based: this means that hardware and
software aspects are present at a higher level and integrated in a total construction. In this
document some powerpoint slides are incorporated, but it is useful to give attention to the full
collection of slides we made.
The document is a collection of Matlab and Halcon programs. It can inspire programmers in
finding good practices when using ToF cameras in industrial applications. We wish all Time of
flight users success during the creation of their own 3D-Vision-applications.
Often used variable names (alfabetic).
Alfa, beta, gamma: angular values.
bw,BW black/white image.
BWc Black/white image complement.
co
abbreviation for a cosine value: e.g. coA, coB ….
d,D
distance values.
Dd,dD Distance to distance ratio: world positions relative to camera pixel positions.
f
focale length measured in pixel.
ff, FF set of coordinates resulting from a FIND command.
G
Gaussian filter to reduce noise.
H
historgam for a certain population.
i
row counter.
ii
extension for the row counter i . e.g. ii = i*i .
I
Total number of rows in an image. Look e.g. [I J] = size(D).
I2
extension on value I; e.g. I2 = round(I/2) , or I2 = I+2 , or I2 = 2*I …
im,IM local name for an image.
j
column couter.
jj
extension for counter j. e.g. jj = j*j .
J
Total number of columns in an image. Look e.g. [I J] = size(D).
J2
extension on value I; e.g. J2 = round(J/2) , or J2 = J+2 , or J2 = 2*J …
l,L
intensity image, Luminance values.
LSf, LSb, MSf, MSb, HSf, HSb: low/medium/high speed, forward/backward.
mm minimum value in a sequence of values.
MM
maximum value in a sequence of values.
phi
angular coordinate of a World Point projected on a reference plane.
Angular value used for navigation.
O2,O3… matrix of order n, filled up with ‘ones’: Matlab ones(2), ones(3),… ones(n) .
R
cylinder coordinate of a World Point projected on a reference plane.
Rio,RIO Range, related to a Region Of Interest.
som sum over a sequence of values.
si
abbreviation for a sine value: e.g. siA, siB, …
t
counter in a for-loop.
u
Image coordintes relative to the optical center. u = j-J2 (Column counter).
v
Image coordintes relative to the optical center. v = i-I2 (Row counter).
x,y,z cartesian coordinates seen from the camera Point of view.
X,Y,Z relatieve coordinates seen from the AGV Point of view.
Industrial VisionLab:
[email protected]
and
[email protected]
3
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Karel de Grote-Hogeschool Antwerpen vzw.
Department Industrial Science and Technology
(University College, campus Hoboken, Belgium)
Part 1 (pages 1 -> 99)
1. General introduction about the ‘time of flight cameras’.
Red Green Blue cameras (RGB) have a long history yet and a lot of industrial applications work at
a high accuracy level. Based on photogrammetry random image shots of the 3D-world can be
combined to become high resolution and more or less real time 3D information from the scène.
Industrial vision packages (like Halcon, OpenCV, Matlab…) became mature to deal with this kind
of image information.
A second group of cameras uses the principle of ‘Time of Flight’. Their resolution is growing
fast and nowadays a grid of 200 by 200 measurement points can be refreshed in each image
shot, with an accuracy of about 5.10-3 m/m. In the recent past both camera types are combined
in one concept and this is very powerful since a lot of precise calibration activities become
overruled. This new type of RGBd-camera makes it possible to carry out efficient image
segmentations in order to become a correct perception of the different objects in the world.
Colour aspects alone are not robust enough to distinguish the objects. Neither ToF nor RGB
cameras are able to make correct interpretations. Combining both camera types deliver
synergetic possibilities which must be analysed carefully and used in practical circumstances.
Software must be worked out and proofs of concepts (demonstrators) must be delivered. At that
moment companies will feel the power of the new approach and will be smart enough to realize
that thousands of applications can be worked out on this combined principle.
With the recent international Trade Fair for Machine Vision and Identification Technologies
Stuttgart 2010-2011 as important reference for the state of the art of robotic vision technology
we mean that 3D-Vision Technology has many more opportunities than currently present and
used in the average European SME’s. We think about applications in rather weak structured
production environments in which automatic guided vehicles must operate; in which robots are in
full action, in which computer interactions are useful (e.g. Human Machine Interfacing, gaming)
or in which intelligent supervision has to be done on moving objects (e.g. Healthcare: fall
detection..).
Therefor our intentions are to design and work out some 3D-proofs of concepts in order
convince companies about the new possibilities that arise from this technology. Based
expected accuracy levels the best practices should be explored and expressed in terms
price/quality ratios. Advices must be given on how the newest 3D-Vision principals could
successfully incorporated in practice.
.
to
on
of
be
The core of the project should be a confrontation of the classic stereo or multiple view vision
applications with the abilities of Time of Flight (ToF) cameras and the mentioned RGBd cameras.
The dissemination of the 3D-vision results will be done in the courses and labs for Master
students as well as in many courses and seminars given to industry and SME’s. Also some
international cooperation is looked for. One of the opportunities was in cooperation with the
University College of Boudapest (Hongaria).
The fact that 3D-vision didn’t reach its full speed conditions in industrial practice has to do with
the overall complexity of real time 3D-vision intelligence, caused by the correspondence
Industrial VisionLab:
[email protected]
and
[email protected]
4
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
problem known for stereo vision. Problems arise from the tasks we like to solve: what’s the
object of interest, what view direction delivers optimal perception conditions, what is the better
zooming factor for an optimal contrast between the object and its background, how to deal with
unexpected reflections or shadow zones, what integration times must be advised for typical
lighting conditions, what are the world coordinates of the objects to be handled? This are
just a few questions for which the answers seem evident for us, ‘biological robots’. We don’t feel
any problem while doing our ‘robotic’ tasks at a high accuracy level and real time balanced. For
robots, seen as ‘artificial humans’, this is totally different. Beside the lack of a clear visual
perception system robots neither have ears or sophisticated tactile abilities (touch, thermal…)
which could help them to make dynamic decisions in the real world. In the active perception lab
of prof. Peremans (University Antwerp, Belgium) investigations are carried out on sonar principals
to offer robots auditive navigation capabilities. In the lab of prof. Claes (University Antwerp) one
uses the Lidar principal to give cars for invalid people the ability to register the distance to
surrounding objects and to find out if a car (wheelchair) keeps in track with a chosen trajectory.
In the biomedical lab of prof. Dirckx accurate laser measurement techniques are used to get
accurate 3D information of objects in the world (3D-position, 3D-deformation and/or 3D-speed
evaluation). This was once again proven during the recent ‘OptiMess’ conference, held in March
2012.
Despite of all these capabilities one has to realize that robots and automatic guided vehicles
remain very helpless with respect to visual, tactile en audio perceptions. Especially the real
time aspects and the correct interpretations of the relative position of the objects in
the scene form basic ‘bottlenecks’.
Nevertheless a new ‘breakthrough’ arises at the horizon. The innovative possibilities come
from the fact that so called RGBd-cameras introduce themselves on the market. With such
cameras the visual information in RGB and the depth information of the scène are captured by
one single camera. This fact must be seen as a revolution in the world of 3D perception
since this means that the old fashion way of stereo vision is deliberated from its hard calibration
requirements and deliberated from the time consuming correspondence evaluations. In contrast
with the well known ToF cameras and/or the Lidar laser measurement principles the common
visual contact with the world remains intact for RGBd cameras. Another benefit for the newest
types of cameras originates from the fact that the image information for colour and for distance is
controlled by the manufacturers hard- and software. This enlarges the compatibility of both
information streams and avoids unlikely calibration steps concerning the focal distances or the
damaging lens distortions. The disadvantage of pose calibrations for stereo vision setups are also
avoided by this RGBd type of cameras. In combination with the recent progress on the level of
hard- and software it is clear that SME’s should be informed and introduced in the new evolutions
especially in industrial 3D-vision possibilities. Such activity must narrow the gap between the
latest technological possibilities and the common used know how in industry. Efficient industrial
vision packages in combination with high speed hardware (like GPU’s, embedded software) form
a new basis for high speed evaluation in combination with high quality performance. And this is
what it is all about.
The project will communicate about the state of the art of RGBd driven Real Time 3DSupervisor possibilities in an industrial environment. From this the overall trust in 3D-vision
must grow to a level that ‘indoor and outdoor, nearby and real time 3D-vision’ grew out to a
higher level which is worthfull to realize in practice. Insight in the possibilities will strengthen the
European SME’s in their concurrence position. It will lead to specialized high tech jobs and
improved production speed. All these things give expression to the degree of valorisation that
might be expected with this new 3D-vision capabilities.
Antwerp, Belgium 15 September 2012 .
dr. ir. Luc Mertens &
Industrial VisionLab:
[email protected]
and
ing. Wim Abbeloos.
[email protected]
5
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
2. Application categories for ToF cameras
2.1. Appliaction domains for ‘Time of Flight cameras’.
Building technology



safety surveillance for automatic doors, gates and windows
Room, building and lift surveillance
present or not-present control
Industrial automation



Robot control
Machine safety and object security
Recognizing and measuring objects on conveyor belts
Transport technology




Track detection at stopping points
Pedestrian detection and protection
Calculating trafic volume
Railway platfrom monitoring
Military




Driverless vehicles
Recognizing and assured detection of incoming flying objects
Battle simulation
Land-up support for helicopter and airplanes
Logistics



Control and monitoring during package sorting
Volume measurements, eg. pallets and packages
Avoiding collisions between mobile systems.
Automotive





Avoidung collisions
Pre-Crash detection
Interior-room monitoring
Monitoring "dead angles"
Distance measurements
2.2. Overview of applications worked out during our tetra project.
1. DepthSense 311 camera.
2. ToF guided material handling (ifm-electronic O3D2xx). (Robotic application).
3D-character recognition, paprika handling program, beer vessels manipluation.
3. ToF guided AGV and Wheelchair navigation. Sewer inspections. ( MESA SR 4000 )
4. RGBd, ToF calibration: depth to colour, colour to depth information, ToF stitching.
Internal and external camera calibration. ( MESA SR 4000 ) + ( uEye )
Collinearity, Coplanarity and Cross Ratios.
5. Fall Detection for ederly people. ( MESA SR 4000 )
6. Outdoor applications for ToF cameras. ( Fotonic Z70 )
7. Euro Palet handling: a comparison of 4 ToF camera types.
Industrial VisionLab:
[email protected]
and
[email protected]
6
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
3. Image Acquisition for ifm-electronic/ Mesa/ DepthSense/ Fotonic
3.1. DepthSense 311
Download ‘OptriView and OptriImageRegistrationDemo’.
The programs can be reached via URL: www.softkinetic.com/PublicDownload.aspx
A. Hardware aspects (120x160 pixel ToF; 480x640 RGB):
1. Camera connection: RED = power , BLACK = camera !
2. PC connection: BLACK USB.
3. Extra Power Supply: RED USB.
B. Start the program ‘OptriView’
( = DepthSense Viewer ).
The program opens a Graphic User Interface (GUI) which acts as a Limited Software
Development Kit (SDK). You are able to do things like:
 framerate handling: default = 30 f/s.
 Confidence Threshold settings: the ratio between Luminace and distance.
If Confidence Threshold = 0 all measurements are accepted.
At a positive value a minimum Luminance needed before accepting the measurement.
 NIR-light intensity setting between 0 and 100% . Experiment with it in relation
to the maximum depth you like to measure.
 Activation of the RGB and/or ToF camera ( enable / disable ).
 Finding the 3D-objects borders or acquire common ToF images (phasemap).
 Reducing the image noise (denoising: yes/no ).
 via item VIEW: - show the ‘Confidence Map’.
- show the common RGB-image.
- show Colour on Depth (ColourOnDepth).
C. Start the program ‘OptriImageRegistrationDemo’:
RGBd .
The program shows ‘Coloured Point Clouds’. This are small and flat segments who have a position
description (x, y and z) and also a local colour definition. This colour is taken from the
corresponding RGB-image. Non defined fragments remain black.
With the combination: Shift 2 you can lower the ‘Confidence Level’ (less rejection).
Shift 8 the Confidence Threshold can be up scaled (more rejection).
With the functions (F1, F2 en F3) you can change on the presentation level:
Fnct 1 : brings colour to the ToF-image (ColorOnDepth).
Fnct 2 : the colour image becomes 3D-fragmented (DepthOnColor).
Fnct 3: depth is converted in to gray value (0-255). (DepthOnly).
With the ‘keyboard arrows up/down’ ‘, ’ you are able to change the relative camera position.
The point cloud will rotate on a corresponding way.
With the ‘ r ’ button you can reset the image in its original position. (Reset).
Industrial VisionLab:
[email protected]
and
[email protected]
7
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
3.2. TOF_LiveView from ifm-electronic O3D2xx camera
3.2.1: Acquire O3D2xx images based on its dll-files.
% 1. Install the MESA software and the Mesa Command Library.
% 2. Change the IP-address based on next procedure:
%
Start -> Control Panel -> Network and Sharing Centre.
%
Right Click on your Local Area Network and select ‘Properties'.
%
Select Internet Protocol Version 4 (TCP/IPv4) and Click ‘Properties'
%
Select the radio button which give entrance to 'free IP addressing'.
%
Set IP Address, (e.g. 192.168.1.xx where xx is any other than 42).
%
Click on Subnet mask, to apply default of 255.255.255.0
% 3. Connect computer and camera by means of the Ethernet-Network cable.
% 4. Connect the camera with the power supply: 12V DC .
% 5. Run this program and get ‘Distance’ and ‘Luminance’ data (174x144 pixel).
% Tetra project 100191: RGBd, TOF !
% Wim Abbeloos & Luc Mertens:
%
% Program: ' AcquireIFM.m '.
September 2012.
Industrial VisionLab.
function [D L]= AcquireIFM(inttime)
dllname = 'O3D2xxCamera'; headername = 'O3D2xxCameraMatlab.h';
IP = '192.168.0.69'; XMLPort = uint32( 8080 );
hwnd = libpointer( 'uint32Ptr', 0 ); FWversion = libpointer( 'stringPtr', 'xxxxxx' );
SensorType = libpointer( 'stringPtr', 'xxxxxxxxxx' );
if ~libisloaded( dllname ) loadlibrary( dllname, headername ); end;
for c = 1:3 % Try to connect camera.
[ answer, hwnd, IP, FWversion, SensorType ] = calllib( dllname,...
'O3D2XXConnect', hwnd, IP, XMLPort, FWversion, SensorType );
if answer == 0 disp( 'Camera Connected' );
calllib( dllname, 'O3D2XXPerformHeartBeat' ); break;
else calllib( dllname, 'O3D2XXDisconnect', 1 );
disp( strcat( 'Failed to connect, attempt no', num2str(c) ) );
if ( c == 3 ) error( 'Failed to connect' ); end; end; end;
calllib( dllname, 'O3D2XXSetTrigger', 4 ); % 4 = Software trigger.
head = libpointer('int32Ptr', zeros(1,21*4)); SIZE = uint32(64*50*4);
dat = libpointer('uint8Ptr', zeros(1,SIZE)); TCPport = int32(50002);
cam = struct( 'dllname', dllname, 'dat', dat, 'SIZE', SIZE,...
'head', head, 'TCPport', TCPport);
setfrontend = libpointer( 'int32Ptr', [1, 0, 3, inttime, inttime, 0] );
calllib( dllname, 'O3D2XXSetFrontendData', setfrontend );
% Front end parameters: [1, 0, 3, inttime, inttime, 0]
% 1. ModulationFrequency [0,1,2,3] default = 0; Range = 6.51m 7.38m 7.40m 45m.
% 2. Single or double sampling normal/high dynamic
% 3. Illumode: 0 = off, 1 = 'a' on, 2 = 'b' off, 3 = Illumination 'a and b' on.
% 4. First integration time [µs] (single sampling mode), 1-5000, default 2000.
% 5. Second integration time [µs] (double sampling mode), 1-5000.
% 6. Delay time [ms] default = 141 ms.
% Get frame:
calllib(cam.dllname, 'O3D2XXTriggerImage' ); datmode = int8( 'd' );
[answer,data,header] = calllib(cam.dllname, 'O3D2XXGetImageData',...
datmode, cam.dat, cam.SIZE, cam.head, cam.TCPport );
frame.D = double(typecast(data,'single')); frame.D = reshape(frame.D,64,50);
datmode = int8( 'i' ); [answer,data,header] = calllib(cam.dllname,...
'O3D2XXGetImageData',datmode,cam.dat,cam.SIZE,cam.head,cam.TCPport);
Industrial VisionLab:
[email protected]
and
[email protected]
8
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
frame.L = double(typecast(data,'single')); frame.L = reshape(frame.L,64,50);
Head = double(typecast(header(1:21),'single')); frame.time = Head(12:13);
D = frame.D; L = frame.L;
% Stop camera
dllname = 'O3D2xxCamera';
for c = 1:3 answer = calllib( dllname, 'O3D2XXDisconnect', 1 );
if answer == 0 disp( 'Camera disconnected' ); break;
else disp( strcat('Failed to disconnect, attempt no', num2str(c)));
pause(0.5); end; end;
if libisloaded( dllname ) unloadlibrary( dllname ); end;
figure(100);
% In order to test the setup: plot results.
subplot(131); imshow(D,[0.4 4]); title('Distance image: [0.4 4]');
subplot(132); imshow(L./D,[0.4 4]); title('Confidence image L./D .)');
subplot(133); imshow(L,[0.4 4]); title('Luminance image.');
3.2.2 Live O3D2xx View for O3D2xx-cameras,
based on its dll-files.
% Tetra project 100191: RGBd, TOF ! September 2012.
% Wim Abbeloos & Luc Mertens:
Industrial VisionLab.
%
% Program: AcquirePMD_live.m .
% Time of Flight Image Acquisition (PMDTechnolgies)
% This program is the smallest version to get live contact
% with the Time of Flight camera of PMDVision.
192.168.0.1
function LiveView()
min = 0.8; max = 4;
% Load library, connect camera...
[cam, height, width] = connectcamera('192.168.0.1', 6000);
distance = zeros(width, height, 'double');
distancePtr = libpointer('voidPtrPtr', distance);
for i = 1:30
acquireframe(cam,distancePtr);
% Read camera data.
distance = distancePtr.value;
imshow(distance,[min max],'InitialMagnification',800);
pause(0.01); end;
endsession(cam);
function [hnd,height,width] = connectcamera(IP,inttime)
if ~libisloaded('pmd')
warning('off'); loadlibrary pmdaccess pmdmsdk.h alias pmd;
warning('on'); end;
hnd = libpointer('voidPtrPtr',0);
calllib('pmd','pmdConnectTCPIP',hnd,IP);
widthPtr = libpointer('uint32Ptr',0);
calllib('pmd','pmdGetWidth',hnd,widthPtr);
width = widthPtr.value;
heightPtr = libpointer('uint32Ptr',0) ;
calllib('pmd','pmdGetHeight',hnd,heightPtr);
height = heightPtr.value;
calllib('pmd','pmdSetIntegrationTime',hnd,inttime);
function acquireframe( hnd, distancePtr )
calllib('pmd','pmdUpdate',hnd);
calllib('pmd','pmdGetDistances',hnd,distancePtr);
function endsession(hnd)
calllib('pmd','pmdDisconnect',hnd);
Industrial VisionLab:
[email protected]
and
[email protected]
9
Association University and University Colleges Antwerp.
3.3.
RGBd, ToF !
Final Report IWT 2012.
Camera activations: uEye + IFM cameras .
% Tetra project 100191: RGBd, TOF !
% Wim Abbeloos & Luc Mertens:
% Stephanie Buyse (Master student) & Rudi Penne.
%
% Program: Acquire_RGB_ToF_ifm.m
July 2012.
Industrial Vision Lab.
clear all; close all; home; delete(imaqfind); debug = true;
nimgs = 1; filename = 'img'; filefmt = '.mat';
% #images and format.
% uEye camera configuration: create camera object
if exist( 'ueye' ) stop( ueye ); flushdata( ueye ); clear( 'ueye' ); end;
ueye = videoinput('winvideo', 1, 'RGB24_1280x1024' );
prop = get( ueye, 'Source' );
% Display camera properties.
if debug warning( 'on' );
disp( 'Hardware Properties:' ); imaqhwinfo( 'winvideo', 1 )
disp( 'Camera Properties:' );
get( ueye )
disp( 'Exposure Properties:' ); propinfo( prop )
else warning( 'off' ); end;
triggerconfig( ueye, 'manual' );
% Set camera properties.
set( ueye, 'FramesPerTrigger', 1 ); set( ueye, 'TriggerRepeat', nimgs-1 );
set( prop, 'VerticalFlip', 'on' );
set( prop, 'ExposureMode', 'manual', 'Exposure', -3 );
% range: [-16 -3].
set( prop, 'GainMode', 'manual', 'Gain', 0 );
set( prop, 'ContrastMode', 'manual', 'Contrast', 0 );
start( ueye );
% Start camera.
% ifm camera configuration.
alg = algorithms();
% Load algorithms WIM.
inttime = 300;
% Integration time.
navg = 10;
% Number of images to average.
frame_array = zeros( 64, 50, navg, 2 );
% Initialize frame stack.
ifm = alg.startcamera( inttime );
for c1 = 1:nimgs trigger( ueye );
% uEye acquisition.
for c2 = 1:navg
% ifm acquisition.
frame = alg.getframe( ifm );
frame_array( :, :, c2, 1) = frame.L; frame_array( :, :, c2, 2) = frame.D; end;
L = mean( frame_array(:,:,:,1), 3 ); D = mean( frame_array(:,:,:,2), 3 );
rgbimg = getdata( ueye, 1 );
figure(1);
subplot(131); imshow( rgbimg ); title( strcat( 'RGB Image nr', num2str(c1) ) );
subplot(132); imshow( L, [] );
title( 'Intensity image' );
subplot(133); imshow( D, [0.55 0.8] ); title( 'Distance image' );
filename2 = strcat( filename, num2str(c1), filefmt );
save( filename2, 'D', 'L', 'rgbimg' );
%pause();
end;
% Close cameras
stop( ueye ); clear( 'ueye' );
alg.stopcamera();
Industrial VisionLab:
[email protected]
and
[email protected]
10
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4. Geometrical considerations about ToF data.
4.1. Normal vector components derived from ToF-images.
The components nx, ny and nz of the ‘normal vector’ at a point of a surface in the world can be found from the vector product of two
vectors present in or tangent to a curved surface. The vectors can be estimated from row and column wise ToF-camera information. Here,
the distances D1 and D2 are column wise related while D3 and D4 are row wise bounded. All the vectors have corresponding x, y and zcoordinates but these components need not to be calculated. In formulas we get:
nx
ny
=
nz
x1 - x2
x3 – x4
y1 - y2
x y3 – y4
z1 - z2
z3 – z4
If we use the abbreviations:
nx
ny
nz
=
=
D1.u1/d1 - D2.u2/d2
D3.u3/d3 - D4.u4/d4
D1.v1/d1 - D2.v2/d2 x
D3.v3/d3 - D4.v4/d4
D1.f/d1 -
D2.f/d2
D3.f/d3 - D4.f/d4
.
δ13 = D1D3/d1d3 ; δ14 = D1D4/d1d4 ; δ23 = D2D3/d2d3 ; δ24 = D2D4/d2d4 , then the vector product can be expressed as:
δ13.(v1-v3).f - δ14.(v1-v4).f - δ23.(v2-v3).f + δ24.(v2-v4).f
- [δ13.(u1-u3).f - δ14.(u1-u4).f - δ23.(u2-u3).f + δ24.(u2-u4).f ]
δ13.(u1v3 – u3v1) - δ14.(u1v4 – u4v1) - δ23.(u2v3 – u3v2) + δ24.(u2v4 – u4v2)
Under the special circumstances that: u1 = u2 = u, u3 = u-1, u4 = u+1, v1 = v-1, v2 = v+1 en v3 = v4 = v, we get:
nx
( δ14 + δ24 - δ13 - δ23 ).f
ny
=
nz
( δ23 + δ24 - δ13 - δ14 ).f
3
(v,u) 4
(v-1,u)
D3
n
D4
d1
(v,u+1) 2
D2
d2 (v+1,u)
δ13.(u+v-1) - δ14.(u-v+1) - δ23.(-u+v+1) + δ24.(-u-v-1)
nx
(D1/d1+ D2/d2).(D4/d4 - D3/d3).f
ny
=
nz
(D2/d2 - D1/d1).(D3/d3 + D4/d4).f
u.(D1/d1+ D2/d2)(D3/d3 - D4/d4) + v.(D1/d1- D2/d2)(D3/d3 + D4/d4) (D1/d1+ D2/d2)(D3/d3 + D4/d4)
nx =
f.(D1/d1+ D2/d2).(D4/d4 - D3/d3)
ny =
f.(D2/d2 - D1/d1).(D3/d3 + D4/d4)
nz
1
D1
Nx ~ (D4/d4 - D3/d3)/(D4/d4 + D3/d3).f
a division by
(D1/d1+ D2/d2)(D3/d3 + D4/d4)
= - [ u.nx + v.ny + (D1/d1+ D2/d2)(D3/d3 + D4/d4) ]
Industrial VisionLab:
[email protected]
and
Ny ~ (D2/d2 - D1/d1)/ (D2/d2 + D1/d1).f
Nz ~ - ( u.Nx + v.Ny + 1 ) ▪
[email protected]
11
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.2. Collinearity and coplanarity (straightness and flatness analysis).
Collinearity
Coplanarity
1
z
2
2
D1
z
1
3
D2
D3
D1
y
3
4
d1 f
d1
d2
d3
C
u
v
C
u
x
X
4.2.1. Colinearity is present if the next sequence of determinant equals zero.
x1
x2
x3
z1
z2
z3
1
1
1
=
D1.u1/d1
D2.u2/d2 D3.u3/d3
f.D1/d1
f.D2/d2
1
f.D3/d3
1
D1/d1
=
u1
u2
u3
f
f
f
D2/d2
1
D3/d3
d1/D1 d2/D2
= 0.
d3/D3
The determinant calculation can use an expansion over the last row while dividing by the factor f:
(d1/D1).(u2-u3) – (d2/D2).(u1-u3) + (d3/D3).(u1-u2) = 0 . (Collineratity Constraint)
For equidistant points the constraint becomes:
(d1/D1) – 2.(d2/D2) + (d3/D3) = 0 . (Equidistant Collineratity Constraint)
The continuation of this constraint delivers:
d/D = f(u)
and
∂²(d/D)/∂u² = 0 .
Column wise it holds that: d/D = f(v)
and
( Local Collinearity, row wise ).
∂²(d/D)/∂v² = 0 .
Notice that ∂²(d/D)/∂u² + ∂²(d/D)/∂v² can be zero without local flatness while
flatness itself means that the local Laplacian is zero.
4.2.2. Coplanarity delivers another constraint. The next determinant should equal zero.
D1.u1/d1
D2.u2/d2
D3.u3/d3
D4.u4/d4
D1.v1/d1
D2.v2/d2
D3.v3/d3
D4.v4/d4
f.D1/d1
f.D2/d2
f.D3/d3
1
1
1
f.D4/d4
D1/d1
0
D2/d2
=
0
D3/d4
1
D4/d4
det A
u1
u2
u3
u4
v1
v2
v3
v4
f
f
f
f
= 0.
d1/D1 d2/D2 d3/D3 d/D4
.
det B
Since det(A.B) = det(A).det(B) = 0 , de non zero value ‘det(A)’ can be ommitted. Expand the
determinant calculation of the matrix B over the last row and divide the result by the constant
Industrieel VisieLab:
[email protected] and
[email protected]
12
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
value f. The sub determinants that arise are formed by the components of the vectors di , i = 1:4.
(d1/D1).det([d2 d3 d4]) - (d2/D2).det([d1 d3 d4]) +
or,
(d3/D3).det([d1 d2 d4]) - (d4/D4).det([d1 d2 d3]) = 0
(d1/D1).[(u2v3
(d2/D2).[(u1v3
(d3/D3).[(u1v2
(d4/D4).[(u1v2
–
–
–
–
u3v2)
u3v1)
u2v1)
u2v1)
+
+
+
+
(u3v4
(u3v4
(u2v4
(u2v3
–
–
–
–
u4v3)
u4v3)
u4v2)
u3v2)
+
+
+
+
(u4v2
(u4v1
(u4v1
(u3v1
–
–
–
–
u2v4)]
u1v4)]
u1v4)]
u1v3)]
+
(Coplanarity
Constraint).
=0
For regular chosen vectors d1, d2, d3 and d4 (grid based) it can be proven that all determinants
are equal. In such case the ‘Coplanarity Constraint’ reduces it selves to:
d1/D1 - d2/D2 + d3/D3 - d4/D4 = 0
(Coplanarity Constraint for regular grids).
Remark: the coplanarity constraint can directly be found from the row wise and column
wise ToF collinearity constraints:
(d1/D1) – 2.(dM/DM) + (d2/D2) = 0 . (Column wise equidistant collineratity).
(d3/D3) – 2.(dM/DM) + (d4/D4) = 0 . (Row wise equidistant collineratity).
The difference gives:
(d1/D1) + (d2/D2) - (d3/D3) – (d4/D4) = 0
.
The sum gives: ∆²(d/D) = 0; (Laplacian at point M).
% Tetra project 100191: RGBd, TOF !
% Luc Mertens & Rudi Penne & Wim Abbeloos:
% Kenny Hemgenbergs (Masterstudent).
%
% Function: Indoor_Flatness_dD.m .
June 2012.
Industrial VisionLab.
close all; clear all; home; ThresFloor = -0.500; E = 0.6; % Floor at 0.6 m.
I = 144; J = 176; I2 = I/2; J2 = J/2; f = 150; ff = f*f; ku = 1.0; kv = 1.0;
a0 = pi/30; co = cos(a0); si = sin(a0);
% a0 = camera inclination.
E = 0.60;
% Floor corresponding to E = 600 mm.
u = ku*((1:J) - (J2+0.5)); uuff = u .* u + ff;
v = kv*((1:I) - (I2+0.5)); vv = v .* v;
U = repmat( u , [I 1]); UUff = repmat( uuff, [I 1]);
V = repmat( v', [1 J]); VV = repmat( vv',[1 J]);
d = sqrt( VV + UUff ); Ed = E*d; fsi = f*sin(a0);
% Camera inclination.
vco = kron(ones(1,J),v')*cos(a0); factor = fsi + vco;
name = 'T1TMv.mat';
% T1TLv.mat; T1TMv.mat; T1TRv.mat; T2TLv.mat;
% T2TMv.mat; T2TRv.mat; T3TMv.mat;
% T4TMv.mat; T5TLa.mat ; T5TLv.mat;
t0 = cputime;
load(name); [I J] = size(D); J2 = round(J/2); LD = double(L)./D;
D = medfilt2(D,[3 3]); ff = find(D< -0.1); D(ff) = 5*(1+rand); dD = d./D;
Balance = Ed - D.*factor; bwFloor = Balance < ThresFloor;
filter = [0 0 1 0 0;0 0 0 0 0;-1 0 0 0 -1;0 0 0 0 0;0 0 1 0 0];
Flat = conv2(dD,filter,'same'); bwFlat = abs(Flat) < 0.7 & ~bwFloor;
%bwFlat = imerode(bwFlat,ones(2));
% Erode after segmentation !
t0 = cputime - t0;
Industrieel VisieLab:
[email protected] and
[email protected]
13
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
figure(1);
subplot(221); imshow(D,[0.5 3]); title('Distances from [ 0.5 3 ].');
ylabel(name);
subplot(222); imshow(LD,[]);
title('Confidence Image.');
subplot(223); imshow(bwFloor); title('Free Floor.');
subplot(224); imshow(bwFlat);
title('Flat Parts.');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
ylabel('Coplanarity Check');
figure(2);
imshow(bwFlat); title('dD(i-2,j) - dD(i,j-2) + dD(i,j+2) - dD(i+2,j).');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
ylabel('Coplanarity Check dD = d./D . ');
Further ‘Erosion’ is advised after segmentation and after selection of a
‘segment of interest SOI’.
Industrieel VisieLab:
[email protected] and
[email protected]
14
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.3. Cross Ratios (straightness and flatness analysis).
Cross Ratios in practice.
ρ² =
Fast Flatness Analysis
D1/D3 + D3/D1 – 2.cos(D1,D3)
D1/D4 + D4/D1 – 2.cos(D1,D4)
D1² + D3² - 2.D1.D3.cos(D1,D3)
D1² + D4² - 2.D1.D4.cos(D1,D4)
=
D2² + D3² - 2.D2.D3.cos(D2,D3)
D2² + D4² - 2.D2.D4.cos(D2,D4)
D3/D2 + D2/D3 – 2.cos(D2,D3)
D2/D4 + D4/D2 – 2.cos(D4,D2)
2.cos(D1,D3) = [ d1² + d3² - (j3-j1)² ] / d1d3 = 2.cos(d1,d3)
2.cos(D1,D4) = [ d1² + d4² - (j4-j1)² ] / d1d4 = 2.cos(d1,d4)
2.cos(D2,D3) = [ d2² + d3² - (j3-j2)² ] / d2d3 = 2.cos(d2,d3)
2.cos(D2,D4) = [ d2² + d4² - (j4-j2)² ] / d2d4 = 2.cos(d2,d4)
D1
The cosine values can be calculated in advance !
{ [D1//D3 + D3/D1 – 2.cos(d1,d3) ].[D2//D4 + D4/D2 – 2.cos(d2,d4) ] }
1
2
D2
D4
{ [D1//D4 + D4/D1 – 2.cos(d1,d4) ].[D2//D3 + D3/D2 – 2.cos(d2,d3) ] }
j1
ρ² =
(j3 – j2)²/(j4 – j2)²
d1
= (9/16)/(4/9) = 81/64
j2
d2
d3
j3
d4
For equidistant pixels: ρ = 9/8
Optical centre
% Tetra project 100191: RGBd, TOF !
% Luc Mertens & Wim Abbeloos:
% Kenny Hemgenberghs (Master Student).
%
% Program: FreeFloorFlatnessCrossRatio.m
Industrieel VisieLab:
[email protected] and
4
D3
ρ² =
(j3 – j1)²/(j4 – j1)²
3
j4
sensor
2/5
September 2012.
Industrial VisionLab.
[email protected]
15
Association University and University Colleges Antwerp.
%
%
%
%
%
%
RGBd, ToF !
Final Report IWT 2012.
The 'real world flatness' is in strongly related with 'horizontal' and 'vertical'.
Therefore flatness analysis forms a strong basis of plane segmentation.
For navigation purposes its also important to evaluate the free floor area.
This aspects are present in the following program.
close all; clear all; home; f = 150; ff = f*f;
ThresFloor = 1; ThresVFlat = 3*10^-3; ThresHor = 1*10^-3;
I = 144; J = 176; I2 = round(I/2); J2 = round(J/2);
% Image dimensions.
u = [0.5:J-0.5]-J2; uuff = u.*u + ff; v = [0.5:I-0.5]-I2; vv = v.*v;
UUff = kron(uuff,ones(length(v),1)); VV = kron(vv',ones(1,J));
d = sqrt(UUff+VV);
% Distances from the optical centre to the pixels.
E = 0.600; Ed = E*d;
% Floor at a distance E = 600 mm.
a0 = pi/30; fsi = f*sin(a0);
% Camera inclination.
vco = kron(ones(1,J),v')*cos(a0); factor = fsi + vco;
% Prepare the Vertical Flatness Analyser.
d1 = d(:,1:end-4); d2 = d(:,2:end-3); d3 = d(:,4:end-1); d4 = d(:,5:end);
d13 = d1.*d3; d24 = d2.*d4; d14 = d1.*d4; d23 = d2.*d3;
cos13c = d1./d3 + d3./d1 - 9./d13; % Column wise values.
cos24c = d2./d4 + d4./d2 - 9./d24; % Column wise values.
cos14c = d1./d4 + d4./d1 - 16./d14; % Column wise values.
cos23c = d2./d3 + d3./d2 - 4./d23; % Column wise values.
% Images are: T1TLv, T1TMv, T1TRv, T2TRv, T2TMv, T2TLv...
name = 'T1TLv.mat'; load(name); t0 = cputime;
% 1. Fast Floor Analyser (FFA).
Dev = Ed - D.*factor; bwFloor = Dev < ThresFloor; % One sided Thresh.!
% 2. Connected Vertical Flatness Analyser.
D1 = D(:,1:end-4); D2 = D(:,2:end-3); D3 = D(:,4:end-1); D4 = D(:,5:end);
t1 = D1./D3 + D3./D1 - cos13c; t2 = D2./D4 + D4./D2 - cos24c;
n1 = D1./D4 + D4./D1 - cos14c; n2 = D2./D3 + D3./D2 - cos23c;
VFlat = abs(9*(t1.*t2) - 16*(n1.*n2));
% Column wise.
bwVFlat = abs(VFlat) < ThresVFlat;
bwVFlat = bwVFlat & ~bwFloor(:,3:end-2);
diffV = abs(diff(D)); bwV = diffV < 0.03;
diffH = abs(diff(D')); bwH = diffH' < 0.03;
bwVH = bwV(:,1:end-1) & bwH(1:end-1,:);
% Vert & Hor edges !
bwPlanes = bwVFlat(2:I-1,:) & bwVH(1:I-2,3:end-1);
[planes count] = bwlabel(bwPlanes,4); CC = []; % 4-connected labeling.
for c = 1:count, FF = find(planes == c);
% Remove small areas.
if length(FF) < 50 planes(FF) = 0; else CC = cat(2,CC,c); end; end;
LenCC = length(CC);
for c = 1:LenCC, FF = find(planes == CC(c)); planes(FF) = c; end;
t0 = cputime-t0;
figure(1);
subplot(221); imshow(bwFloor); title(' White = floor.');
xlabel('Deviation = E.d - D.*factor');
subplot(222); imshow(L./D,[]); title('Confidence image.'); xlabel(name);
subplot(223); imshow(bwPlanes); title('Connected Vertical Flat & ~Floor.');
xlabel(cat(2,'Connected if abs(diff) < 0.03 m.'));
subplot(224); imshow(planes,[-1 LenCC-1]); title('Labeled planes.');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
ylabel(cat(2,'# Planes = ', num2str(length(CC))));
Industrieel VisieLab:
[email protected] and
[email protected]
16
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
17
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
18
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Further ‘Erosion’ is adviced after segmentation and after selection of a
‘segment of interest SOI’.
Industrieel VisieLab:
[email protected] and
[email protected]
19
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.4. Free floor detection for fixed cameras.
The free floor area can be found from the measurement Di
and the location of its associated pixel (at the distance di ):
di/Di = e/E = [ f.sin(a0) + vi.cos(a0) ] / E .
The points on the floor fulfil the relation: E = (Di/di)[ f.sin(a0) + vi.cos(a0) ] .
camera
Camera
inclination = a0 .
f
di e
vi
zi
a0
Camera bounded
parallel to the floor.
E
Di
Floor.
% Tetra project 100191: RGBd, TOF !
September 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
%
%% Program
%
% For navigation purposes its important to evaluate the free floor area.
% The dimensions of this free floor determine the entrance possibilities
% for the AGV (wheelchair..).
close all; clear all; home; f = 150; ff = f*f; Thres = -0.500;
I = 144; J = 176; I2 = round(I/2); J2 = round(J/2);
% Image dimensions.
u = [0.5:J-0.5]-J2; uuff = u.*u + ff; v = [0.5:I-0.5]-I2; vv = v.*v;
UUff = kron(uuff,ones(length(v),1)); VV = kron(vv',ones(1,J));
d = sqrt(UUff+VV);
% Distances from the optical centre to the pixels.
E = 0.600; Ed = E*d;
% Floor corresponding to E = 600 mm.
a0 = pi/30; fsi = f*sin(a0);
% Camera inclination.
vco = kron(ones(1,J),v')*cos(a0); factor = fsi + vco;
load('T1TLv.mat'); t0 = cputime; Balance = Ed - D.*factor;
bwFloor = Balance < Thres; t0 = cputime-t0;
figure(1);
subplot(131); imshow(Balance,[]); title('E.d - D.[ f.sin(a0) + v.cos(a0) ]');
xlabel('Grey values');
subplot(132); imshow(L./D,[]); title('Confidence image.');
subplot(133); imshow(bwFloor); title(' White = floor.');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
Industrieel VisieLab:
[email protected] and
[email protected]
20
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.5. RGBd, ToF: images correspondence
4.5.1. The correspondence between parallel aligned cameras.
ToF
tx
RGB x
Consider the sine rule:
f
90°-b
vc
vt
a
F
sin(90-b)
sin(a+b)
--------------- = ---------------D
tx
b
tx = D.sin(a+b)/cos(b)
D
[1]
[2]
During a calibration step one can present
points P with a known position. The focal
distances f and F can be derived. From there
the basis tx can be calculated.
During camera usage the angle b can be
found as a function of D. From b and F the
calculation of the pixel position vc is
z
From [2] it follows that: tx = DP.[ sin(a).cos(b) + cos(a).sin(b) ] / cos(b)
tx /D = sin(a) + cos(a).tg(b)
tg(b) = [tx/D - sin(a) ] / cos(a) = vc/F ;
________
vc,P/F = tx/√(zP² + yP²) – tg(aP) ; Take care for the sign: tg(a) = - kv.vt,P/f .
_______
vc,P/F = tx/√(z²P + y²P) + kv.vt,P/f .
__________
vc,P/F – kv.vt/f = tx/√(z²P + y²P) .
[3]
The left hand side of [3] may be seen as an extended ‘disparity’.
Ponits on the optical axis of the colour camera fullfill the relation:
tx = Dc.sin(ac) . (best fit over more points Pc)
___________
tx = Dc.kv.vt,Pc / √f²+(kv.vt,Pc)² .
[4]
Remark: the value tx is undependent from the F-value changings (e.g. focal steps).
Based on logarithmic differentiantion the relative accuracy of the value tx can be
expressed as a function of the errors dD and daPc . iet te klein mag zijn:
dtx/tx = dD/D + d[sin(aPc)]/sin(aPc)
dtx /tx = dD/D + cotg(aPc).daPc
( relatieve error on tx in % ).
[5]
De punten Pt op de optische as van de ToF-camera kunnen benut worden om F te ijken:
vt = 0 en xPt = yPt = 0 
F = vc,Q1.zPt/tx .
[6]
Voor de rijcoördinaten ut en uc van goed uitgelijnde camera’s, kan men het vlak beschouwen
dat door de basis en door het ruimtelijke punt P gaat. Er geldt dan:
uc/F = ku.ut/f
Industrieel VisieLab:
( de relatieve rijcoördinaten zijn gelijk ) .
[email protected] and
[email protected]
[7]
21
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.5.2. De correspondentie tussen een RGB en een hellende ToF-camera
We veronderstellen beide camera-horizonten in hetzelfde platte vlak.
Of, ty = 0 + relatieve camerarotatie = 0 + gelijk georiënteerde y-assen. !
De loodrechte stand van een RGB-camera ten opzichte van het werkvlak kan men eenvoudig
realiseren met behulp van een spiegel. De beeldkrommings-constanten kt en kc voor beide
camera’s kunnen vooraf door ijking worden vastgelegd. (Remember: straight lines should be
straight!). De distorsiecorrectie kan onafhankelijk uitgevoerd worden op beide beelden en leidt
dan tot de zogenaamde ‘pin hole views’, verbonden door de translatie-vector t(tx,tz). (Nota: ty
= 0 !) . Bij het zoeken naar de translatie t beschouwen we de
punten P, Q en R :
P ligt op de optische as van de ToF-camera.
Q ligt op de optische as van de RGB-camera.
ToF
tz
x
P en Q liggen in het vlak π op een meetbare
tx
afstand δ. ( P en Q spelen een sleutelrol, zoals
de epipolen dat doen bij stereovisie ) .
f
F
Het ‘ToF optische centrum’ ligt op een hoogte Ht
vt,Q
vc,P
Het ‘RGB optische centrum’ ligt op een hoogte Hc
Het hoogteverschil tz := Ht - Hc (hier negatief !)
Na de calibratie van de ToF-camera tegenover
het werkvlak π , bekomt men zeer betrouwbare
waarden voor f , ku , kv, DP , aP en δ (zie
vroeger). Verder geldt opeenvolgend:
b
b
Ht
Hc
( best fit value )
( best fit value )
( best fit value )
Verder geldt voor de punten P en R ook:
DT
vc,P/δ = F/Hc en vc,R/δ = F/(Hc–ε) ,
vc,P.Hc = F.δ = vc,R.(Hc–ε) ,
Hc.(vc,R - vc,P) = vc,R . ε .
aP
δ
[4] Hc = ε/(1 - vc,P/vc,R) ; tz = HP – Hc ;
[5] F = vc,P.Hc/δ = (ε/δ)/(v-1c,P – v-1c,R)
R
ε
T
DP
Daarmee is de calibratie rond. Ze leidde tot de
parameters: kt, kc, tx, tz, f, ku, kv, DP,aP, δ en F
DQ
π
xP
[1] Ht = cos(aP).DP
[2] xP = sin(aP).DP
[3] tx = xP + δ .
P
δ
Q
Voor elk willekeurig punt T geldt nu de volgende
beeldcorrespondentie. Vertrek bij de ToF-camera
1. aT = atan2(kv.vt,T , f) ( hier negatief !); HT = DT.cos(aP - aT) ; XT = DT.sin(aP - aT) ;
waaruit volgt: tg(b) = vc,T / F = ( tx - XT )/( HT -tz) ; waaruit volgt:
Indien aP = 0:
vc,T / F = [ tx/DT - sin(aP-aT)]/[cos(aP-aT) - tz/DT] .
vc,T / F = [ tx/DT + sin(aT)]/ [cos(aT) - tz/DT] .
[6]
[6’]
2. Op vergelijkbare wijze:
bT = atan2(ku.ut,T , f) ; (let op: de hoek bT ligt in een loodvlak op de tekening) .
YT = DT.sin(bT) => tg(bT) = uc,T/ F = YT/(HT -tz) ; waaruit volgt:
uc,T/ F = sin(bT)/[cos(aP-aT) - tz/DT]
Indien aP = 0: uc,T/ F = sin(bT)/[cos(aT) - tz/DT]
Industrieel VisieLab:
[email protected] and
[7]
[7’]
[email protected]
22
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.5.3. Matlab program: image correspondence
% Tetra project 100191: RGBd, TOF !
July 2012.
% Luc Mertens & Wim Abbeloos:
Industrial Vision Lab.
% Stephanie Buyse (Master student) & Rudi Penne.
%
% Program: ToF versus RGB Correspondency
%
% The correspondence between a ToF and an RGB image must be found.
% As a proof of concept we take images of a disk and show that the boarder
% is associated well.
% size(RGB) = 1280 x 1024 x 3
% size(ToF) = 64 x 50
% The values B and b0 should be calibrated in advance.
close all; clear all; format short; home; rep = 'replicate';
% 1. From previous calibrations we found:
B = 110; z0 = 672; f = 81; F = 2900;
corrI = -35; corrJ = -100;
% Corrections in order to outline ToF and RGB.
% 2. Load and initialize images.
load('RGBd2_disk.mat'); D = 1000*rot90(D,-1);
% General data in mm.
Time = cputime;
f4 = 4*f; G = fspecial('gaussian',9,1.5);
O2 = ones(2); O3 = ones(3); O4 = ones(4);
[It Jt] = size(D); It2 = It/2; Jt2 = Jt/2;
RGB = rgbimg; Gray = rgb2gray(RGB); [Ig Jg] = size(Gray);
Ig2 = round(Ig/2); Jg2 = round(Jg/2);
ff = f*f;
ut = [0.5:Jt-0.5]-Jt2; uut = ut.*ut; % column pixel values ut = -Jt/2:Jt/2 .
vt = [0.5:It-0.5]-It2; vvt = vt.*vt; % row pixel values
vt = -It/2:It/2 .
Ut = kron(ut,ones(It,1));
% Row wise extension (Kronecker product).
UUt = kron(uut,ones(It,1));
Vt = kron(vt',ones(1,Jt));
% Column wise extension (Kronecker product).
VVt = kron(vvt',ones(1,Jt));
VVfft = VVt+ff;
d = sqrt(UUt+VVt+ff);
% Pythagoras. Internal camera distances --> LUT.
Dd = D./d;
% Distance ratios for world points.
x = Ut.*Dd;
% Camera x-coordinates.
y = Vt.*Dd;
% Camera y-coordinates. Downwards oriented !!
z = f*Dd;
% Camera z-coordinates.
x = kron(x,O4); y = kron(y,O4); z = kron(z,O4);
It = 4*It; Jt = 4*Jt; It2 = It/2; Jt2 = Jt/2;
x = round(imfilter(x,G,rep)); y = round(imfilter(y,G,rep));
z = round(imfilter(z,G,rep)); Df = sqrt(x.*x + y.*y + z.*z);
bwCircle = z < z0-5;
% Disk on a flat plane at a distance 672 mm.
bwCircle = imerode(bwCircle,O4);
bwCircle = imdilate(bwCircle,O4);
% Denoise.
border = imdilate(bwCircle,O3) & ~imerode(bwCircle,O2);
FF = find(border == true); z(FF) = 1000;
c0 = z(It2,Jt2)/Df(It2,Jt2); s0 = sqrt(1-c0*c0) ; t0 = s0/c0; % c0 = cos(a0).
for it = 1:It, ut = it-It2;
for jt = 1:Jt, vt = jt-Jt2;
if border(it,jt) == true
xt = x(it,jt); yt = y(it,jt); zt = z(it,jt);
jc = Jg2-round(F*( B/zt - (f4*t0 + vt)/(f4- t0*vt) )) + corrJ;
Industrieel VisieLab:
[email protected] and
[email protected]
23
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
ic = Ig2+round(ut*F/(f4*c0 - vt*s0)) + corrI; % Take care the borders might be crossed.
Gray(ic-1:ic+1,jc-1:jc+1) = 255; end; end; end;
Time = cputime - Time;
figure(1);
subplot(221); imshow(Df,[]);
title('Filtered distance data.');
subplot(222); imshow(z,[]);
title('z-values');
subplot(223); imshow(RGB);
title('RGB-image Ueye');
subplot(224); imshow(bwCircle); title('bwCircle: raw filtering');
figure(2);
subplot(121); imshow(Df,[]); title('Range Image');
subplot(122); imshow(Gray); title('From colour to Gray');
xlabel('Correspondency indicated: white spots.');
figure(3);
subplot(131); imshow(z,[]); title('ToF image: z-values.');
xlabel('Disk border positions');
subplot(132); imshow(Gray); title('Gray image.');
xlabel('Corresponding Gray positions.');
subplot(133); imshow(bwCircle); title('bwCircle.');
figure(4); imshow(Gray); title('Correspondence.');
xlabel(cat(2,'f = ',num2str(f),' F = ',num2str(F), ' B = ',num2str(B), ' a0 = ',...
num2str(asin(s0)) ));
ylabel(cat(2,'CPUtime = ',num2str(Time)));
From ‘ToF disk border’ positions to corresponding ‘Gray image positions’.
Industrieel VisieLab:
[email protected] and
[email protected]
24
Association University and University Colleges Antwerp.
4.5.6.
RGBd, ToF !
Final Report IWT 2012.
Matlab program.
% Tetra project 100191: RGBd, TOF !
January 2012.
% Wim Abbeloos & Luc Mertens:
Industrial Vision Lab.
% Stephanie Buyse (Master student) & Rudi Penne.
%
% Program: RGBd_Calib2012.m
%
% The correspondence between a ToF and an RGB image must be found.
% As a proof of concept we take images of a chekerboard and show the colour
% to distance image (colour2distance).
clear all; close all; home;
load XYZ % XYZ = 3x80x24 Cartesian coord. of the 80 corners in 24 images.
load RGBd_tof_corners % Corners = 2x80x25 image coordinates (25 images).
% Corners_D = 80x25 distances (25 images).
X = XYZ(1,:,:); X = X(:);
% X-coordinates of 80x24 = 1920 points.
Y = XYZ(2,:,:); Y = Y(:);
% Y-coordinates of 80x24 = 1920 points.
Z = XYZ(3,:,:); Z = Z(:);
% Z-coordinates of 80x24 = 1920 points.
D = corners_D(:,2:25); D = 1000*D(:); % Distances of 80x24 = 1920 points.
% 1. Find translation vector: minimalize the cost function
t0 = [80 0 0]
minfunc = @(t) sum((( X+t(1)).^2 + (Y+t(2)).^2 + (Z+t(3)).^2 - D.^2) .^2) ;
[ t t_cost ] = fminsearch( minfunc , t0 )
t=t
% t is the best fit translation after one iteration.
% 2. Find improved intrinsic parameters of TOF camera
u = corners(1,:,2:25); u = u(:)/10;
% u/10-coordinates of 80x24 points.
v = corners(2,:,2:25); v = v(:)/10;
% v/10-coordinates of 80x24 points.
x = cat(2, u, v, ones(size(u)) );
% Table = [ u v 1] ; 1920 rows 3 columns.
for qq = 1:10 % Iterate to refine the translation and the TOF internal parameters.
A = []; b = [];
for q = 1:size(X(:))
% For 80x24 points.
A = cat(1,A,[(X(q)+t(1))/(Z(q)+t(3)) 0 1 0; 0 (Y(q)+t(2))/(Z(q)+t(3)) 0 1 ]);
b = cat( 1, b, [ u(q); v(q) ]); end;
P = A \ b % Focal length u, focale length v, central point u0, central point v0.
temp = inv([P(1) 0 P(3); 0 P(2) P(4); 0 0 1]) * x';
n = sqrt( temp(1,:).^2 + temp(2,:).^2 + 1);
n = repmat( n, [3 1]); d = repmat( D', [3 1]); xyz = d .* temp ./ n;
t = [ mean(xyz(1,:)-X') mean(xyz(2,:)-Y') mean(xyz(3,:)-Z') ]
end
% 3. Transform distance to XYZ
load('RGBd12');
error_points = D < 0; D(error_points) = 5;
ups = 0;
% Interpolation factor related with 2^ups.
D = interp2(D,ups);
% Linear interpolated distances.
L = interp2(L,ups);
% Linear interpolated luminaces.
[I J] = size(D); ut = repmat( 0:J-1, [I 1] ); vt = repmat( (0:I-1)', [1 J] );
ut = ut(:); vt = vt(:); Dt = D(:);
xt = cat(2, ut, vt, ones(size(ut)) );
temp = inv([2^(ups)*P(1) 0 2^(ups)*P(3); 0 2^(ups)*P(2) 2^(ups)*P(4); 0 0 1])*xt';
n = sqrt( temp(1,:).^2 + temp(2,:).^2 + temp(3,:).^2 );
n = repmat(n, [3 1]); d = repmat(Dt', [3 1]); xyz = d.*temp./n;
x = xyz(1,:)*1000 - t(1);
% From ToF coordinates to RGB(x) coordinates.
y = xyz(2,:)*1000 - t(2);
% From ToF coordinates to RGB(y) coordinates.
z = xyz(3,:)*1000 - t(3);
% From ToF coordinates to RGB(z) coordinates.
% From a previous calibration of the RGB-camera we found:
f = [ 1153.99786 1154.35200 ];
% Focal Lengths.
c = [ 485.32366 582.87738 ];
% Central point (u,v) .
k = [ -0.18174 0.15183 -0.00045 0.00201 0.00000 ]; % Distortion param.
Industrieel VisieLab:
[email protected] and
[email protected]
25
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
a = x./z; b = y./z;
% Project 3D coordinates onto color image.
r = sqrt(a.^2 + b.^2);
xx = a .* (1 + k(1)*r.^2 + k(2).*r.^4) + 2*k(3)*a.*b + k(4)*(r.^2 + 2*a.^2);
yy = b .* (1 + k(1)*r.^2 + k(2).*r.^4) + k(3)*(r.^2 + 2*b.^2) + 2*k(4)*a.*b;
xxp = f(1)*xx + c(1);
% If negative, take 1; if to big take border.
xxp = max(xxp,1); xxp = min(xxp, size(rgb,2)); % Keep points inside the image.
yyp = f(2)*yy + c(2); yyp = max(yyp, 1); yyp = min(yyp, size(rgb,1));
C = zeros( size(xxp(:)),3 );
% Assign colour to 64*50 ToF pixels.
for q = 1:size(xxp(:)) C(q,:) = rgb( round(yyp(q)), round(xxp(q)), : ); end;
figure(1);
subplot(131); imshow(D,[0.5 1]); title('Raw distance data.');
subplot(132); imshow(L,[]); title('Raw lunimance data.');
subplot(133); imshow(rgb); title('Raw RGB data.');
figure(2);
xr = reshape(xyz(1,:),I,J); yr = reshape(xyz(2,:),I,J), zr = reshape(xyz(3,:),I,J);
surf(xr,yr,zr, L, 'LineStyle', 'None');
xlim( [-0.3 0.3] ); ylim( [-0.3 0.3] ); zlim( [0 1.2] );
xlabel( 'X' ); ylabel( 'Y' ); zlabel( 'Z' );
daspect( [1 1 1] ); colormap( 'gray' );
cameratoolbar( 'Show' ); cameratoolbar( 'SetMode', 'Orbit' );
title( 'ToF camera coordinates presented in 3D.' );
figure(3);
imshow( rgb ); hold on; plot( xxp, yyp, 'r.','Linewidth',0.1);
title('ToF points projected onto the colour image');
xlabel('64 rows, 50 columns')
figure(4);
surf(xr,yr,zr,reshape(C/255,I,J,3), 'LineStyle', 'None' );
xlim( [-0.3 0.3] ); ylim( [-0.3 0.3] ); zlim( [0 1.2] );
xlabel( 'X' ); ylabel( 'Y' ); zlabel( 'Z' );
daspect( [1 1 1] );
cameratoolbar( 'Show' ); cameratoolbar( 'SetMode', 'Orbit' );
title( '3D + colour reconstruction' );
Industrieel VisieLab:
[email protected] and
[email protected]
26
Association University and University Colleges Antwerp.
Colour to Depth
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
Depth to Colour
[email protected]
27
Association University and University Colleges Antwerp.
5.
RGBd, ToF !
Final Report IWT 2012.
The calibration of ToF-cameras.
Definition: the distances from the pinhole center to the different sensor points (pixels)
are named the Internal Radial Distances (IRD). Calibration can be developed
in terms of IRD’s. The calibration of a camera can be seen as the activity during which one is
able to find the final most accurate IRD-values.[Luc Mertens, Rudi Penne & Wim Abbeloos 2012].
We will proof that a ToF-camera can be calibrated based on the perception of flat objects. Since
‘Straigthness and Flatness’ are primitive geometrical properties, they are independent of the
camera position or orientation. Therefor the internal calibration parameters should have such
values that the perception of the camera about straightness and flatness is guaranteed from
ervery point of view.
5.1. First calibration step: Focal length + row and column wise scale factors.
Een zeer eenvoudige calibratiestap leidt tot de intrinsieke ToF-camera
parameters: ku, kv, f, ( + distorsie parameters ).
f = 140.0
f = 80.0
Introduction Program used for calibration
% Tetra project 100191: RGBd, TOF !
September 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
%
% Program: 'CalibrationRowColumn.m'.
%
% During the calibration step a flat plane is presented to the camera.
% Row wise median filtering is used as a horizontal noise suppressor.
% Just the horizon and its perpendicular direction are inspected.
% Combined with a good guess for the focal value f , the values ku and kv
% are derived. They represent the asymmetry between the row wise and the
% column wise pixel locations of the optical sensor.
% Meanwhile the inclination of the world lines are found and expressed as best fit
% calculation: z = a + b.x (row wise) and z = a' + c.y (column wise) .
close all; clear all; home;
Industrieel VisieLab:
[email protected] and
[email protected]
28
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
load('ifm_PLANE.mat'); f = 80; f4 = 4*f; ff = f4*f4;
D = rot90(D,2); G = fspecial('gaussian',11,2.2);
D = kron(D,ones(4)); D = imfilter(D,G,'replicate');
figure(10); imshow(D,[]); title('Raw image data: distances').
[I J] = size(D); ID2 = I/2; JD2 = J/2;
DD = 1000*sum( D(ID2:ID2+1,11:end-10) )/2;
J = length(DD); J2 = round(J/2); STD = []; Z = []; range = 0.90:0.001:1.1;
for ku = range
% ku is a grid factor in the u-direction (row wise).
u = ku*([0.5:J-0.5]-J2); uu = u.*u;
% column pixel values u = -J/2:J/2 .
d = sqrt(uu + ff); DDd = DD./d;
% Distance ratios for world points.
x = u.*DDd; z = f4*DDd;
% Camera x,z-coordinates.
data = cat(2,ones(J,1),x(:)); a = data\z(:); % Best Fit over the camera horizon.
ROT = atan2(a(2),1);
% Rotation around the y-axis.
co = cos(ROT); si = sin(ROT); zz = co*z - si*x; stdz = std(zz); Z = cat(1,Z,zz);
STD = cat(2,STD,stdz); end;
disp(cat(2,'Grondvlak z = ',num2str(a(1)),' + (',num2str(abs(a(2))),').x '));
a(1) = round(10*a(1))/10; a(2) = round(1000*a(2))/1000;
[mmSTD r] = min(STD); ku = range(r);
figure(1); hold on; plot(range, STD); plot([ku ku],[0 mmSTD],'r');
title('Horizontal grid calibration. Standard deviations.');
xlabel(cat(2,'ku = ', num2str(ku), ...
'
z = ', num2str(a(1)), ' + (', num2str(a(2)),').x')) ;
ylabel(cat(2, 'ROT = ',num2str(ROT)));
figure(2); Zr = Z(r,:); Zr = Zr - mean(Zr); hold on; plot(Zr);
plot([1 length(Zr)],[0 0],'r'); title('Spread relative to the plane');
xlabel(cat(2,'Horizontal standard deviation = ',num2str(mmSTD)));
DD = 1000*sum( D(11:end-10,JD2:JD2+1),2)/2; corr = -0.5 ;
I = length(DD); I2 = round(I/2); for i = 1:2:I, DD(i) = DD(i)+corr; end;
STD = []; Z = [];
for kv = range
% kv is a grid factor in the v-direction (column wise).
v = kv*([0.5:I-0.5]-I2); vv = v.*v;
% row pixel values v = -I/2:I/2 .
d = sqrt(vv + ff); DDd = DD'./d;
% Distance ratios for world points.
y = v.*DDd; z = f4*DDd;
% Camera y,z-coordinates.
data = cat(2,ones(I,1),y(:)); a = data\z(:); ROT = atan2(a(2),1);
co = cos(ROT); si = sin(ROT); zz = co*z - si*y; Z = cat(1,Z,zz);
STD = cat(2,STD,std(zz)); end;
disp(cat(2,'Grondvlak z = ',num2str(a(1)),' - ',num2str(abs(a(2))),'.y '));
a(1) = round(10*a(1))/10; a(2) = round(1000*a(2))/1000;
[mmSTD r] = min(STD); kv = range(r);
figure(3); hold on; plot(range, STD); plot([kv kv],[0 mmSTD],'r');
title('Vertical grid calibration. Standard deviation.');
xlabel(cat(2,'f = ', num2str(f), '
kv = ', num2str(kv), ...
'
z = ', num2str(a(1)), ' + (', num2str(a(2)),').y')) ;
ylabel(cat(2, 'ROT = ',num2str(ROT)));
figure(4); Zr = Z(r,:); Zr = Zr - mean(Zr); hold on; plot(Zr);
plot([1 length(Zr)],[0 0],'r'); title('Spread relative to the plane');
xlabel(cat(2,'Vertical standard deviation = ',num2str(mmSTD)));
Industrieel VisieLab:
[email protected] and
[email protected]
29
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Focal length
f = 80.0
Outcome: focal length f ; row and column wise scale factors kv and ku .
In extention also the row and column wise distortion
coefficients kkv and kku can be looked for. See below.
Industrieel VisieLab:
[email protected] and
[email protected]
30
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
4.2. Second calibration step: calibration of the work plane.
Calibration: based on the
perception of a flat plane:
f , ku , kv
z
• Select a rough substrate.
• Evaluate the row and column wise
standard deviations as a function of
the integration time.
• Eliminate (if present) the systematic
odd-even-errors.
• Make use of an adequate filter:
Gaussian, Mean, Median, …
• Calculate the best fit reference
plane: z = a + b.x + c.y .
• Find the camera rotation angles:
ROTx and ROTy .
• Find the central distance z0.
Calibration = shoot some images,
calculate the parameters…
At that moment the camera is
ready for use: … ToF !
ToF VISION: world to image, image to world – conversion.
1
1
j
J/2
i
J
phi
horiz
I/2
f
I
z
on
R
(0,0,f)
A
u.ku
r
D
v.kv
N
kr,kc
d
u = j – J/2 ; xu = ku*u
v = i – I/2 ; yv = kv*v
x
tg φ = xu/f
y
Aan elk wereldpunt en aan zijn locale omgeving kunnen
12 belangrijke coördinaten verbonden worden:
x, y, z,
Nx, Ny, Nz, N, kr, kc,
Industrieel VisieLab:
R, G, B .
[email protected] and
r = √(xu²+f²)
d = √(xu²+yv²+f²)
D/d = x/xu = y/yv = z/f
[email protected]
31
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Tetra project 100191: RGBd, TOF !
September 2011.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
%
% Program: 'CalibrationPlane.m'.
%
% During the calibration step a flat plane is presented to the camera.
% Row wise median filtering is used as a horizontal noise suppressor.
% Mean filtering is used as a column wise noise suppressor.
% The inclination of the plane is found from a best fit calculation z = a.x + b.y + c.
close all; clear all; home; f = 80; ku = 0.965 ; kv =1.000; f2 = 2*f; corr = 0.005;
load('ifm_PLANE.mat');
[I J] = size(D); I2 = I/2; J2 = J/2; for i = 1:2:I, D(i) = D(i)-corr; end;
ROIi = 15:I-14; ROIj =15:J-14;
D = kron(D(ROIi,ROIj),ones(2));
% Resized image D-coordinates.
[I J] = size(D); I2 = I/2; J2 = J/2;
[x y z] = Dist2Cam(D,f2,ku,kv);
% From camera distances to z-values.
data = cat(2,ones(I*J,1),x(:),y(:)); a = data\z(:);
% Best Fit in reserved area.
disp('Grondvlak z = a(1) + a(2).x + a(3).y');
disp(cat(2,'Grondvlak z = ',num2str(a(1)),' - ',num2str(abs(a(2))),'.x - ',...
num2str(abs(a(3))),'.y '));
ROTy = atan2(a(2),1); ROTx = atan2(a(3),1);
% Inclination.
cox = cos(ROTx); six = sin(ROTx); coy = cos(ROTy); siy = sin(ROTy);
z = cox*z - six*y ; z = coy*z - siy*x;
% Transformation: camera to world coord.
MEDz = medfilt2(z,[1 5],'symmetric');
% Horizontal median filter.
Z = (MEDz(1:end-3,:) + MEDz(2:end-2,:) + ...
% Vertical mean filter.
MEDz(3:end-1,:) + MEDz(4:end,:))/4;
correction = z(2:end-2,:) - Z; sigma = std2(correction);
std2z = std2(z); std2Z = std2(Z);
figure; hold on; axis([-0.15 0.15 -0.22 0.22 0.58 0.6]); view(75,30);
plot3(x,y,z,'.'); grid on; xlabel(cat(2,'ROTx = ' ,num2str(ROTx)));
title('Raw data'); ylabel(cat(2,'ROTy = ',num2str(ROTy)));
zlabel(cat(2,'"Interlace" correction = ',num2str(corr)));
Z = cat(1,Z(1:2,:),Z,Z(end,:));
figure(1); hold on; axis([-0.15 0.15 -0.22 0.22 0.58 0.6]); view(75,30);
plot3(x,y,Z,'.'); grid on; xlabel(cat(2,'ROTx = ' ,num2str(ROTx)));
title('Raw data'); ylabel(cat(2,'ROTy = ',num2str(ROTy)));
zlabel(cat(2,'"Interlace" correction = ',num2str(corr)));
figure(2); hold on; grid on; plot(std(z),'r'); plot(std(Z),'r');
ylabel(cat(2,'I = ', num2str(I), ' J = ', num2str(J)));
plot(std(z'),'k'); plot(std((Z(1:end-1,:))'),'k');
xlabel('red = std(z) ...
blue = std(Z) ');
figure(3);
D(3,3:end-2) = 1; D(end-2,3:end-2) = 1;
D(3:end-2,3) = 1; D(3:end-2,end-2) = 1;
subplot(221); imshow(D,[]); title('Distance image 2x(64x50).');
ylabel('Raw Data');
subplot(222); imshow(z,[]); title('z-image 2x(64x50).');
xlabel(cat(2,'std2(z) = ',num2str(std2z))); ylabel('Raw Data');
subplot(223); imshow(Z,[]);
title('Best Fit Z = (MEDz(1:end-3,:)+..+ MEDz(4:end,:))/4;');
xlabel(cat(2,'std2(Z) = ',num2str(std2Z))); ylabel('Filtered Data');
subplot(224); imshow(correction,[]); ylabel('correction = z-Z');
xlabel(cat(2,'std2(z-Z) = ',num2str(sigma)));
Industrieel VisieLab:
[email protected] and
[email protected]
32
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
33
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Tetra project 100191: RGBd, TOF !
September 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
%
% Program: 'FlatnessBasedCalibration.m'.
%
% During the calibration step a flat plane is presented to the camera.
% Based on colpanarity checks the local flatness is calulated in every point.
% The border is excluded. The standard deviation of the flatness is a
% function of f, corr, kv and ku. A multidimensional least mean square
% calcultion can give the optimal parameter values.
close all; clear all; home; load('ifm_1.mat');
f = 79; corr = -0.0003; ku = 1.0; kv = 1.0; ff = f*f;
[I J] = size(D); I2 = I/2; J2 = J/2;
u = ku*((1:J) - (J2+0.5)); uuff = u .* u + ff;
v = kv*((1:I) - (I2+0.5)); vv = v .* v;
U = repmat( u , [I 1]); UUff = repmat( uuff, [I 1]);
V = repmat( v', [1 J]); VV = repmat( vv',[1 J]); d = sqrt( VV + UUff );
t0 = cputime; for i = 1:2:I, D(i,:) = D(i,:)+corr; end;
dD = d./D; Dd = 1./dD; % Ratios.
dD12 = imfilter(dD,[1 0 1],'same'); dD34 = imfilter(dD,[1; 0; 1],'same');
Flatness = dD12 - dD34;
Flat = Flatness(5:end-4,5:end-4); stdFlat = std2(Flat);
Dd12m = imfilter(Dd,[-1; 0; 1],'same'); Dd34m = imfilter(Dd,[-1 0 1],'same');
Dd12p = imfilter(Dd,[1; 0; 1],'same'); Dd34p = imfilter(Dd,[1 0 1],'same');
Nx = Dd34m./Dd34p; Ny = Dd12m./Dd12p; Nz = - (U.*Nx + V.*Ny +1)/f;
N = sqrt(Nx.*Nx + Ny.*Ny + Nz.*Nz); Nx = Nx./N; Ny = Ny./N; Nz = Nz./N;
t0 = cputime - t0;
figure(1); subplot(131); imshow(D,[]); title('Raw distances.');
ylabel('Coplanarity test');
subplot(132); imshow(Flat,[-1 1]);
title(cat(2,'StdFlat = ',num2str(stdFlat)));
xlabel('Flatness = d1/D1-d2/D2+d3/d3-d4/D4');
ylabel(cat(2,'Focal length = ',num2str(f),' corr = ',num2str(corr)));
subplot(133); hist(Flat(:)); xlabel(cat(2,'CPUtime = ', num2str(t0)));
title('Histogram of Flatness');
ylabel(cat(2,'kv = ',num2str(kv),' ku = ',num2str(ku)));
figure(2); subplot(131); imshow(Nx,[-0.5 0.5]); title('Nx ~ (D4/d4 - D3/d3)/(D4/d4 + D3/d3)');
subplot(132); imshow(Ny,[-0.5 0.5]);
title('Ny ~ (D2/d2 - D1/d1)/(D2/d2 + D1/d1)');
subplot(133); imshow(Nz,[-1 0]); xlabel(cat(2,'CPUtime = ', num2str(t0)));
title('Nz ~ - (U.*Nx + V.*Ny +1)/f');
Industrieel VisieLab:
[email protected] and
[email protected]
34
Association University and University Colleges Antwerp.
4.3.
RGBd, ToF !
Final Report IWT 2012.
Calibration based on the straightness of 5 consecutive points on a flat wall.
As we will show a calibration based on the straightness of 5 consecutive pixels will not give a stable calibration method. Nevertheless it
gives some insights in the calibration problem and therefor we think it is worthfull to investigate on the method. In 6.2. a stable method
will be explained. It is based on coplanarity of a 5 points-star.
Let’s think diagonal, column or row wise while looking to a wall from which we (persons) now it is perfectly flat in every direction. The
camera has to believe this ‘flatness’ and can try to find the relation between his unique optical sensor construction (exact 3D-pixel
positions) and the perception of a flat wall. Five consecutive pixels will deliver 5 measured distances (D1, D2, D3, D4 and D5 ). Their
internal radial distances d1, d2, d3, d4 and d5 are unknowns during the calibration step. As we showed before the following equations are
valid:
1
2
3
4
5
d1/D1 – 2.d2/D2 + d3/D3
=0
d2/D2 - 2.d3/D3 + d4/D4 = 0
d1² -
2.d2² +
d2² -
d3 ²
2.d3² +
= 2.r²
d4 ²
Collineariteit
(1)
in de World
(2)
Equidistant
pixels.
(3)
= 2.r²
(4)
d5/D5 – 2.d4/D4 + d3/D3
=0
d4/D4 - 2.d3/D3 + d2/D2 = 0
d5² -
2.d4² +
d3²
d4² - 2.d3²
= 2.r²
+ d2²
= 2.r²
From (1) and (3) , respectively (2) and (4) we get:
(2.d2/D2 – d3/D3)² = 2d2²/D1² - d3²/D1² + 2r²/D1²
(a)
(2.d4/D4 – d3/D3)² = 2d4²/D5² - d3²/D5² + 2r²/D5²
(2.d3/D3 – d2/D2)² = 2d2²/D4² - d3²/D4² + 2r²/D4²
(b)
(2.d3/D3 – d4/D4)² = 2d4²/D2² - d3²/D2² + 2r²/D2²
Industrieel VisieLab:
[email protected] and
[email protected]
35
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Working out the squares and subtracting (b) from (a) delivers:
(3/D2² – 2/D1² - 1/D4²).d2² = (3/D3² – 2/D4² - 1/D1²).d3² + 2r²(1/D1² - 1/D4²) .
(Ia)
(3/D4² – 2/D5² - 1/D2²).d4² = (3/D3² – 2/D2² - 1/D5²).d3² + 2r²(1/D5² - 1/D2²) .
(Ib)
Because of equation (4) the form (Ib) can further be worked out:
(3/D4² – 2/D5² - 1/D2²).(2r² + 2d3² - d2²) = (3/D3² – 2/D2² - 1/D5²).d3² + 2r²(1/D5² - 1/D2²) .
(3/D4²–2/D5²-1/D2²).d2² = 2.(3/D4²–2/D5²-1/D2²).d3²-(3/D3²–2/D2²-1/D5²).d3² + 2r².(3/D4²–2/D5²-1/D2²) - 2r²(1/D5²-1/D2²)
(3/D4²–2/D5²-1/D2²).d2² = (6/D4² – 3/D5² - 3/D3²).d3² + 2r².(3/D4² – 2/D5²)
(IIb)
From (Ia) and (IIb) the value d2² can be eliminated in order to find d3² as a function of the measuring values D1,..,D5 .
This gives us the final result:
(3/D4² – 2/D5² - 1/D2²).(3/D3² – 2/D4² - 1/D1²).d3² + 2r²(1/D1² - 1/D4²).(3/D4² – 2/D5² - 1/D2²)
=
(3/D2² – 2/D1² - 1/D4²).(6/D4² – 3/D5² - 3/D3²).d3² + 2r².(3/D2² – 2/D1² - 1/D4²)(3/D4² – 2/D5²)
(IIb’)
[ (3/D4² – 2/D5² - 1/D2²).(3/D3² – 2/D4² - 1/D1²) - (3/D2² – 2/D1² - 1/D4²).(6/D4² – 3/D5² - 3/D3²) ].d3² =
2r².{(3/D2² – 2/D1² - 1/D4²)(3/D4² – 2/D5²) - (1/D1² - 1/D4²).(3/D4² – 2/D5² - 1/D2²)}
[ (3/D4² – 2/D5² - 1/D2²).(3/D3² – 2/D4² - 1/D1²) - (3/D2² – 2/D1² - 1/D4²).(6/D4² – 3/D5² - 3/D3²) ].d3² =
2r².{16/(D1²D5²) + 16/(D2²D4²) + 2/(D1²D2²) + 2/(D4²D5²) - 18/(D2²D5²) - 18/(D1²D4²) }
[ (3/D4² – 2/D5² - 1/D2²).(3/D3² – 2/D4² - 1/D1²) - (3/D2 – 2/D1² - 1/D4²).(6/D4² – 3/D5² - 3/D3²) ].d3² =
2r².{ 8/(D1²D5²) + 8/(D2²D4²) + 1/(D1²D2²) + 1/(D4²D5²) - 9/(D2²D5²) - 9/(D1²D4²) }
{ D32².(D31²+6+9D35²-8D34²) + D34².(9D31²+6+D35²-8D32²) - 6.(D35²+D31²) - 4.D31²D35² } d3² =
(IIb’’)
2r².{ 8.(D31²-D32²)(D35²-D34²) - (D31²-D35²)(D34²-D32²) }
Industrieel VisieLab:
[email protected] and
[email protected]
36
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Unfortunately, while the formula is theoretical correct it has one important disadventage: the
numerical stability is very week. Small changes in de measured values, as must be expected for
ToF camera’s, make that the coefficient of d3² and the right side of the equation can change from
–ε till +ε . Therefor the nominator and the denominator are that close to zero that every result
can be found in practice.
5.4.
Calibration based on the straightness of 3 consecutive points on a flat wall.
Imagine a camera with just 3 pixels. Such camera can be seen as a primitive part of a common
ToF-camera. The pixel triplet ‘is looking to’ a flat plane which is hit at the measured world
distances D1, DM and D2 . These values are temporal mean values. Apart from a systematic error
they have a repeatable value. We will proof that the internal camera distances d1 and d2 of the
anti-symmetric pixels 1 and 2 are bounded to the central distance dM . A full sensor can be
viewed as a collection of separate antisymmetric pixels relative to the principal point of the
sensor.
D1
1
d1
r1=r
DM
M
O
dM
r2=r
d2
D2 2
For every sensor triplet the next constraints hold:
Antisymmetry:
r1 = r2 = r
Collinerarity:
d1/D1 – 2.dM/DM + d2/D2 = 0
From the cosine rule it can be derived that:
d1² – 2.dM² + d2² = 2r²
[1]
[2]
[3]
The substitution of d1 from [2] into equation [3] gives an expression for d2 as a function of dM:
d2² = 2.dM² - d1² + 2r² = 2.dM² - { 2.dM.D1/DM - d2.D1/D2 }² + 2r²
or, in short:
d2² = 2.dM² - {2dM.D1M - d2.D12 }² + 2r²
;
D1M := D1/DM .
d2² = 2.dM² - 4dM²D1M² +4 dMD1MD12.d2 - d2².D12² + 2r²
(1 + D12²).d2²- 4dMD1MD12.d2 + [4dM²D1M² – 2(r² + dM²)] = 0 .
2dMD1MD12 + sqrt{4dM²D1M²D12² - (1 + D12²)[4dM²D1M² – 2(r²+dM²)]}
d2 = ---------------------------------------------------------------------------------(1 + D12²)
Industrieel VisieLab:
[email protected] and
[email protected]
37
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
2dMD1MD12 + sqrt{2.(1 + D12²).(r²+ dM²) - 4dM²D1M²}
d2 = -------------------------------------------------------------(1 + D12²)
2dMD1²/(DMD2) + 2.dM/D2.sqrt{(D1² + D2²).(1 + r²/dM²) - D1M².D2²}
d2 = ------------------------------------------------------------------------------(D1² + D2²)/D2²
D1² + sqrt{ DM².(D1² + D2²).(1 + r²/dM²) - D1².D2² }
d2/D2 = dM/DM . -------------------------------------------------------------(D1² + D2²)/2
D1M² + sqrt{ (D1M² + D2M²).(1 + r²/dM²) - D1M².D2M² }
d2/D2 = dM/DM . -------------------------------------------------------------(D1M² + D2M²)/2
[4]
The value dM must be seen as a parameter.
For a real camera the point M can be chosen more or less in the middle of the image, near by the
optical centre (Principal Point).
On the same basis the ratio d1/D1 equals:
D2M² - sqrt{ (D1M² + D2M²).(1 + r²/dM²) - D1M².D2M² }
d1/D1 = dM/DM . -------------------------------------------------------------(D1M² + D2M²)/2
[5]
Special case:
Consider two points which are antisymmetric with respect to the principal point. In such case
d1 = d2 = d and dM = f . The value Df can follow from the best fit plane through all
measurement points. The value Df also should be found in the real world (from camera to wall).
From equation 2 we get:
d/D1 – 2.f/Df + d/D2 = 0
-
d = f/Df . (D1+D2)/2 .
[2’]
By generalization all pixels at a constant squared radius r² = u²+v² = Cte will have the same
distance d . For this reason the final most accurate IRD value will be the mean of the values
delivered by the different antisymmetric couples:
cos(a) = f/d = Df/Dmean
;
Dmean = Σ Di/n
.
The mean value Dmean is based on at least 4k ( k = 1,2...) separate measurements which
supports the stability of the calculations.
Interpretation: the angle a depends on the ratio of Df and the mean distance measured by
sets of anti-symmimetric pixels on a circle around the optical center. If the
angle a and the radius r are known the value f is found as: f = r/tg(a).
Some remarks. 1. The sum [4] + [5] of course fulfil equation [2] which means that the plus
and minus signs of the ‘sqrt’ must be in accordance with the names given
to the points 1 and 2 . If D1/DM < D2/DM than ....
2. The calculation of the expressions [4] and [5] is stable.
3. If it is accepted that dM points to the central point then d2² = f² + r² !
Industrieel VisieLab:
[email protected] and
[email protected]
38
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
From now on we will think row wise and column wise since this can help us during the
calibration.
Consider the points on the pseudo horizon of the camera ( v = 0 and u = -J/2:J/2) and also the
perpendicular image points ( the mid column: v = -I/2:I/2 and u = 0 ). As a reference point M
we choose the point at ( v = 0 and u = 0 ). Consider symmetric points at a distance 2r.
Horizontally:
From Pythagoras law it follows that:
u2² - u1² - 2.u0.Δu = d2² - d1²
For symmetrical points:
- 2.u0.2r = d2² - d1²
4u0.r/dM² = (d1/dM)² - (d2/dM)²
[6]
A sequence of u0/dM values can be found for consecutive values r = 1:J/2 .
The best fit value u0/dM can be the median or the mean of this sequence.
Vertically:
From Pythagoras law it follows that: v2² - v1² - 2.v0.Δv = τ²(d2² - d1²)
For symmetrical points:
( τ = aspect ratio )
- 2.v0.2r = τ²(d2² - d1²)
4v0r/dM² = τ².[ (d1/dM)² - (d2/dM)²]
[7]
A sequence of v0/dM values can be found for consecutive values r = 1:J/2 .
The best fit value v0/dM can be the median or the mean of this sequence.
From [4] and [5] it can be calculated that:
d1²-d2² = 4dM²/(D1²+D2²)².{D1²/DM².(D24–2D2².sqrt+sqrt²)–D2²/DM².(D14–2D1².sqrt+sqrt²)}
d1²-d2² = 4dM²/(D1²+D2²)².{D1²D24 – 2D1²D2².sqrt + D1².sqrt²
– D2²D14 + 2D1²D2².sqrt - D2².sqrt²}/DM²
d1² - d2² = 4dM²/(D1²+D2²)².{ (D1² - D2²).(sqrt² - D1²D2²) }/DM²
remember: sqrt = sqrt{ DM².(D1² + D2²).(1 + r²/dM²) - D1².D2² }
d1² - d2² = 4.dM².(D1² - D2²)/(D1²+D2²)².{ DM².(D1² + D2²).(1 + r²/dM²) }/DM²
d1² - d2² = 4.(dM² + r²).(D1² - D2²)/(D1²+D2²).
And finally:
u0 =
(d1² - d2²)/4r = (dM² + r²)/r . (D1² - D2²)/(D1²+D2²)
u0/dM = (dM/r + r/dM).(D1² - D2²)/(D1²+D2²)
[8]
v0 = τ².(d1² - d2²)/4r = τ².(dM² + r²)/r . (D1² - D2²)/(D1²+D2²)
v0/dM = τ².(dM/r + r²/dM²).(D1² - D2²)/(D1²+D2²)
Industrieel VisieLab:
[email protected] and
[9]
[email protected]
39
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
5.5. ToF camera calibration
The calibration of the suggested primitive ToF cell corresponds to the problem of finding the final
most accurate values d1 and d2 in correspondence with the distance dM of ‘the central pixel’.
The calculation is straightforward for all the triplets of anti-symmetric pixels in the ToF image
relative to the reference pixel of the optical pinhole centre to the sensor.
The points at the pseudo horizon and its perpendicular direction (row wise and column wise) can
further be used for finding a consistent set of classic calibration parameters. These parameters
define the difference between the theoretical pinhole coordinates δuv(f,u,v) of a perfect
(u,v)-grid relative to the real pixel positions duv. We have:
- the theoretical distances
δuv² = f² + (u-u0)² + (v-v0)² ,
- the distances after distortion: duv² = f² + (u-u0)²[au+bu.(u-u0)²] + (v-v0)²[av+bv.(v-v0)²].
dM² = d00² = f² + u0²(au+bu.u0²) + v0²(av+bv.v0²)
[8]
The parameters au and bu can be estimated e.g. from the points corresponding with v = 0 ;
Su = ∑ { [au + bu.(u-u0)²] – (du0²-f²-avv0²-bvv04)/(u-u0)² }² = minimum; v = 0 , u = -J/2:J/2 .
∂Su/∂au = 0
∂Su/∂bu = 0


∑ { (au + bu.(u-u0)²) – (du0²-f²-avv0²-bvv04)/(u-u0)² } = 0
;
∑ { (au + bu.(u-u0)²) – (du0²-f²-avv0²-bvv04)/(u-u0)² }.(u-u0)² = 0
J.au + bu . ∑(u-u0)² = ∑ (du0²-f²-avv0²-bvv04)/(u-u0)²
au . ∑(u-u0)²+ bu.∑(u-u0)4 = ∑ du0² - J.(f²-avv0²-bvv04) .
.
[10a]
[10b]
Similar calculations for the points corresponding with u = 0 and v = -I/2:I/2, deliver av and bv :
Sv = ∑ { [av + bv.(v-v0)²] – (d0v²-f²-auu0²-buu04)/(v-v0)² }² = minimum
;
v = -I/2:I/2 .
J.av + bv . ∑(u-u0)² = ∑ (du0²-f²-auu0²-buu04)/(v-v0)²
av . ∑(v-v0)²+ bv.∑(v-v0)4 = ∑ du0² - J.(f²-auu0²-buu04) .
[11a]
[11b]
The equation sets [9a,b] and [10a,b] are dependent from each other. This means that the sets
need to be solved iteratively.
Once the coefficients au, bu, av and bv are known the analytically best fit d-values (IRD’s) for the
ToF-camera follow equation [8], distortion included.
If the ToF-image is assumed to be distortion free the parameters bu and bv equal zero and the
formulas reduce to the equation sets:
Su = ∑ { au – (du0²-f²-avv0²)/(u-u0)² }² = minimum; v = 0 , u = -J/2:J/2 .
Sv = ∑ { av – (d0v²-f²-auu0²)/(v-v0)² }² = minimum; u = 0 , v = -I/2:I/2 .
J.au = ∑ (du0²-f²-avv0²)/(u-u0)² ; v = 0 , u = -J/2:J/2 .
J.av = ∑ (du0²-f²-auu0²)/(v-v0)² ; u = 0 , v = -I/2:I/2 .
Industrieel VisieLab:
[email protected] and
[10c]
[11c]
[email protected]
40
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6. AGV and Wheelchair navigation.
6.1. AGV-translation: finding the displacement between two images.
In order to avoid ‘backfolding’ (periodicity) it’s better to give the camera’s a small inclination
ortiented to the floor. The angle ‘a’ can be calibrated by a simple measurement (e.g. a free wall).
Distance estimation during pure translations,
horizontal camera.
RMS error.
d1 = sqrt(u1² + v1² + f²)
x1 = u1* D1/d1; y1 = v1* D1/d1; z1 = f* D1/d1
D22 = D1² + δ² - 2.δ.D1.cos(A)
D22 = D1² + δ² - 2.δ.z1
u2/f = x1/(z1 - δ);
δ
( x 2 = x1 ! )
For every δ there is a D2 .
For one specific δ the
error | D2 – DP | is minimal.
v2/f = y1/(z1 - δ) .
Measurement at (v2,u2)  DP .
δ
d1
Random world
f
f
v1,u1
v2,u2
A
D1
Floor.
y1
D2 = DP ?
P
Every single point P can be used in order to estimate the translation δ .
More points make a statistic approach possible.
1/6
Procedure:
Select a random point (u1,v1) in the prvious image. The values x1, y1, z1 and d1 can be found.
Don’t select in the center or at the border of the image. For a chosen value δ the corresponding
distance and position (u2,v2) can be calculated. These distance values must be confronted with
the measured distances at th same senor pixel. The difference ε(d) between measurement and
calculated distances will be minimum at the correct distance δ .
The calcultion can be extended to a collection of random start points. The sum of square errors
must be minimised. A set of 20 points seem to be enough. The calculation can be done in less
than 125 msec (in Matlab).
Industrieel VisieLab:
[email protected] and
[email protected]
41
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Tetra project 100191: RGBd, TOF !
July 2012.
% Luc Mertens & Wim Abbeloos:
Industrial Vision Lab.
% Kenny Hemgenberghs (master student).
%
% Program: Translation_VR2012.m .
%
% During navigation it's important to evaluate the forward translation relative
% to a random scene in front. At a rate of 10 images a second this progress
% can be evaluated. If necessary the measurement can be reset and the
% measurement starts over again.
%
% Note: the method needs some texture in the scene.
%
This gives opportunities to find the better correspondences.
close all; clear all; home; rep = 'replicate'; f = 158; ff = f*f;
ROTx = 0.01; cox = cos(ROTx); six = sin(ROTx);
% Values from calibration.
load('mesa_trans_data.mat');
% Previous and next image: D1 and D2.
%%%%%
%
Acquire ToF image if live camera --> Distance D1 matrix .
%
Acquire ToF image if live camera --> Distance D2 matrix .
%%%%%
[I J] = size(D(:,:,1)); I2 = I/2; J2 = J/2;
I2p = I2+1; J2p = J2+1; I2m= I2-1; J2m = J2-1;
MSQE = []; T = 21;
% T is the number of random points chosen.
D1 =1000*D(:,:,1); D2 =1000*D(:,:,5);
t0 = cputime; U1 = []; U2 = U1; V1 = U1; V2 = U1; U2 = zeros(1,T); V2 = U2;
x1 = zeros(1,T); y1 = x1, z1 = x1; d12 = x1;
for t = 1:T
r1 = 0; while abs(r1) < 0.3 r1 = 1.2*rand -0.5; end;
r2 = 0; while abs(r2) < 0.1 r2 = 1.2*rand -0.5; end;
v1 = round(I2*r1); V1 = cat(2,V1,v1+I2);
u1 = round(J2*r2); U1 = cat(2,U1,u1+J2);
h = D1(v1+I2m : v1+I2p , u1+J2m : u1+J2p); d1 = median(h(:));
d12(t) = d1*d1;
Dd = d1/sqrt(u1*u1 + v1*v1 + ff);
x1(t) = u1*Dd; y1(t) = v1*Dd; z1(t) = f*Dd; end;
x1f = x1*f; term = 2*(y1*six - z1*cox);
for delta = 0:100
% Displacement between 0 tot 100 mm/(image pair).
SQE = []; dsix = delta*six; dcox = delta*cox;
for t = 1:T
% 15 random image points.
d2delta = sqrt(d12(t) + delta*(delta + term(t)));
u2 = round(x1f(t)./(z1(t) - dcox));
U2(t) = u2+J2;
v2 = round((y1(t)+ dsix)*f./(z1(t) - dcox)); V2(t) = v2+I2;
h = D2(v2+I2m:v2+I2p,u2+J2m:u2+J2p); d2 = median(h(:));
SQE = cat(2,SQE,(d2 - d2delta)*(d2 - d2delta));
% Deviations.
end;
MSQE = cat(2, MSQE, mean(SQE));
end;
t0 = cputime - t0;
RMS = sqrt(MSQE); [mmRMS jj] = min(RMS); JJ = jj-1;
figure(1); mm = min(D1(:));
subplot(121); imshow(D1, [mm mm+400]); title('Previous image.');
subplot(122); imshow(D2 ,[mm mm+400]); title('Next image.');
figure(2); hold on; axis([1 J 1 I]); plot(U1,V1,'k.'); plot(U2,V2,'ro');
plot(J2,I2,'b+'); title('Imagine: STAR TREK');
xlabel('Black = previous position. Red = next position.');
Industrieel VisieLab:
[email protected] and
[email protected]
42
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
figure(3); hold on; plot([JJ JJ],[0 mmRMS],'r'); grid on;
plot([0:100],RMS); plot([0 JJ],[ mmRMS mmRMS],'r');
title('Root Mean Square Error as a function of delta. Delta = 0:100 mm. ')
xlabel(cat(2,'Calculation time = ', num2str(t0),'.
Minimum at delta = ',num2str(jj-1)));
ylabel(cat(2,num2str(T),' random points used.', ' Minimum at RMS = ',
num2str(mmRMS)));
Distance Images: previous and next.
Industrieel VisieLab:
[email protected] and
[email protected]
43
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.2. AGV-rotation: angle between two images.
In order to avoid ‘backfolding’ (periodicity) it’ better to give the cameras a small inclination
ortiented to the floor. The angle ‘a’ can be calibrated by a simple measurement (e.g. a free wall).
Distance estimation during pure translations,
camera inclination ‘a’.
RMS error.
d1 = sqrt(u1² + v1² + f²)
x1 = u1* D1/d1; y1 = v1* D1/d1; z1 = f* D1/d1
D22 = D1² + δ² - 2.δ.[D1.cos(A)]
D22 = D1² + δ.(δ - 2.[z1.cos(a) - y1.sin(a)])
δ
u2/f = x1/(z1 - δ*cos(a)); ( x2 = x1 ! )
For every δ there is a D2 .
For one specific δ the
error | D2 – DP | is minimal.
v2/f = (y1+ δ*sin(a))/(z1 - δ*cos(a)) .
Measurement at (v2,u2)  DP .
δ
d1
f
v1,u1
Horizontal movement !
Random world
f
a = camera inclination.
v2,u2
A
D1
D2 = DP ?
Floor.
y1
P
Every single point P can be used in order to estimate the translation δ .
More points make a statistic approach possible.
2/6
Distance correspondence during a pure rotation + horizontal camera.
x1 = u1.D1/d1; y1 = v1.D1/d1 ; z1 = f D1/d1; α = atan(x1,z1);
D22 = D1² + δ² - 2.δ.D1.cos(A) ;
RMS error.
cosine rule.
A = π/2 – β/2 – α ; B = π/2 – β/2 – γ ; A - B = γ - α ;
Every distance D1 and associated choises of δ 
D2 .
δ
From sin(B) = sin(A).D1/D2  B  γ  β .
x2 = D2.sin(γ) ; y2 = y1 : z2 = D2.cos(γ) ;
u2 = f.x2/z2 ; v2 = f.y2/z2 ;  Measurement DP at (v2,u2)
 Error = D2 – DP ;
For every δ there is a D2 .
For one single δ the
error D2 – DP is minimal.
Camera
previous position
z1
Top View !
α
β
δ
r0
f
A
B
D1
γ
x1
P
D2 = D P ?
x2
z2
Every single point P
can be used in order to
estimate the angle β.
More points make a
statistic approach
possible.
Camera
next position
Industrieel VisieLab:
[email protected] and
3/6
[email protected]
44
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Distance correspondence during a pure rotation + camera inclination ‘a’.
x1 = u1.D1/d1; y1 = v1.D1/d1 ; z1 = f D1/d1; α = atan(X1,Z1);
Z1 = z1.cos(a) + y1.sin(a) ; Y1 = y1.cos(a) - z1.sin(a) ;
(Projection)
δ1² = x1² + Z1² ;
(Projected distance δ1)
δ22 = δ1² + δ² - 2.δ.δ1.cos(A) ;
RMS error.
(Cosine rule).
A = π/2 – β/2 – α ; B = π/2 – β/2 – γ ; A - B = γ - α ;
For every projected distance δ1 and associated choises of δ,
a corresponding projected distance δ2 is found.
From sin(B) = sin(A). δ1/δ2  B  γ  β .
X2 = δ2.sin(γ); Y2 = y1 ; Z2 = δ2.cos(γ) ; x2 = X2 ;
y2 = Y2.cos(a)+Z2.sin(a); z2 = Z2.cos(a)-Y2.sin(a); (Back projection).
D2 = sqrt( x2² + y2² + z2² ) ;
u2 = f.x2/z2 ; v2 = f.y2/z2 ;  Measurement DP at (v2,u2)
 Error = D2 – DP ;
δ
For every δ there is a D2 .
For one single δ the
error D2 – DP is minimal.
Camera
previous position
z1
Top View !
x1
α
β
δ
A
B
r0
P
D1
D2 = D P ?
x2
γ
z2
f
Every single point P
can be used in order to
estimate the angel β.
More points make a
statistic approach
possible.
Camera
next position
4/6
Distance correspondence during a general rotation + camera inclination ‘a’.
x1 = u 1.D 1/d1; y1 = v1.D1/d1 ; z1 = f D1/d1; α = atan(x1,z1);
Z1 = z1.cos(a) + y1.sin(a) ; Y1 = y1.cos(a) - z1.sin(a) ;
(Projection)
δ1² = x1² + Z1² ;
(Projected distance δ1)
δ22 = δ1² + δ² - 2.δ.δ1.cos(A) ;
A = α – β/2 ; B = π - β/2 – γ ;
RMS error.
(Cosine rule).
For every projected distance δ1 and associated choises of δ,
a corresponding projected distance δ2 is found.
From sin(B) = sin(A). δ1/δ2  B  γ
 β.
X2 = δ2.sin(γ) ; Y2 = y1 : Z2 = δ2.cos(γ) ;
y2 = Y2.cos(a) + Z2.sin(a); z2 = Z2.cos(a) - Y2.sin(a);
(Reprojection)
D2 = sqrt( x2² + y2² + z2² );
u2 = f.x2/z2 ; v2 = f.y2/z2 ;  Error = D2 – DP ;
δ
Camera
previous position
A
v1,u1
R
Z2
v2,u2
δ1
β
δ2 D2 = DP ?
D1
For every δ there is a D2 .
For one single δ the
error D2 – DP is minimal.
Next camera
position
Z1
α
B
d1
β
X1
γ
X2
Every single point P
can be used in order to
estimate the angle β.
More points make a
statistic approach
possible.
P
6/6
Industrieel VisieLab:
[email protected] and
[email protected]
45
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Tetra project 100191: RGBd, TOF !
July 2012.
% Luc Mertens & Wim Abbeloos:
Industrial Vision Lab.
% Kenny Hemgenberghs (master student).
%
% Program: Rotation_VR2012.m .
%
% During navigation it's important to evaluate the actual rotation relative
% to a random scene in front. At a rate of 10 images a second this progress
% can be evaluated. If necessary the measurement can be reset and the
% measurement can be started over again.
%
% Note: the method needs some texture in the scene.
close all; clear all; home; rep = 'replicate'; f = 158; ff = f*f; MSQE = []; T = 5;
ROTx = 0.01; co = cos(ROTx); si = sin(ROTx);
% Values from calibration.
load('rotatietest.mat');
% Previous and next image: D1 and D2.
% Take care for the vertical 'world-offset' between both images.
t0 = cputime; D1 = 1000*D1; D2 = 1000*D2;
%%%%%
%
Acquire ToF image if live camera --> Distance D1 matrix .
%
Acquire ToF image if live camera --> Distance D2 matrix .
%%%%%
[I J] = size(D1); I2 = I/2; J2 = J/2;
I2p = I2+1; J2p = J2+1; I2m= I2-1; J2m = J2-1;
U1 = []; U2 = U1; V1 = U1; V2 = U1; U2 = zeros(1,T); V2 = U2;
L = zeros(1,T); L2 = L; x1 = L; y1 = L; z1 = L; Y1 = L; Z1 = L; r0 = 0;
for t = 1:T
r1=0; while abs(r1<0.2) r1=rand -0.5; end; r2=(rand-0.5)/2; % Mid right region !
u1 = round(J2*r1); U1 = cat(2,U1,u1+J2);
v1 = round(I2*r2); V1 = cat(2,V1,v1+I2);
h = D1(v1+I2m : v1+I2p , u1+J2m : u1+J2p); d1 = median(h(:));
D1(v1+I2m : v1+I2p , u1+J2m : u1+J2p) = 5000;
Dd = d1/sqrt(u1*u1 + v1*v1 + ff);
x1(t) = u1*Dd; y1(t) = -v1*Dd; z1(t) = f*Dd;
Y1(t) = y1(t)*co -z1(t)*si; Z1(t) = z1(t)*co + y1(t)*si;
L2(t) = x1(t)*x1(t) + (Z1(t)+r0)*(Z1(t)+r0); end;
L = sqrt(L2); Z2 = L; x2 = L; y2 = L; z2 = L; d2 = L; Dd = L; u2 = L; v2 = L;
range = [1:1:20]*pi/180; Len = length(range); MSQE = []; b = 0
mmMSQE = 10000000;
for beta = range, b = b+1;
% Angles between 0 tot 45 degrees.
SSQE = 0; TT = 0; U2 = []; V2 = []; sib = sin(beta); cob = cos(beta);
for t = 1:T
% 15 random image points.
Y1t = Y1(t); Z2t = L(t)*cob - r0; x2t = -L(t)*sib;
% Negative x-values !
D2t = sqrt(x2t*x2t + Y1t*Y1t + Z2t*Z2t);
y2t = Y1t*co + Z2t*si; z2t = Z2t*co - Y1t*si; Dd = z2t/f;
u2 = round(x2t/Dd); v2 = round(-y2t/Dd);
U2 = cat(2,U2,u2+J2); V2 = cat(2,V2,v2+I2);
if abs(u2)<J2-1 && abs(v2)<I2-1
TT = TT+1;
h = D2(v2+I2m:v2+I2p,u2+J2m:u2+J2p); dp = median(h(:));
SQE = (D2t - dp)*(D2t - dp); SSQE = SSQE + SQE; end;
end;
if TT > 0.9*T MSQE = cat(2,MSQE,SSQE/TT);
if length(MSQE) > 0
% Keep the best set of points.
if MSQE(b) < mmMSQE mmMSQE = MSQE(b); UU2 = U2; VV2 = V2; end; end; end;
end;
for tt = 1:length(VV2), D2(VV2(tt),UU2(tt)) = 5000; end;
t0 = cputime - t0;
Industrieel VisieLab:
[email protected] and
[email protected]
46
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
RMS = sqrt(MSQE); [mmRMS jj] = min(RMS); JJ = jj;
figure(1);
subplot(121); imshow(D1, [700 3500]); title('Previous image.');
subplot(122); imshow(D2 ,[700 3500]); title('Next image.');
figure(2); hold on; axis([1 J 1 I]); plot(U1,V1,'k.'); plot(UU2,VV2,'r.');
plot(J2,I2,'b+'); title('Imagine: STAR TREK');
xlabel('Black = previous position. Red = next position.');
figure(3); hold on;
plot([1:length(RMS)],RMS); plot([0 JJ],[ mmRMS mmRMS],'r');
plot([JJ JJ],[0 mmRMS],'r'); grid on;
title('Root Mean Square Error as a function of alfa. Alfa = 0 : 45° .')
xlabel(cat(2,'Calculation time = ', num2str(t0),'.
Minimum at beta = ',num2str(jj)));
ylabel(cat(2,num2str(T),' random points used.', ' Minimum at RMS = ',
num2str(mmRMS)));
Industrieel VisieLab:
[email protected] and
[email protected]
47
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.3. ToF guided AGV ( Mesa SR4000 ): Masterstudent Kenny Hemgenberghs.
In case 3 willen we het volgende bereiken. We concentreren ons op een typisch onderdeel van het veralgemeende vraagstuk van de
rolwagenbesturing. Het systeem werkt met de MESA-camera. (Liefst zelfs met 2 MESA’s: één vooraan en één achteraan). Posities worden
opgemeten tegenover twee verticale vlakken. We positioneren de AGV tegenover de muur en kiezen dan vrij of we plaats nemen ‘aan de
PC’, ‘aan de tafel’ of ‘in de parking/batterijlader’. De bezoeker moet het mechanisme begrijpen waarin we systematisch 3 acties
ondernemen (AEP-cyclus). Een beweging opstarten, een beeldeffect verwachten binnen een bepaalde tijdspanne en een
positionering doorvoeren op basis van de zichtbare informatie.
Parking
PC
7
14
10
Industrial
1/19
2
3/5
6/8
18/16
4
9
15/13
17
12
11
Tafel
Stappen: Frontaal oriënteren ; Frontaal compenseren ; Frontaal Positioneren ; Indraaien ; Frontaal Oriënteren ; Uitdraaien ;
Rotatie
Rotatie/rotatie
translatie
Rotatie
translatie
Industrieel VisieLab:
[email protected] and
[email protected]
48
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Healthcare Center (UA).
Bart Geraets & Victor Claes.
Basic tasks of ToF cameras in order to support Healthcare Applications:
•
Guide an autonomous wheelchair along the wall of a corridor.
•
Avoid collisions between an AGV and unexpected objects.
•
Give warnings about obstacles (‘mind the step’…, ‘kids’, stairs…)
•
Take position in front of at a table, a desk or a TV monitor.
•
Drive over a ramp at a front door or the door leading to the garden.
•
Drive backwards based on a ToF camera (find the free floor).
•
Park a wheelchair or an AGV autonomous.
•
Command a wheelchair to reach a given position.
•
Guide a patient in a semi automatic bad room.
•
Support the supervision on elderly people.
•
Fall detection of (elderly) people.
ToF driven navigation of AGVs and Wheelchairs (indoor and outdoor).
% Tetra project 100191: RGBd, TOF !
July 2012.
% Wim Abbeloos & Luc Mertens & Rudi Penne:
Industrial VisionLab.
% Kenny Hemgenbergs (Masterstudent).
%
% Program: wchair_DS_door.m .
%
% Our intention is to organize a closed loop wheelchair parcours .
% In an open area the camera is looking for a door opening in a wall.
% It uses the right door edge to calculate the radius of a circle that
% will bring the wheelchair to the other domain part. There it turns
% around and will come back through the door.
function wchair_DS_door()
% Created for the DepthSense ToF camera.
clear all; close all; clc;
global intens D L x y z nx ny nz f c1;
f = 150; c1 = 1; intens = 30; first = 0; t = 0; start_DS(); startmotor();
while 1 == 1
update_data();
% function starts at line 121.
switch c1 % Start driving: speed = 30 % ; Angular Velocity = 50 % .
case 1
% Rotate right untill R ~= 0 .
motorcmd(30,50); R = analyze_img(); if R ~= 0 c1 = c1+1; end;
case 2
% R ~=0 , so rotate over a fixed time.
motorcmd(33, round(130/R)); pause(8.5); c1 = c1+1; end;
case 3
% Drive straight forward but compensate for deviations.
motorcmd(40,4); pause(9); c1 = 1; end;
otherwise
motorcmd(0,0); break; end; end; stopmotor(); stop_DS();
Industrieel VisieLab:
[email protected] and
[email protected]
49
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
function startmotor()
% Start a serial motor communication.
global motor;
delete(instrfind);
% Delete the list of connected instruments.
motor = serial('COM4','BaudRate',38400,'Parity', 'none',...
'DataBits',8,'StopBits',2,'Timeout',0.2);
fopen(motor); motorcmd(0,0);
function stopmotor()
% Stop the serial motor communication.
global motor;
motorcmd(0,0); fclose(motor); delete(motor); clear('motor');
function motorcmd(fwd,trn)
% Command motor: turn = 5 on a scale -100 -> 100 .
%
forward speed = 20 on a scale -100 --> 100 .
%
Full scale = 100.
% Build the string <XY X='5' Y='20' S='100'/> \r and send it to the motor.
global motor;
str1 = '<XY X='''; str2 = num2str(trn); str3 = ''' Y='''; str4 = num2str(fwd);
str5 = ''' S=''100''/>'; fprintf(motor,strcat(str1,str2,str3,str4,str5));
function R = analyze_img()
global x y z D L nx ny nz intens;
% Detect the edge at the right side of the door opening ( = discontinuity, disc ).
disc = imfilter(z,[1 0 -1],'same');
disc2 = (disc>0.7) & ( D>0.5) & ( D<4) & (L>200);
% Logic constraints.
disc2(:,119:120) = 0; figure(2); imshow( disc2 );% Supress the image border.
% Search for the reference point based on projections of the x-values. Grid
% width = 20 cm. ( 1/5 of 1 meter ). So enlagre de x-values by a factor 5.
xx = round(5*x); labels = [-25:25];
% xx-values ranging from [-1 1] meter.
n = histc( xx(disc2), labels );
% Count and expect a peak at the door edge.
figure(100); bar(labels,n); [maxval maxloc] = max(n);
% 'Bar' diagram.
if maxval > 0 % Find a good radius in order to reach the door.
% Door opening = 1.2 m . Midpoint at 0.6 m.
points = ( xx == labels( maxloc ) & disc2 );
if sum(points(:)) > 10 % Find distance XX from edge to frontal image point.
dx = mean(x(points)) - x(80,60); dz = mean(z(points)) - z(80,60);
if dx > 0, XX = sqrt(dx*dx + dz*dz);
R = D(80,60)/nx(80,60) - 0.6 - XX;
% R = radius needed.
else, R = 0; end;
% Door edge on the right side of the image.
else, R = 0; end;
% Not enough points found to confirm the door edge.
else R = 0; end;
% No points found at all.
L1 = mean2(L(80:100,50:70)); % Evaluate the intensity near the image center.
if L1 < 3000, intens = min(round(intens*1.5),100); end; % Adaptive corr.
if L1 > 5000, intens = max(round(intens/1.5),5);
end;
% Adaptive corr.
intensity_DS();
% Renew intensity .
function start_DS()
global pmap lmap plength llength confthresh range U V d f;
% LOAD LIBRARY
if libisloaded( 'optrima' ) unloadlibrary( 'optrima' ); end;
dllname = 'liboptrima.dll'; headername = 'Optrima2.h'; warning('off');
[notfound warnings] = loadlibrary( dllname, headername, 'alias', 'optrima' );
warning('on');
% INITIALIZE VARIABLES
plength = libpointer('uint32Ptr', zeros(1)); llength = libpointer('uint32Ptr',zeros(1));
Industrieel VisieLab:
[email protected] and
[email protected]
50
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
rangeval = libpointer('singlePtr', zeros(1));
pmap = libpointer('int16Ptr', zeros(160,120,'int16'));
lmap = libpointer( 'uint16Ptr', zeros160,120,'uint16')); confthresh = single(5);
% START CAMERA AND SET PROPERTIES
calllib( 'optrima', 'optrima_init'); pause(3);
errmsgx1 = calllib(‘optrima','optrima_set_property','ENABLE_RGB_EVENT_HANDLERS', 0 );
errmsgx2 = calllib('optrima', 'optrima_set_property', 'ENABLE_DENOISING', 0 );
errmsgx3 = calllib('optrima', 'optrima_set_property', 'ENABLE_LEAKAGE_ALGORITHM', 0 );
errmsgx4 = calllib('optrima', 'optrima_set_property', 'ENABLE_DENOISING', 0 );
errmsgx5 = calllib('optrima', 'optrima_set_property', 'OC310_ENABLE_SATURATION', 1 );
errmsgx6 = calllib('optrima', 'optrima_set_property', 'OC310_FRAMERATE', 25 );
% RESTART CAMERA
calllib( 'optrima', 'optrima_exit'); pause(1);
calllib( 'optrima', 'optrima_init'); pause(3);
errmsg1 = calllib( 'optrima', 'optrima_enable_camera' );
errmsg2 = calllib( 'optrima', 'optrima_enable_camera_rgb' ); pause(3);
% GET RANGE
[errmsg4 range] = calllib( 'optrima', 'optrima_get_range', rangeval );
I = 160; J = 120; I2 = I/2; J2 = J/2; ff = f * f;
u = (1:J) - (J2+0.5); uu = u .* u; v = (1:I) - (I2+0.5); vv = v .* v;
U = repmat( u , [I 1]); UU = repmat( uu, [I 1]);
V = repmat( v', [1 J]); VV = repmat( vv',[1 J]); d = sqrt( UU + VV + ff );
intensity_DS()
% Start up intensity setting.
function stop_DS()
% Shut down camera.
errmsg7 = calllib( 'optrima', 'optrima_disable_camera' );
errmsg8 = calllib( 'optrima', 'optrima_disable_camera_rgb' );
calllib( 'optrima', 'optrima_exit');
function update_data()
global pmap plength confthresh range D lmap llength L d x y z U V f nx ny nz;
% Get camera data: phase map, luminance map, confidence threshold.
[errmsg5 P q] = calllib('optrima','optrima_get_phasemap',pmap,plength,confthresh);
[errmsg7 L q] = calllib('optrima', 'optrima_get_confidencemap',lmap,llength );
% Calculate distance from phase data.
D = double(fliplr(P))*(range/2^15); L = fliplr(L);
Dd = D ./ d; x = U.* Dd; y = -V.* Dd; z = f*Dd;
f1 = zeros(1, 9); f1(1) = 1; f1(end) = -1; f2 = f1';
z1 = conv2( z, f1, 'same' ); z2 = conv2( z, f2, 'same' );
% Local diferrences.
x1 = conv2( x, f1, 'same' ); x2 = conv2( x, f2, 'same' );
y1 = conv2( y, f1, 'same' ); y2 = conv2( y, f2, 'same' );
nx = y1.*z2-z1.*y2; ny = z1.*x2-x1.*z2; nz = x1.*y2-y1.*x2; % Normal vector.
n = sqrt(nx.^2 + ny.^2 + nz.^2 ); nx = nx./n; ny = ny./n; nz = nz./n;
function intensity_DS()
global intens;
calllib( 'optrima', 'optrima_set_light_intensity', uint8(intens));
Industrieel VisieLab:
[email protected] and
[email protected]
51
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.4. An introduction on Kalman Filters in order to use it in navigation
programs.
State space models as a start to explain the Kalman
Filter Technique.
SLAM: simultanous Localisation and Mapping .
x
d/dt
1
dt
x
=
v
dt²/2
+
0
1
v
Anoise.randn.dt²/2
. u(t) +
dt
Anoise.randn.dt
x
y = C.
+ Mnoise
v
x
v
a = input = u(t) = 0.01
Kalman Filters

Process to be estimated:
xk = A.xk-1 + B.uk + wk-1
yk = C.xk + vk

Process Noise (w) with covariance Q
Measurement Noise (v) with covariance R
Kalman Filter
Predicted: ^xk is estimate based on measurements at previous time-steps
^x-k = A.xk-1 + B.uk
P-k = APk-1AT + Q
Time update.
Prediction Error Covariance
Corrected: ŷk has additional information – the measurement at time k
^xk = ^x-k + K.( yk – C.^x-k )
Pk = (I - KC)P-k
Industrieel VisieLab:
, with K := P-kCT(CP-kCT + R)-1
Measurement update.
Final Error Covariance
[email protected] and
[email protected]
52
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Matlab program: Kalmanstraight.m .
% Tetra project 100191: RGBd, TOF !
July 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
%
% Program: KalmanStraight.m
%
% Kalman filter simulation for a vehicle with a constant acceleration u .
close all; clear all; home;
T = 20; dt = 0.1; time = 0:dt:T;
% Inspectation time interval.
u = 0.01;
% Make use of a constant acceleration u [m/s²].
Mnoise = 0.05;
% Position measuring noise [m].
Anoise = 0.005;
% Acceleration noise [m/s²].
% System description:
%
% From mechanics we know that: dv = a.dt and dx = v.dt , so
%
%
x(k+1) = x(k) + v(k).dt + a.dt²/2 (Remember a = input = u(t) ).
%
v(k+1) =
v(k)
+ a.dt
%
%
|x|
|1 dt|| x | |dt²/2|
| Anoise.randn.dt²/2 |
% d/dt | | = |
|| | +|
|.u(t) + |
|
%
|v|
|0 1 || v | | dt |
| Anoise.randn.dt
|
%
%
|x|
%
y = C.| | + Mnoise
%
|v|
%
% About the process variances and co-variances:
%
sigma(a) = 0.0005 ; var(a) = sigma²(a). (Remember a = input = u(t) ).
%
v = a.T
--> var(v) = sigma²(v) = var(a).T²
%
x = a.T²/2
-->
var(x) = var(a)*(T².T²)/4
%
x.v = a².T³/2 -->
var(x.v) = var(a).(T³/2) .
%
% About the variance on the measurements:
% sigma(y) = Mnoise --> var(y) = Sz = Mnoise*Mnoise.
Sz = Mnoise*Mnoise ;
% Measurement Error variance.
dt22 = dt*dt/2; dt32 = dt*dt22/2; dt44 = dt22*dt22;
Sw = Anoise*Anoise*[dt44 dt32; dt32 dt22] % Process Noise Covariance.
P = Sw ;
% Initial Estimation Covariance.
A = [1 dt; 0 1];
% System Transition Matrix.
B = [dt22; dt];
% Input Matrix.
C = [1 0];
% Output Measurement Matrix.
X = [0; 0]
% Initial State Vector.
% Xhat is state estimate; xhat = Xhat(1); vhat = Xhat(2);
Xhat = X; x = [ ]; xhat = [ ]; xmeas = [ ]; v = [ ]; vhat = [ ];
for t = time
ProcNoise = Anoise * [randn*dt22; randn*dt]; % Renewed ProcNoise.
MeasNoise = Mnoise*randn;
% Renewed MeasNoise.
X = A*X + B*u + ProcNoise;
% Simulate the linear system.
x = [x; X(1)]; v = [v; X(2)];
% Resulting state vector components.
y = C*X + MeasNoise;
% Simulate the noisy measurement.
xmeas = [xmeas; y];
% Estimation of the x-position.
Xhat = A*Xhat + B*u;
% The most recent State Estimate.
Inn = y - C*Xhat;
% Form the socalled INNOVATION MATRIX.
Industrieel VisieLab:
[email protected] and
[email protected]
53
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
s = C*P*C' + Sz;
% % Compute the covariance of the Innovation.
K = A*P*C'*inv(s);
% % Form the Kalman Gain Matrix.
Xhat = Xhat + K*Inn;
% % Update the State Estimate.
P = (A*P - K*C*P)*A' + Sw;
% % Covariance of the Estimated Error.
xhat = [xhat; Xhat(1)];
vhat = [vhat; Xhat(2)];
end;
figure; grid on; plot(time,x, time,xmeas, time,xhat);
legend('True Position','Measured Position','Estimated Position');
xlabel('Time (sec)'); ylabel('Position [m]');
title('Vehicle Position ( True, Measured & Estimated)');
figure; grid on; plot(time,x-xmeas, time, x-xhat);
legend('True Position - Measured Position','True Position - Estimated Position');
xlabel('Time (sec)'); ylabel('Position Error [m]');
title('Position Measurement Error & Position Estimation Error [m].');
figure; grid on; plot(time,v, time,vhat);
legend('Velocity','vhat');
xlabel('Time (sec)'); ylabel('Velocity [m/s]');
title('Velocity (True and Estimated [m/s]).');
figure; grid on; plot(time,v-vhat);
legend('Velocity - Estimated Velocity');
xlabel('Time (sec)'); ylabel('Velocity Error [m/s]');
title('Velocity Estimation Error [m/s].');
Industrieel VisieLab:
[email protected] and
[email protected]
54
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
55
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
56
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.5. Motor Control System
MD 25 – Dual 12 V 2.8 A H-Bridge Motor Drive for the EMG30 Motors.
Properties and abilities:
-
The motors have ‘encoders’ in order to measure displacements.
The motors act independently.
The accelerations and the motor power can be controlled.
The Power Supply (12 V) is tolerated in the range 9 – 14 V.
Noise on the traction is suppressed by means of capacitors.
Red LED = power OK; Green LED = communication OK.
Automatic speed control ( = Power adjustment): parameter REGULATOR.
Automatic Communication ‘Time out’ ( = Watch Dog): parameter TIMEOUT.
Working modes:
Forward direction:
motor speed1 = speed1 – turn
motor speed2 = speed1 + turn
Not-Forward direction: motor speed1 = speed1 + turn
motor speed2 = speed1 - turn
Commands
Value
Hexa
Value
uint8
Description
0x21
0x22
0x23
0x24
0x25
0x26
0x27
0x28
0x29
0x2A
0x2B
0x2C
33
34
35
36
37
38
39
40
41
42
43
44
Requested speed: motor 1
Requested speed: motor 2
Encoder value: motor 1
Encoder value: motor 2
Encoder values: motor 1 + 2
Battery Voltage level
Current intensity: motor 1
Current intensity: motor 2
MD25 Version number
Acceleration value: motor 1
Selected Mode
Overview: Volts, Amps 1 + 2
0x31
0x32
0x33
0x34
0x35
0x36
0x37
0x38
0x39
49
50
51
52
53
54
55
56
57
Set new Speed value motor 1
Set new Speed on TURN motor 2
Set new Acceleration
Set new Mode
Reset encoders
Power Out independent of encoders
Power Out regulated by encoders
MD25 continuously output
MD25 stopping if 2 seconds idle
Industrieel VisieLab:
[email protected] and
2 bytes
2 bytes
4 bytes
10x
[email protected]
57
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.6. Matlabprogram: Wheelchair Navigation.
% Tetra project 100191: RGBd, TOF !
% Wim Abbeloos & Luc Mertens:
%
% Wheelchair navigation.
%
% Function: 'wchair5.m'.
July 2012.
Industrial VisionLab.
function wchair5()
% Wheelchair5.
clear all; close all; clc;
global cam speed first d2 a2 f2 D L x y z nx ny nz f ku kv c1;
addpath( strcat(cd,'/MESA/') );
if exist('cam','var') sr_close(cam); end;
f = 138; ku = 1.0; kv = 1.0;
% Values from the calibration step.
speed = 20; c1 = 1; first = true;
% c1 = case 1; % first --- delay.
process_init(144,176);
% Calculate the distances d = sqrt(u²+v²+f²).
cam = sr_open; res = sr_setautoexposure(cam,0,255,0,50);
startmotor(4);
% USB poort 4 !
while 1 == 1
update_data();
[d2 a2 f2] = analyze_img(); % Wall distance, Wall Orientation, Wall Flatness.
switch c1
case 1 move_rot(1);
% Rotate in order to find ‘Main Wall 1’ .
case 2 move_trans(2.73);
% Move forward to ‘distance 2.73 meter’.
case 3 move_arc(1,1);
% Rotate in order to find ‘the Table Wall’.
case 4 move_trans(0.25)
% Move forward to ‘distance 0.25 meter’.
case 5 move_trans(-0.7);
% Move backward to ‘distance 0.7 meter’.
case 6 move_arc(-1,-1);
% Rotate in order to find ‘Main Wall 1’ .
case 7 move_trans(1.7);
% Move forward to ‘distance 1.7 meter’.
case 8 move_arc(1,-1);
% Rotate in order to find ‘the Park Wall’ .
case 9 move_trans(0.25);
% Move forward to ‘distance 0.25 meter’.
case 10 move_trans(-1.8);
% Move backward to ‘distance 1.8 meter’.
case 11 move_arc(1,-1);
% Rotate in order to find ‘Main Wall 2’ .
case 12 move_trans(1.65);
% Move forward to ‘distance 1.65 meter’.
case 13 move_arc(1,1);
% Rotate in order to find ‘PC Wall’.
case 14 move_trans(0.25);
% Move forward to ‘distance 0.25 meter’.
case 15 move_trans(-0.7);
% Position at a distance 0.7 meter.
case 16 move_arc(-1,-1);
% Rotate in order to find ‘Main Wall 2’ .
case 17 move_trans(0.6);
% Position at a distance 0.6 meter.
otherwise motorcmd('setspeed1',0); motorcmd('setspeed2',0); break;
end; end;
stopmotor();
sr_close( cam );
function process_init(I,J)
global U V d f ku kv;
I2 = I/2; J2 = J/2; ff = f * f;
u = ku*((1:J) - (J2+0.5)); uu = u .* u;
v = kv*((1:I) - (I2+0.5)); vv = v .* v;
U = repmat( u , [I 1]); UU = repmat( uu, [I 1]);
V = repmat( v', [1 J]); VV = repmat( vv',[1 J]);
UUff = UU + ff; d = sqrt( VV + UUff );
function startmotor(portnr)
global motor;
delete( instrfind );
Industrieel VisieLab:
% process_init.
% startmotor.
[email protected] and
[email protected]
58
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
port = strcat('COM',num2str(portnr));
% Start serial communication.
motor = serial(port,'BaudRate',9600,'Parity','none','DataBits',8,'StopBits',2,'Timeout',0.2);
fopen(motor); motorcmd('disabletimeout'); motorcmd('enablereg');
% ‘disabletimeout’ means: output will stop after 2 seconds without communication
% ‘enablereg’ means: power output is changed by encoder feedback !
motorcmd('resetenc'); motorcmd('setmode',3);
motorcmd(‘setspeed1',0); motorcmd('setspeed2',0); motorcmd('setaccel',10);
% ‘setaccel’ expresses the acceleration the controller takes to change voltages.
function update_data()
% update_data.
global cam U V d D L x y z nx ny nz f;
sr_acquire( cam ); D = sr_getimage(cam,1); L = sr_getimage(cam,2);
D = double( D' ) / (double(intmax( 'uint16' ))/5); L = L';
Dd = D ./ d; x = U .* Dd; y = -V .* Dd; z = f * Dd;
f1 = zeros(1, 9); f1(1) = 1; f1(end) = -1; f2 = f1';
% Gradient-filters.
x1 = conv2( x, f1, 'same' ); x2 = conv2( x, f2, 'same' );
% Grad(x).
y1 = conv2( y, f1, 'same' ); y2 = conv2( y, f2, 'same' );
% Grad(y).
z1 = conv2( z, f1, 'same' ); z2 = conv2( z, f2, 'same' );
% Grad(z).
% Create ‘vectors normal to the world objects’.
nx = (y1.*z2)-(z1.*y2); ny = (z1.*x2)-(x1.*z2); nz = (x1.*y2)-(y1.*x2);
n = sqrt( nx.^2 + ny.^2 + nz.^2 );
% Normalized normal = n/|n|.
nx = nx ./ n; ny = ny ./ n; nz = nz ./ n;
function [d1 a1 f1] = analyze_img()
% analyze_img.
global nx z;
Z1 = z(72:92,78:98); d1 = mean(Z1(:));
% Distance to wall.
A1 = nx(72:92,78:98); a1 = abs(mean(A1(:))); % Abs(orientation) of wall.
f1 = mean(Z1); f1 = sum(abs(diff(f1)))/d1;
% Relative Flatness.
function move_trans( dz )
% move_trans.
global c1 d2 a2 speed first; % case, angle, distance, speed and first(Y/N).
if first==true motorcmd( 'setspeed1', sign(dz)*speed );
motorcmd( 'setspeed2', round(-speed/2*a2) ); end;
% a2 -> 0.
if (sign(dz)*d2) < dz c1 = c1+1; first = true; end;
function move_rot(cw)
% move_rot.
global c1 d2 a2 f2 speed first;
if first == true motorcmd( 'setspeed1', 0 );
motorcmd( 'setspeed2', sign(cw)*round(speed/3) );
for c2 = 1:10 update_data(); pause(0.1); end;
[d2 a2 f2] = analyze_img(); first = false; end; % dist., angle and flatness.
if a2 < 0.1 && f2 < 0.025 c1 = c1+1; first = false; end;
function move_arc( fwd, cw )
% move_arc.
global c1 d2 a2 f2 speed first;
if first == true motorcmd( 'setspeed1', sign(fwd)*speed );
motorcmd( 'setspeed2', sign(cw*fwd)*round(speed/2) );
for c2 = 1:10 update_data(); pause(0.1); end;
% Adaptive Exposure.
[d2 a2 f2] = analyze_img(); first = false; end;
if abs(a2) < 0.1 && f2 < 0.025 c1 = c1+1; first = true; end;
function stopmotor()
% stopmotor.
global motor;
motorcmd('setmode',3); motorcmd('enabletimeout');
motorcmd('setspeed1',0); motorcmd('setspeed2',0);
fclose(motor); delete(motor); clear('motor'); % Stop serial communication.
function varargout = motorcmd(cmd,varargin)
Industrieel VisieLab:
[email protected] and
% motorcmd.
[email protected]
59
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
global motor;
if ~ischar( cmd ) error( 'Second argument must be a command string' ); end;
switch cmd
case 'getspeed1'
fwrite(motor,[0 33],'int8'); % returns the requested speed of motor 1.
varargout(1) = { -fread(motor,1,'uint8') };
case 'getspeed2'
fwrite(motor,[0 34],'int8'); % returns the requested speed of motor 2.
varargout(1) = { -fread(motor,1,'uint8') };
case 'getenc1'
% motor 1: encoder count.
fwrite(motor,[0 35],'uint8'); % 4 bytes returned, high byte first (signed).
val = fread(motor,4,'uint8');
val2 = uint32(bitcmp(uint8(val)));
% Reorder data !
val3=bitshift(val2(1),24)+bitshift(val2(1),16)+bitshift(val2(3),8)+val2(4);
varargout(1) = { double(val3) };
case 'getenc2'
% motor 2, encoder count,
fwrite(motor,[0 36],'uint8'); % 4 bytes returned, high byte first (signed).
val = fread(motor,4,'uint8');
val2 = uint32(bitcmp(uint8(val)));
val3=bitshift(val2(1),24)+bitshift(val2(1),16)+bitshift(val2(3),8)+val2(4);
varargout(1) = { double(val3) };
case 'getencs'
fwrite(motor,[0 37],'uint8' );
% returns 8 bytes: encoder1/2 count.
varargout(1) = { fread(motor,8,'uint8') };
case 'getvolts'
fwrite(motor,[0 38],'uint8');
% returns the input battery voltage level.
varargout(1) = { fread(motor,1,'uint8') };
case 'getcurrent1'
fwrite(motor,[0 39],'uint8');
% returns the current drawn by motor 1.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent2'
fwrite(motor,[0 40],'uint8');
% returns the current drawn by motor 2.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getversion'
fwrite(motor,[0 41],'uint8');
% returns the software version.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getaccel'
fwrite(motor,[0 42],'uint8');
% returns the current acceleration level.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getmode'
fwrite(motor,[0 43],'uint8');
% returns the currently selected mode.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getVI'
fwrite(motor,[0 44],'uint8');
% returns ‘Volts’, motor 1/2 current.
varargout(1) = { fread(motor,1,'uint8') };
% Battery voltage.
varargout(2) = { fread(motor,1,'uint8') };
% Current motor 1.
varargout(3) = { fread(motor,1,'uint8') };
% Current motor 2.
case 'setspeed1'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
speed = cell2mat(varargin(1));
fwrite(motor,[0 49 -speed],'int8');
% set new speed1.
case 'setspeed2'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
speed = cell2mat(varargin(1));
fwrite(motor,[0 50 -speed],'int8');
% set new speed2.
case 'setaccel'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
accel = cell2mat(varargin(1));
Industrieel VisieLab:
[email protected] and
[email protected]
60
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
fwrite(motor,[0 51 accel],'uint8');
% set new acceleration.
case 'setmode'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
mode = cell2mat(varargin(1));
fwrite(motor,[0 52 mode],'uint8');
% set the motor mode.
case 'resetenc' fwrite(motor,[0 53],'uint8');
% zero both encoder counts.
case 'disablereg'
fwrite(motor,[0 54],'uint8'); % power not changed by encoder feedback.
case 'enablereg'
fwrite(motor,[0 55],'uint8');
% power regulated by encoder feedback.
case 'disabletimeout'
fwrite(motor,[0 56],'uint8'); % Continuously out if no regular commands.
case 'enabletimeout'
fwrite(motor,[0 57],'uint8');
% Watch dog: 2 seconds.
otherwise error( 'Incorrect command' );
% Incorrect command string.
end;
AEP cycles:
Action / Expect target / Positioning
Reach position relative to target (i+1)
Expect marker or target (i+1)
Start action (i+1).
Reach position
position relative to target i .
Expect marker or target i .
Start action i .
TV
Grafcet Driven
Make use of position
position tolerance if possible !
PC
Example: the sequence from ‘PC –> TV’
TV’ can be expressed in 3 AEP cycles
Cb(50) M2(M2(-250)
Industrieel VisieLab:
Cf(Cf(-200) T4(200)
[email protected] and
R(60) T3 .
[email protected]
61
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.7. Navigation Practice
6.7.1. Forming a virtual descending path leading from the start to the end point.
% Tetra project 100191: RGBd, TOF !
% Luc Mertens & Luc Mertens:
%
% Program: WaveFrontTest2.m .
June 2012.
Industrial VisionLab.
clear all; close all; clc; V = 120; U = 250; O3 = ones(3); O10 = ones(10);
map = false(V,U);
% Generate new map: 240 * 500 cm .
start = [100 10]; target = [25 225];
% Define start point and target point.
map(1,:) = 1; map(end,:) = 1; map(:,1) = 1; map(:,end) = 1;
% Walls.
map(1:30,50) = 1; map(1:30,100) = 1; map(1:30,200) = 1;
% Obstacles.
map(30,170:200) = 1; map(end-90:end,140) = 1; map(end-30:end,190) = 1;
map(70:90,70:90) = 1; D = bwdist(map); % Eucledian distances to nearest 1.
map = imdilate(map,O10);
% Dilated map.
map2 = zeros(V,U); map2(target(1),target(2)) = 2;
% End point.
cn = 3; old = double(map2 ~= 0);
% cn = current #.
tic; while map2(start(1),start(2)) == 0,
% While 'start' not reached...
new = conv2(old,O3,'same');
% Number of neighbours.
change = ~old & new & ~map; old(change) = 1;
map2(change) = cn; cn = cn + 1; end; toc;
verDiff = diff(map2,1,1); horDiff = diff(map2,1,2);
S = cat( 1, -verDiff, zeros(1,U) ); N = cat( 1, zeros(1,U), verDiff );
E = cat( 2, -horDiff, zeros(V,1) ); W = cat( 2, zeros(V,1), horDiff );
NESW = cat( 3, N, E, S, W ); NESW(find( abs(NESW) > 1)) = -1;
tic; cp = start; track = uint8(map); [m1 m2] = max(NESW,[],3); % m2 = layer !
while map2(cp(1),cp(2)) ~= 2, nn = m2(cp(1),cp(2));
if nn == 1 cp(1) = cp(1) - 1; elseif nn == 2; cp(2) = cp(2) + 1;
elseif nn == 3 cp(1) = cp(1) + 1; else cp(2) = cp(2) - 1; end;
track(cp(1),cp(2)) = 2; end; toc;
figure(1); subplot(211); imshow(map);
title( 'Map' );
subplot(212); imshow(track,[]); title( 'Simple Track.' );
figure(2); imshow(map2,[]); title( 'Wavefront' ); colormap('jet');
xlabel('Bleu = Low potential; Red = High potential.');
% Wavefront vectors.
[gR gC] = gradient(single(map2));
temp = imdilate(map2 < 1, O3); gR(temp) = 0; gR = -gR; gC(temp) = 0;
tn
= imfilter(double(~temp), O10,'same');
% Count # OK points.
ggR = imfilter(gR,O10,'same'); ggR = ggR./tn;
% Vector component 1.
ggC = imfilter(gC,O10,'same'); ggC = ggC./tn;
% Vector component 2.
U = 250; V = 120;
P = kron([1:U],ones(V,1));
P4 = kron([1:4:U],ones(round(V/4),1));
Q = kron([V:-1:1]',ones(1,U)); Q4 = kron([V:-4:1]',ones(1,round(U/4)));
figure(10); axis equal; title('Wavefront vector field');
quiver( P4, Q4, ggR(1:4:V,1:4:U), ggC(1:4:V,1:4:U));
xlabel('Walls and obstacles.');
figure(20); imshow(D, [0 35] ); title( 'Distance Transform.' ); colormap( 'jet' );
[gDr gDc] = gradient(single(D)); gDc = -gDc;
% Distance vector components.
figure(30); axis equal; title('Distance vector field.'); quiver(P,Q,gDr,gDc);
figure(40); axis equal; title('Combined vector field: wave front & distance.');
hold on; quiver(P,Q,ggR+ 0.5*gDr,ggC+0.5*gDc); % Weighted combination of...
angles = atan2((ggC+0.5*gDc),(ggR + 0.5*gDr)); % wavefront and distances.
figure(50); imshow(angles, [-pi pi]); title('Angles');
Industrieel VisieLab:
[email protected] and
[email protected]
62
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
63
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
64
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.7.2. Potential based flow
% Tetra project 100191: RGBd, TOF !
% Wim Abbeloos & Luc Mertens:
%
% Program: Navigation3DviewWim.m .
July 2012.
Industrial VisionLab.
clear all; close all; clc; pi2 = pi/2; wb = 0.365; % Vehicle weelbase.
O10 = ones(10); dt = 0.1; wf = 0.3;
% Time step & weigth factor.
hh = 10; O3 = ones( 3, 'single' );
% Wall and object height.
oc = [.5 .5 .5]; fc = [.7 .7 .7]; vc = [.4 .7 1];
% Color settings.
map = false(120,250);
% Map dimensions: 240 * 500 cm.
wd = [ 1 1 1 250; 120 120 1 250; 1 120 1 1 ; 1 120 250 250];
od = [ 1 30 50 50; 1 30 100 100; 1 30 200 200;
30 30 170 200; 30 120 140 140; 90 120 190 190;
70 90 70 70; 70 90 90 90; 70 70 70 90;
90 90 70 90];
% Wall and obstacle definition.
vd = [ -5 -5 10; -5 5 0; 1 1 1];
% Vehicle definition.
h = figure(2);
% Add walls and objects to map and figure.
axis equal; hold on; view(70,30); camzoom(3.5);
cameratoolbar('Show'); cameratoolbar('SetMode','Orbit');
set( h, 'Renderer', 'OpenGL' ); %maxfig_7a(h,1);
patch([120 120 1 1], [1 250 250 1], [0 0 0 0], fc);
for c1 = 1:size(wd,1)
map(wd(c1,1):wd(c1,2),wd(c1,3):wd(c1,4)) = 1;
patch([wd(c1,1) wd(c1,2) wd(c1,2) wd(c1,1)],...
[wd(c1,3) wd(c1,4) wd(c1,4) wd(c1,3)], [0 0 hh hh], oc); end;
for c1 = 1:size(od,1)
map(od(c1,1):od(c1,2),od(c1,3):od(c1,4)) = 1;
patch([od(c1,1) od(c1,2) od(c1,2) od(c1,1)],...
[od(c1,3) od(c1,4) od(c1,4) od(c1,3)], [0 0 hh hh], oc); end;
map = imdilate( map, ones(10) );
ifh = figure(1);
title( 'Map' ); xlabel( 'Select start and endpoint' );
imshow( map ); %maxfig_7a(ifh,1);
[ spx spy ] = ginput(2);
% Select start position and start direction.
line( spx, spy, 'Color', [0 1 1], 'LineWidth', 2 ); % Use quiver
[ epx epy ] = ginput(1); close(ifh); % Select target position (end point).
sp = round([spx(1) spy(1)]); ep = round([epx(1) epy(1)]);
S = [sp(1) sp(2) atan2(spy(1)-spy(2),spx(2)-spx(1))];
lmap = bwlabel(~map);
% Region to handle.
ptodo = (lmap == lmap(ep(2), ep(1)));
% Points to handle.
ntodo = sum(ptodo(:));
% Number of points to handle.
Wave = zeros( size(map), 'uint32' );
% Create empty 'Wave map'.
Wave( ep(2), ep(1) ) = 2; cn = 3;
% Mark endpoint / current number.
old = single( Wave ~= 0 );
while sum(old(:)) < ntodo
new = conv2(old,O3,'same');
xtra = ~old & new & ptodo;
% Extract pixels to set to handle.
old(xtra) = 1; Wave(xtra) = cn; cn = cn + 1; end;
[gr gc] = gradient(single(Wave)); temp = imdilate(Wave < 1,O3);
gr(temp) = 0; gr = -gr; gc(temp) = 0;
tn = imfilter(double(~temp),O10,'same');
% Filter wavefront vectors.
ggr = imfilter(gr,O10, 'same' ); ggr = ggr./tn;
ggc = imfilter(gc,O10, 'same' ); ggc = ggc./tn;
D = bwdist( map );
% Distance to nearest object border.
[gdr gdc] = gradient( single(D) ); gdc = -gdc;
Industrieel VisieLab:
[email protected] and
[email protected]
65
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Angles of combined vector fields
angles = atan2( (ggc + wf*gdc), (ggr + wf*gdr) );
temp = angles < 0; angles(temp) = angles(temp) + pi2;
ed = Wave( S(2), S(1)); tc = 0; % Distance to endpoint and time counter.
figure(2); Kp = 150; Ki = 5; aev = [];
% Start simulation.
while ed > 5, tc = tc + 1; S3 = S(3);
ca = S3 - pi2*sign(S3)*floor(abs(S3/pi2));
% Current angle.
ba = angles(S(2),S(1)); ae = ba - ca; % Best angle and angle error.
if abs(ba - ca) > pi ae = ae - pi2; end;
if size(aev,1) < 5, aev = cat(1,aev,ae);
else aev(1:end-1) = aev(2:end); aev(end) = ae; end;
speed = 20; dv = (Kp*ae + Ki*sum(aev))/pi; vl = speed - dv; vr = speed + dv;
co = cos(S3); si = sin(S3); sf = 0.00588; % m/s per motor speed unit
vl = vl*sf; vr = vr*sf;
if vl == vr, da = 0; l = vl*dt; dx = l*co; dy = l*si;
else v = (vr + vl)/2; r = (vr*wb)/(vr - vl) - wb/2;
da = v/r*dt; dx1 = r*sin(da); dy1 = r - r*cos(da);
dx = 100*(co*dx1 - si*dy1); dy = 100*(si*dx1 + co*dy1); end;
S = S + [ round(dx) round(dy) da ];
ed = Wave(S(2),S(1));
% Transform vehicle to current position and orientation.
T = [co si S(1); -si co S(2); 0 0 1]; veh = T*vd;
if exist( 'm', 'var' ), delete(m); delete(n); end; % Remove old vehicle.
quiver3( S(2), S(1), 5, -10*si, 10*co, 0, 'g' );
m = patch( veh(2,:), veh(1,:), [5 5 5], vc );
n = text( 130, 125, 0, ['time: ' num2str(tc*0.1) 's'] ); drawnow; end;
Industrieel VisieLab:
[email protected] and
[email protected]
66
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
6.8. Fotonic Z40 camera:
6.8.1. Indoor application at Vision & Robotics.
% Tetra project 100191: RGBd, ToF !
July 2012.
% Luc Mertens & Wim Abbeloos & Rudi Penne:
Industrial VisionLab.
%
% Program: Indoor_WheelchairNavigation_VR2012. FOTONIC CAMERA .
%
% Our intention is to develop a wheelchair navigation system that is able
% to find its path from a given position and direction to a free selected
% end point and end direction. First we calculate a potential field. This
% may not have local minima and must keep the AGV away from the world
% objects. The gradient of the field shows the way to follow. If the actual
% direction differs from the desired one a PI-control system slightly
% changes it. The method isn't finished yet but from now different strategies
% can be evaluated and tested out.
function fot_app4()
% Fotonic application.
clear all; close all; clc;
global D L x y z nx ny nz L1 L2 wall ftime cd cnx cnz mo;
wb = 0.3625; v = 5; wf = 0.5; Kp = 0.5; Ki = 0; w = 350; h = 120; pi2 = 2*pi;
L1 = [ 350 350 -350 -350 60 -60 60
-270 -270 % Wall definition.
-350 -314 -314 -230 105 105 135;
-120 120 120 -120 120 80 80
120 84
-4 -4
-84 -84 -120 -76 -76];
L2 = [ 350 -350 -350 350
60 -60 -60
-270 -350 % Wall definition.
-314 -314 -230 -230 105 135 135;
120 120 -120 -120
80 120 80
84
84
-4 -84
-84 -120 -76 -76 -120];
fh = figure(); hold on; title( 'World' ); axis equal; h1 = gca; maxfig(fh,1);
xlim( [min(L1(1,:))-0.1 max(L1(1,:))+0.1]./100 );
ylim( [min(L1(2,:)-0.1) max(L1(2,:))+0.1]./100 );
map = false(240,700);
M1 = L1; M1(1,:) = M1(1,:) + 350; M1(2,:) = 120-M1(2,:);
M2 = L2; M2(1,:) = M2(1,:) + 350; M2(2,:) = 120-M2(2,:);
bw = (M1 == 0); M1(bw) = 1; bw = (M2 == 0); M2(bw) = 1;
for c1 = 1:size(L1,2)
map( min(M1(2,c1),M2(2,c1)):max(M1(2,c1),M2(2,c1)), ...
min(M1(1,c1),M2(1,c1)):max(M1(1,c1),M2(1,c1)) ) = 1;
plot( h1, [L1(1,c1) L2(1,c1)]./100, [L1(2,c1) L2(2,c1)]./100, 'k' ); end;
map((45:120)+120,(210:320)+350) = 1;
% Table
L1 = L1/100; L2 = L2/100;
L1 = cat( 1, L1, ones(1,size(L1,2)) ); L2 = cat( 1, L2, ones(1,size(L2,2)) );
map = imdilate( map, ones(10) ); % Enlarge the map.
ifh = figure(2); title( 'Map' ); imshow(map); maxfig(ifh,1); hold on;
xlabel( 'Select the endpoint' );
[epx epy] = ginput(1); ep = round([epx(1) epy(1)]); close( ifh ); % End point.
T = [-2.5 0 pi]; E = T; lmap = bwlabel( ~map );
% Labeled empty space.
ptodo = (lmap == lmap( ep(2), ep(1) )); ntodo = sum( ptodo(:) );
map2 = zeros( size(map), 'uint32' );
% Create empty map.
map2( ep(2), ep(1) ) = 2; cn = 3;
% Mark endpoint.
old = single(map2 ~= 0); O3 = ones( 3, 'single' );
while sum(old(:)) < ntodo
new = conv2( old, O3, 'same' ); ff = (~old & new & ptodo);
old(ff) = 1; map2(ff) = cn; cn = cn + 1; end;
% Create potential field.
% figure(100); imshow(map2,[]); colormap('jet');
Industrieel VisieLab:
[email protected] and
[email protected]
67
Association University and University Colleges Antwerp.
%
%
%
%
%
%
RGBd, ToF !
Final Report IWT 2012.
[t1 t2] = gradient(single(map2)); bw = imdilate( map2 < 1, ones(3) );
t1(bw) = 0; t1 = -t1; t2(bw) = 0;
% Wavefront vectors.
tn = imfilter(double(~bw), ones(10), 'same'); % Filter wavefront vectors.
tt1 = imfilter(t1, ones(10), 'same'); tt1 = tt1 ./ tn;
tt2 = imfilter(t2, ones(10), 'same'); tt2 = tt2 ./ tn;
D = bwdist(map);
% Distance to nearest object.
[d1 d2] = gradient(single(D)); d2 = -d2;
angles = atan2((tt2 + wf.*d2), (tt1 + wf.*d1)); % Angles of weighted fields.
bw = (angles < 0); angles(bw) = angles(bw) + pi2;
E1 = E(1); E2 = E(2); E3 = E(3); cosE = 0.1*cos(E3); sinE = 0.1*sin(E3);
T1 = T(1); T2 = T(2); T3 = T(3); cosT = 0.1*cos(T3); sinT = 0.1*sin(T3);
ed = map2(round(h-E2*100), round(E1*100+w)); % Distance to endpoint.
quiver(h1,E1,E2,cosE,sinE,'r'); quiver(h1,T1,T2,cosT,sinT,'g');
figure(1000); w2 2*w; h2 = h*2; axis equal; title('Wavefront vector field');
quiver(repmat((1:1:w2),[h2 1]),repmat((h2:-1:1)',[1 w2]),tt1,tt2);
figure(3000); axis equal; title('Distance vector field');
quiver(repmat((1:1:w2),[h2 1]),repmat((h2:-1:1)',[1 w2]),d1,d2);
figure(5000); axis equal; title('Combined vector field'); hold on;
quiver( repmat((1:1:w2),[h2 1]), repmat((h2:-1:1)', [1 w2]), tt1+d1/2, tt2+d2/2);
startmotor(6); fot_start(); fot_getframe(); st=ftime;% Start: motor/camera/timer.
while ed > 15
% While distance to end point > 15 pixel.
ltime = ftime; fot_getframe();
if E3 > 2*pi E3 = E3 - pi2; end; if E3 < 0 E3 = E3 + pi2; end;
ca = E3; ba = angles(round(h-E2*100), round(E1*100+w)); % Best angle.
[vl vr] = speeds(v,ca,ba,Kp,Ki);
% Speed controller.
motorcmd('setspeed1', vr); motorcmd('setspeed2', vl);
% Set speeds.
dt = ftime - ltime; ct = ftime - st; Eold = E;
[dx dy da db dd dc] = move1(E3,dt,wb,vl,vr);
% Update position.
[dx2 dy2 da2 db2 dd2 dc2] = move1(T3,dt,wb,vl,vr);
E = double(E + [dx dy da] );
T = double(T + [dx2 dy2 da2] );
if E3 > pi2 E3 = E3 - pi2; end; if E3 < 0 E3 = E3 + pi2; end
cosE = cos(E3); sinE = sin(E3);
quiver(h1, E1, E2, 0.1*cosE3, 0.1*sinE3, 'b');
ET = [cosE -sinE E1; sinE cosE E2; 0 0 1]; % New transformation matrix.
LT1 = ET\L1; LT2 = ET \ L2;
% Transform worldmap to camera.
leq = cross( LT1, LT2 ); leq1 = leq(1,:); leq2 = leq(2,:); leq3 = leq(3,:);
% World wall parameters in camera framework
wd = abs(leq3) ./sqrt(leq1.*leq1 + leq2.*leq2);
wnx = -sin(atan2(leq2,leq1)); wnz = cos(atan2(leq2,leq1));
walls();
% Get camera wall parameters.
wall = zeros( size(cd) ); % Associate camera walls to transformed world walls.
TC = 0; for c3 = 1:size(wall,1) de = abs((wd-cd(c3)) ./(0.01*wd));
xe = abs((wnx-cnx(c3))/0.05); ze = abs((wnz-cnz(c3))/0.05);
C = de + xe + ze; [mval mind] = min(C); % Search minimum cost.
wall(c3) = mind; TC = TC + mval; end;
% Total Cost.
m = [db dd dc]; [E cst] = fminsearch(@(t) cost(t,Eold,m), E); % Optimization.
if cst > TC disp('cost to high');
quiver( h1, E(1), E(2), 0.1*cos(E(3)), 0.1*sin(E(3)), 'k' );
E = double( Eold + [dx dy da] ); end;
E1 = E(1); E2 = E(2); E3 = E(3); sinE = 0.1*sin(E3); cosE = 0.1*cos(E3);
T1 = T(1); T2 = T(2); T3 = T(3); sinT = 0.1*sin(T3); cosT = 0.1*cos(T3);
ed = map2( round(h-E2*100), round(E1*100+w) );
% Distance to target.
quiver(h1,E1,E2,cosE,sinE,'r'); quiver(h1,T1,T2,cosT,sinT, 'g' ); drawnow; pause(0.1); end;
stopmotor(); fot_stop(); save('debug.mat');
% figure(200); subplot(121); imshow(D,[0.5 3]); title( 'Distance' );
%
subplot(122); imshow(L, []);
title( 'Luminance' );
Industrieel VisieLab:
[email protected] and
[email protected]
68
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
function [ dx dy da db dd dc ] = move1( a, dt, wb, vl, vr )
sf = 0.00588; % m/s per motor speed unit ( 0.00589 is a bit to high)
vl = vl * sf; vr = vr * sf; si = sin(a); co = cos(a);
if vl == vr da = 0; l = vl*dt; dx = l*co; dy = l*si; db = 0; dd = l; dc = 0;
else v = (vr+vl)/2; r = (vr*wb)/(vr-vl) - wb/2;
da = v/r * dt; dx1 = r*sin(da); dy1 = r*(1- cos(da));
dx = co*dx1 - si*dy1; dy = si*dx1 + co*dy1;
ta = atan2(dy,dx);
if abs(ta) > pi2 tms = fix(ta/pi2) + sign(ta); ta = ta - tms*pi2; end;
if abs(ta) > pi ta = ta - sign(ta)*pi2; end;
db = ta - a; if abs(db) > pi2 tms = fix(db/pi2) + sign(db); db = db - tms*pi2; end;
if abs(db) > pi db = db - sign(db)*pi2; end;
dd = sqrt(dx.*dx + dy.*dy); dc = ta - a;
if abs(dc) > pi2 tms = fix(dc/pi2) + sign(dc); dc = dc - tms*pi2; end;
if abs(dc) > pi
dc = dc - sign(dc)*pi2; end; end;
function C = cost(t,E,m)
global wall L1 L2 cd cnx cnz mo;
E1 = E(1); E2 = E(2); E3 = E(3); co = cos(t(3)); si = sin(t3);
ET = [co -si t(1); si co t(2); 0 0 1];
LT1 = ET \ L1; LT2 = ET \ L2;
u = LT1(2,:) .* LT2(3,:) - LT1(3,:) .* LT2(2,:);
% Cross product.
v = LT1(3,:) .* LT2(1,:) - LT1(1,:) .* LT2(3,:);
w = LT1(1,:) .* LT2(2,:) - LT1(2,:) .* LT2(1,:);
wd = abs(w)./sqrt( u.*u + v.*v); wnx = -sin(atan2(v,u)); wnz = cos(atan2(v,u));
C = 0; for c1 = 1:size(wall,1)
if wall(c1) ~= 0
de = abs(( wd(wall(c1))- cd(c1)) ./ ( 0.01 * wd(wall(c1)) ));
xe = abs((wnx(wall(c1))-cnx(c1)) ./ 0.05);
ze = abs((wnz(wall(c1))-cnz(c1)) ./ 0.05);
C = C + de + xe + ze; end; end;
ta = atan2(t(2)-E2,t(1)-E1);
if abs(ta) > pi2 tms = fix(ta/pi2)) + sign(ta); ta = ta - tms*pi2; end;
if abs(ta) > pi ta = ta - sign(ta)*pi2; end;
dbl = ta - E3; if abs(dbl) > pi2 tms = fix(dbl/pi2) + sign(dbl);
dbl = dbl - tms*pi2; end;
if abs(dbl) > pi dbl = dbl - sign(dbl)*pi2; end;
ddl = sqrt((E1-t(1))^2+(E2-t(2))^2); dcl = t(3) - ta;
if abs(dcl) > pi2 tms = fix(dcl/pi2) + sign(dcl); dcl = dcl - tms*pi2; end;
if abs(dcl) > pi dcl = dcl - sign(dcl)*pi2; end;
mo = [dbl ddl dcl]; C = C*(1+ ((dbl-m(1))^2 + 100*(ddl-m(2))^2 +
(dcl-m(3))^2));
function walls()
global D L x y z nx ny nz fs cd cnx cnz;
wallsize = 200; T = single( 0.6 );
% Minimum size and threshold.
h = uint16(size(D,1)); w = uint16(size(D,2));
% Image sizes.
check = abs(ny) < 0.5 & D > 0 & y < 0; % Vertical, add height constraint on y.
check( :,1:4) = 0; check( :, end-4:end ) = 0;
% Exclude borders.
%figure(800); imshow(check);
NB = [ -1 0; 0 1; 1 0; 0 -1 ]; NBS = uint8(size(NB,1));
% Connectedness.
list = zeros(w*h,2,'uint16' ); npix = zeros(w*h,1,'uint16');
region = zeros(h,w,'uint16'); cur_reg = uint16(1);
for a = 1:h,
for b = 1:w, if check(a,b) region(a,b) = cur_reg; cur_regs = 1;
m = [nx(a,b) nz(a,b)]; list(1,:) = [a b]; last = uint16(1);
while last > 0 u = list(last,1); v = list(last,2); last = last - 1;
Industrieel VisieLab:
[email protected] and
[email protected]
69
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
if check(u,v)
for c1 = 1:NBS iu = u + NB(c1,1); iv = v + NB(c1,2);
% Inside?
if iu > 0 && iu <= h && iv > 0 && iv <= w && check( iu, iv )
d = sqrt((m(1) - nx(iu,iv)).^2 + (m(2) - nz(iu, iv)).^2 );
if d <= T last = last + 1; region(iu,iv) = cur_reg;
m = m + [nx(iu,iv)-m(1) nz(iu,iv)-m(2)]./cur_regs;
cur_regs = cur_regs + 1; list(last,1) = iu; list(last,2) = iv;
end; end; end;
check( u, v ) = false; end; end;
npix( cur_reg ) = cur_regs; cur_reg = cur_reg + 1; end; end; end;
goodwalls = find( npix > wallsize );
cd=[]; cnx = []; cnz = []; % Wall parameters: perpencidular distance, nx and nz.
for c1 = 1:size(goodwalls,1)
cur_wall = (region == goodwalls(c1)); p = polyfit(x(cur_wall),z(cur_wall),1);
cd = cat(1,cd,abs(p(2))./sqrt(p(1).*p(1)+1)); % Current perp. distance.
cnx = cat(1,cnx,mean(nx(cur_wall)));
% Current normal-x.
cnz = cat(1,cnz,mean(nz(cur_wall))); end;
% Current normal-x.
for c1 = 1:h, for c2 = 1:w
% Remove region if not good.
if region(c1,c2) ~= 0 & npix(region(c1,c2)) < wallsize region(c1,c2) = 0;
end; end; end;
% figure(100); subplot(121); imshow(D,[]);
title( 'Distance' );
%
subplot(122); imshow(region,[0 1]); title( 'Vertical planes' );
function [vl vr] = speeds(v,ca,ba,Kp,Ki)
% current angle, best angle, Proportional factor, Integral factor, add speed error.
global aev
% 'Angle error vector', used for integration.
if abs(ba - ca) < pi ae = ba - ca; else ae = ba - ca - sign(ba-ca)*pi2; end;
if size(aev,1) < 5 aev = cat(1,aev,ae);
else aev(1:end-1) = aev(2:end); aev(end) = ae; end;
% Update aev.
dv = (Kp*ae + Ki*sum(aev))*2/pi;
% Set speeds.
vl = v*(1-dv); vr = v*(1+dv);
function fot_start()
addpath('CameraCtrl\'); Closeldu; global cont;
cont.first = 1;
OpenCamera(); StartSensor(); % Open camera and start comm. interface.
%
SetMode('MSSTcont');
% Set mode to Multishutter.
%
SetMSlimit(1000);
% Value proportional to Active brightness.
%
SetMSShutter(220,25);
% Value in 0.1 ms.
SetMode('MultiSpatioTemporal');
% Set mode to Multishutter.
SetShutter(300);
% Value in 0.1 ms.
SetFrameRate(20);
% Set frame rate to 20 fps.
SetLightSwitchState(1);
% Turn on LED's.
for i=1:100, [xt, yt, zt, Lt] = GrabImage(); end;
% Dummy images.
function fot_getframe()
global x y z D L nx ny nz ftime;
[yt, xt, zt, Lt, fc, head] = GrabImage();
x = double(rot90(xt))./1000; y = -double(rot90(yt))./1000;
z = double(rot90(zt))./1000; L = rot90(Lt); D = sqrt(x.*x + y.*y + z.*z);
ftime = double(head.reserved(1)) + double(head.reserved(2))/1000; % Time.
fs = 9; f1 = zeros(1, fs); f1(1) = 1; f1(end) = -1; f2 = f1'; % Filter preparation.
z1 = conv2( z, f1, 'same' ); z2 = conv2( z, f2, 'same' );
x1 = conv2( x, f1, 'same' ); x2 = conv2( x, f2, 'same' );
y1 = conv2( y, f1, 'same' ); y2 = conv2( y, f2, 'same' );
nx = y1.*z2-z1.*y2; ny = z1.*x2-x1.*z2; nz = x1.*y2-y1.*x2; % Normal.
n = sqrt( nx.^2 + ny.^2 + nz.^2 ); nx = nx ./ n; ny = ny ./ n; nz = nz ./ n;
Industrieel VisieLab:
[email protected] and
[email protected]
70
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
function fot_stop()
StopSensor(); CloseCamera(); Closeldu;
function startmotor( portnr )
global motor; delete( instrfind );
port = strcat('COM', num2str(portnr));
% Start serial communication
motor = serial( port, 'BaudRate', 9600, 'Parity', 'none', 'DataBits', 8, …
'StopBits', 2, 'Timeout', 0.2 );
fopen( motor );
motorcmd( 'disabletimeout' ); motorcmd( 'enablereg' ); motorcmd( 'resetenc' );
motorcmd('setmode',1); motorcmd('setspeed1',0); motorcmd('setspeed2',0);
motorcmd( 'setaccel', 1 ); %motorcmd( 'setaccel', 10 );
function stopmotor()
% Stop serial communication.
global motor;
motorcmd('setmode',1); motorcmd('setspeed1',0); motorcmd('setspeed2',0);
motorcmd( 'enabletimeout' );
fclose( motor ); delete( motor ); clear( 'motor' );
function varargout = motorcmd( cmd, varargin )
% MOTOR COMMANDS.
global motor;
if ~ischar( cmd ) error( 'Second argument must be a command string' ); end;
switch cmd
case 'getspeed1'
fwrite(motor,[0 33],'int8'); % returns the current requested speed of motor 1
varargout(1) = { -fread( motor, 1, 'uint8' ) };
case 'getspeed2'
fwrite(motor,[0 34],'int8'); % returns the current requested speed of motor 2
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getenc1'
% Motor 1.
fwrite(motor,[0 35],'uint8');
% 4 bytes returned high byte first (signed).
val = fread( motor, 4, 'uint8' );
val2 = uint32( bitcmp( uint8(val) ) );
val3 = bitshift(val2(1),24)+bitshift(val2(1),16)+bitshift(val2(3),8)+val2(4);
varargout(1) = { val3 };
case 'getenc2'
% Motor 2.
fwrite(motor,[0 36],'uint8');
% 4 bytes returned high byte first (signed).
val = fread( motor, 4, 'uint8' );
val2 = uint32( bitcmp( uint8(val) ) );
val3 = bitshift(val2(1),24)+bitshift(val2(1),16)+bitshift(val2(3),8)+val2(4);
varargout(1) = { double(val3) };
case 'getencs'
fwrite(motor,[0 37],'uint8'); % Returns 8 bytes. Encoder1/encoder2 count.
varargout(1) = { fread( motor, 8, 'uint8' ) };
case 'getvolts'
fwrite( motor, [0 38], 'uint8' );
% Returns the input battery voltage level.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent1'
fwrite( motor, [0 39], 'uint8' );
% Returns the current drawn by motor 1.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent2'
fwrite( motor, [0 40], 'uint8' );
% returns the current drawn by motor 2.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getversion'
fwrite( motor, [0 41], 'uint8' );
% Returns the software version.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getaccel'
fwrite( motor, [0 42], 'uint8' );
% Returns the current acceleration level.
Industrieel VisieLab:
[email protected] and
[email protected]
71
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getmode'
fwrite( motor, [0 43], 'uint8' );
% Returns the currently selected mode.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getVI'
fwrite( motor, [0 44], 'uint8' );
% Returns Volts, current1 and current2.
varargout(1) = { fread( motor, 1, 'uint8' ) }; % Battery voltage
varargout(2) = { fread( motor, 1, 'uint8' ) }; % Current motor 1
varargout(3) = { fread( motor, 1, 'uint8' ) }; % Current motor 2
case 'setspeed1'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
speed = cell2mat(varargin(1));
fwrite( motor, [0 49 -speed], 'int8' ); % set new speed1
case 'setspeed2'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
speed = cell2mat(varargin(1));
fwrite( motor, [0 50 -speed], 'int8' ); % set new speed2
case 'setaccel'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
accel = cell2mat(varargin(1));
fwrite( motor, [0 51 accel], 'uint8' ); % set new acceleration
case 'setmode'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
mode = cell2mat(varargin(1));
fwrite( motor, [0 52 mode], 'uint8' );
% Set the mode.
case 'resetenc'
fwrite( motor, [0 53], 'uint8' );
% Zero both of the encoder counts.
case 'disablereg'
fwrite(motor,[0 54],'uint8'); % Power output not changed by encoder feedback.
case 'enablereg'
fwrite(motor,[0 55],'uint8'); % Power output regulated by encoder feedback.
case 'disabletimeout'
fwrite( motor, [0 56], 'uint8' ); % Continuous output if no-regular commands.
case 'enabletimeout'
fwrite( motor, [0 57], 'uint8' );
% Watch dog, 2 seconds.
otherwise
error( 'Incorrect command' );
end;
Industrieel VisieLab:
[email protected] and
[email protected]
72
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
8.6.2. Outdoor application at Vision & Robotics.
% Tetra project 100191: RGBd, ToF !
June 2012.
% Wim Abbeloos & Luc Mertens:
Industrial VisionLab.
%
% Program: Outdoor_WheelchairNavigation_VR2012. FOTONIC CAMERA .
%
% Our intention is to organize a closed loop wheelchair parcours .
% In an open area the camera is looking for a door opening in a wall.
% It uses the right door edge to calculate the radius of a circle that
% will bring the wheelchair to the other domain part. There it turns
% around and will come back through the door.
function outdoorv2()
% Created for the Fotonic ToF camera.
clear all; close all; clc;
global x y z D L nx ny nz d;
fot_start(); startmotor(); loop = 0; step = 1; first = 0;
while loop == 0
fot_getframe();
% function starts at line 77.
switch step % Start driving: speed = 30 % ; Angular Velocity = 50 % .
case 1
% Rotate right untill R = 0 .
motorcmd(30,60); R = analyze_img1(); if R ~= 0 c1 = c1+1; end;
case 2
% R ~=0 , so rotate over a fixed time.
beep; motorcmd(33, -round(245/R)); P = analyse_img2();
if P ~= 0 beep; step = 3; end;
% Search for the small plate.
case 3
% Drive straight forward but compensate for deviations.
motorcmd(40,4); pause(9); c1 = 1; end;
if first == 0 first = 1; t = tic; end;
if toc(t) > 20 motorcmd( 0, 0 ); loop = 1; first = 0; end;
otherwise
motorcmd(0,0); break; end; end; stopmotor(); fot_stop();
function fot_start()
addpath('CameraCtrl\'); Closeldu; global cont; cont.first = 1;
OpenCamera();
% Open sensor communication interface.
StartSensor();
SetMode('MultiSpatioTemporal');
% Set mode to Multishutter.
SetShutter(800);
% Value in 0.1 ms.
SetFrameRate(20);
% Set frame rate to 20 fps.
SetLightSwitchState(1);
% Turn on LED's.
for i=1:100 [xt, yt, zt, Lt] = GrabImage(); end; % Dummy information.
function startmotor()
% Start a serial motor communication.
global motor;
delete(instrfind);
% Delete the list of connected instruments.
motor = serial('COM4','BaudRate',38400,'Parity', 'none',...
'DataBits',8,'StopBits',2,'Timeout',0.2);
fopen(motor); motorcmd(0,0);
function stopmotor()
% Stop the serial motor communication.
global motor;
motorcmd(0,0); fclose(motor); delete(motor); clear('motor');
function motorcmd(fwd,trn)
% Command motor: turn = 5 on a scale -100 -> 100 .
%
forward speed = 20 on a scale -100 --> 100 .
%
Full scale = 100.
% Build the string <XY X='5' Y='20' S='100'/> \r and send it to the motor.
Industrieel VisieLab:
[email protected] and
[email protected]
73
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
global motor;
str1 = '<XY X='''; str2 = num2str(trn); str3 = ''' Y='''; str4 = num2str(fwd);
str5 = ''' S=''100''/>'; fprintf(motor,strcat(str1,str2,str3,str4,str5));
function R = analyze_img1()
% Find largest wall part.
global x y z nx ny nz D L; R = 0;
% In case no wall is found, R = 0 .
bwW = abs(ny) < 0.6 & L > 0 & nx > 0 & y > -0.50 & y < 0.2 & del2(z) < 0.2;
bwW = imerode(bwW, ones(2)); [Seg, count] = bwlabel(bwW); % Segmentation.
MSeg = 0; MArea = 0;
% Largest wall area
for c1 = 1:count cS = (Seg == c1); cSA = sum(cS(:)); % Current segment area.
if cSA > MArea MSeg = c1; MArea = cSA; end; end;
if MArea > 500 Wall = (Seg == MSeg);
% Wall segment large enough.
WallSum = sum(Wall); Corner = min(find(WallSum > 5)) + 1; % Find corner.
if Corner < 50 && Corner > 20
% If corner 'frontal'.
ff = find(Wall(:,Corner) == true);
% Find x and z values for corner.
xcorner = mean(x(ff,Corner)); zcorner = mean(z(ff,Corner));
ff = find(Wall(:,60)==true);
% Find x and z values in the middle.
xmid = mean(x(ff,60)); zmid = mean(z(ff,60)); dmid = mean(D(ff,60));
alfa = acos( mean2(nx(Wall) )) * 180 / pi;
% Find radius.
XX = sqrt( (xcorner-xmid).^2 + (zcorner-zmid).^2 );
R = dmid/cosd(alfa) - 0.75 - XX; save('debug_R.mat');
%
figure(1); subplot(121); imshow( L, []); subplot(122); imshow( z, [0 5]);
%
figure(2); imshow(Wall); xlabel(num2str(sum(Wall(:))));
%
figure(3); plot( x(Wall), z(Wall), 'r*' ); xlim( [-3 3] ); ylim( [0 5] );
end; end;
function P = analyze_img2()
global x y z nx ny nz D L; P = 0;
% In case no plate is found, P = 0.
bwP = abs(ny) < 0.6 & D > 4; L > 0 & abs(nx) < 0.5 &...
y > -0.50 & y < 0.2 & del2(z) < 0.2;
bwP = imerode(bwP, ones(2)); [Seg, count] = bwlabel(bwP); % Segmentation.
MSeg = 0; MArea = 0;
% Largest wall area
for c1 = 1:count cS = (Seg == c1); cSA = sum(cS(:)); % Current segment area.
if cSA > MArea MSeg = c1; MArea = cSA; end; end;
if MArea > 100 Plate = (Seg == MSeg);
% Plate found ?
if mean(abs(nx(Plate))) < 0.3 P = 1; save('debug_P.mat'); end; end;
function fot_getframe()
global x y z D L nx ny nz ftime;
[yt, xt, zt, Lt, fc, head] = GrabImage(); L = rot90(Lt);
x = double(rot90(xt))./1000; y = -double(rot90(yt))./1000;
z = double(rot90(zt))./1000; D = sqrt(x.*x + y.*y + z.*z);
ftime = double(head.reserved(1)) + double(head.reserved(2))/1000; % Time.
fs = 9; f1 = zeros(1, fs); f1(1) = 1; f1(end) = -1; f2 = f1';
% Filter preparation.
x1 = conv2( x, f1, 'same' ); x2 = conv2( x, f2, 'same' );
y1 = conv2( y, f1, 'same' ); y2 = conv2( y, f2, 'same' );
z1 = conv2( z, f1, 'same' ); z2 = conv2( z, f2, 'same' );
nx = y1.*z2-z1.*y2; ny = z1.*x2-x1.*z2; nz = x1.*y2-y1.*x2; % Normal vectors.
n = sqrt(nx.*nx + ny.*ny + nz.*nz); nx = nx./n; ny = ny./n; nz = nz./n;
function fot_stop()
StopSensor(); CloseCamera(); Closeldu;
Industrieel VisieLab:
% ?? ldu = ?
[email protected] and
[email protected]
74
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
7. Material handling
7.1. Hero-Technologies: material handling combined with free OCR.
7.1.1. Procedure in advance:
1. Bring the camera in an orientation so that it can view a marble at a central
position. After this the camera may not move anymore !.
2. Define a robot reference coordinate system.
3. Take an image of ‘the flat work plane’ and find: f , corr, k u , kv , ROTx and ROTy.
4. Bring the constants into the Hero_PickUp program.
ROTx = -ROTx en ROTy = -ROTy since the program needs to transform back.
5. Take 3 images of the separate characters H E R and derive their histograms.
6. Find the histograms of other characters X Y Z …
Make use of characters with enough ‘histogram contrast’ relative to H E R .
7. Take random stacked combinations of characters and verify if the program
works well.
8. Verify that the axis found are perpendicular to one other : R*R’ = I 3 .
9. If the previous works well, the program is OK.
Success ... ToF !.
ifm electronic: O3D2xx ToF camera
You Tube: ‘KdGiVL’.
Time of flight
3D – OCR
Bin Picking
Proof of concept (1)
Tim Godden, Wim Abbeloos en Luc Mertens.
FANUC M – 10iA
Industrieel VisieLab:
[email protected] and
[email protected]
75
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
7.1.2. Matlab program
% Tetra project 100191: RGBd, TOF !
June 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
% Mesut Usul, Zoltán Nyiro ; Kornel Koksic;
% Program: Robo_OCR.m .
%
% This program can deal with a stack of 3D-characters. Each character is member
% of a specific font (Height = 150 mm, Width = 120 mm, Thickness = 25 mm).
% A character can be found by edge-considerations in the 'range image (ToF)'.
% The 'distance gradients' can be used during the segmentation of th image.
% The edges could be found easely. Image resizing seems to be an other
% interesting approach.
close all; clear all; home; rep = 'replicate'; O2 = ones(2); O3 = ones(3); O4 = ones(4);
disp('From calibration: f = 85, z0 = 673.4 ; ROT = -0.342');
z0 = 673; ROT = 0.342 ; co = cos(ROT); si = sin(ROT);% sign opposite to turn back!
G = fspecial('gaussian',7,1.2); ku = 1.016 ; kv = 1.001; f = 85; f2 = 2*f; ff = f2*f2;
load('ifm_RH1.mat'); % HE, HE1, HER, RE, RH, RH1.
% [D L] = AcquireIFM(400); % With some intergration time, acquire D and L image.
t0 = cputime; [I J] = size(D); LD = L./D;
% ToF Confidence matrix.
ROId = 1000*D(4:end-3,4:end-3);
ROId = kron(ROId,O2); ROId = imfilter(ROId,G,rep);
[I J] = size(ROId); I2 = I/2; J2 = J/2; IJ = I*J; x = zeros(I,J); y = x; z = x;
% Edge detection based on row and column wise differences ...
dDr = abs(diff(ROId));
dDr = cat(1, dDr(1,:),dDr);
dDc = abs(diff(ROId,1,2)); dDc = cat(2, dDc(:,1),dDc);
dD = max(dDr,dDc); BW = dD < 5 ; BW = imerode(BW,O2);
figure; imshow(BW);
[label count] = bwlabel(BW,4);
% Label the connected regions.
C = [];
for c=1:count,
% Objects may not touch the image border.
bw = (label==c); rs = sum(bw,2); cs = sum(bw); Area = sum(cs);
if Area > 250 && Area < 5000 && rs(1)*cs(1)*rs(end)*cs(end) == 0
C = [C c]; end; end;
if length(C) > 0
mm = min(min(ROId(I2-45:I2+45,J2-35:J2+35)));
MM = label(find(ROId == mm)); MMlabel = MM(1);
object = (label==MMlabel); rs = sum(object,2); cs = sum(object);
Area = sum(rs); BlobThin = bwmorph(object,'thin',inf); % Intensive calcul!
for i = 1:I, for j = 1:J,
if BlobThin(i,j) == true; v = kv*(i-I2+0.5); u = ku*(j-J2+0.5);
d = sqrt(ff+u*u+v*v); Dd = ROId(i,j)/d;
y(i,j) = v*Dd; x(i,j) = u*Dd; z(i,j) = f2*Dd; end; end; end;
FF = find(BlobThin == true); Len = length(FF);
XYZ = [mean(x(FF)); mean(y(FF)); mean(z(FF))];
% Pick up nearby XYZ.
X = x(FF) - XYZ(1); Y = y(FF) - XYZ(2); Z = z(FF) - XYZ(3);
data = cat(2,ones(Len,1),X,Y);
a = data\Z; a1 = 0; a2 = a(2); a3 = a(3); % Linear best fit: Z = a2.X + a3.Y .
N = [a2; a3; -1.0]; N = N/norm(N);
ZZ = a2*X + a3*Y;
% Noisy points are projected to the best fit plane.
Char = false(201); R2 = 10000;
% Character in millimeter size.
for tt = 1:Len
% Looking for the pick up point.
Xtt = X(tt); Ytt = Y(tt); ZZtt = ZZ(tt); XXr = round(Xtt); YYr = round(Ytt);
r2 = Xtt*Xtt + Ytt*Ytt +ZZtt*ZZtt; if r2 < R2 R2 = r2 ; TT = tt; end;
Char(XXr+99:XXr+100,YYr+99:YYr+100) = true; end;
XXR = round(X(TT)); YYR = round(Y(TT));
Industrieel VisieLab:
[email protected] and
[email protected]
76
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
vecX = [90; 90; a2*90+a3*90]; vecX = vecX/norm(vecX);
vecY = cross(N,vecX); vecY = vecY/norm(vecY);
xyz = XYZ + [X(TT); Y(TT); ZZ(TT)];
PUy = - xyz(2)*co + xyz(3)*si - z0*si;
% Remember y is downwards.
PUz = - xyz(2)*si - xyz(3)*co + z0*co;
PU = round (10*[xyz(1) PUy PUz ])/10; % World pick up positions: x, y, z.
R = [vecX vecY N]'; RR = R*R';
aa = 180*atan2(R(3,2),R(3,3))/pi;
% Rotation around x.
bb = 180*atan2(-R(3,1),sqrt(R(3,2)^2 + R(3,3)^2))/pi; %
around y.
cc = 180*atan2(R(2,1),R(1,1))/pi;
% Rotation around z.
% OCR part
Radii = zeros(201); Cloud = [];
% Collecting square radii of CharSE.
SE = strel('octagon',6); CharSE = imdilate(Char,SE); % Octagonal element.
for i = 1:201, for j = 1:201,
if CharSE(i,j) == true; ii = (i-100)*(i-100); jj = (j-100)*(j-100);
Radii(i,j) = sqrt(ii + jj); end; end; end;
Cloud = Radii(find(Radii>0)); % B/W-cloud as a basis for the histogram.
% Remember the expected histogram from a learning step:
% H = hist(Cloud, [7.5:15:90]); H = H/sum(H);
HH = [0.0938 0.1173 0.3375 0.2912 0.1588 0.0014];
HO = [ 0
0.0283 0.3974 0.3472 0.2271
0
];
HR = [0.0626 0.1571 0.2537 0.3810 0.1352 0.0103];
HE = [0.0858 0.1340 0.1853 0.3063 0.2659 0.0227];
HV = [0.0668 0.4316 0.2308 0.2210 0.0499
0];
HX = [0.1268 0.2048 0.2615 0.2592 0.1370 0.0108];
H = hist(Cloud, [7.5:15:90]); H = H/sum(H);
% Measured histogram.
SSQ = zeros(1,4);
% Evaluate histogram, relative to H E R O .
SSQ(1) = (HH-H)*(HH-H)'; SSQ(2) = (HE-H)*(HE-H)';
SSQ(3) = (HR-H)*(HR-H)'; SSQ(4) = (HO-H)*(HO-H)';
[ssq pos] = min(SSQ); hero = ['H'; 'E'; 'R'; 'O'];
if ssq < 0.1 Character = hero(pos); text = cat(2,'Character = ', Character);
else text = cat(2,'Character differs from H, E, R, O'); end;
t0 = cputime - t0
disp('R = [vecX" vecY" N"]');
R=R
RR = R*R'
aa = 180*atan2(R(3,2),R(3,3))/pi
bb = 180*atan2(-R(3,1),sqrt(R(3,2)^2 + R(3,3)^2))/pi
cc = 180*atan2(R(2,1),R(1,1))/pi
figure(1);
subplot(221); imshow(ROId,[]); title('Raw Distance values.');
subplot(222); imshow(label*round(255/(count-1)),[0 255]);
title('Labeled image segments');
subplot(223); imshow(dD,[]); title('dD = max(abs(dDr),abs(dDc))');
subplot(224); imshow(object); title('Highest free object');
figure(2);
subplot(221); imshow(ROId,[]); title('Raw Distance values.');
subplot(222); imshow(LD,[]); title('ToF confidence image.');
subplot(223); imshow(z ,[]); title('Corresponding z-values.');
subplot(224); imshow(label*round(255/(count-1)),[0 255]);
title('Labeled image segments');
figure(3);
Char(XXR+97:XXR+103,YYR+97:YYR+103) = true;
object(I2,:) = true; object(:,J2) = true;
subplot(231); imshow(Char); title('Relative to the robot.');
xlabel('Pick Up Point = big square.');
Industrieel VisieLab:
[email protected] and
[email protected]
77
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
subplot(232); hold on; axis([-80 80 -80 80 -80 80]); view(20,45);
plot3( X,Y,Z,'.'); xlabel('x-as'); ylabel('y-as'); zlabel('z-as'); grid on;
subplot(233); hold on; axis([-80 80 -80 80 -80 80]); view(20,45);
plot3(X,Y,ZZ,'.'); xlabel('x-as'); ylabel('y-as'); zlabel('z-as'); grid on;
plot3(vecX(1),vecX(2),vecX(3),'r.'); plot3(0,0,0,'r.');
plot3([0 100*vecX(1)],[0 100*vecX(2)],[0 100*vecX(3)],'r');
plot3([0 100*vecY(1)],[0 100*vecY(2)],[0 100*vecY(3)],'g');
plot3([0 50*N(1)],[0 50*N(2)],[0 50*N(3)],'b');
title(cat(2,'CPUtime = ',num2str(t0)));
subplot(234); imshow(z,[]); title('z-values');
xlabel(cat(2,'Gravity xyz = [ ',num2str(xyz'),' ]'));
ylabel('Segments marked');
subplot(235); imshow(BW); title('Flat object --> white !');
xlabel(cat(2,'N = [ ',num2str(N'),' ]'));
ylabel(cat(2,'Area = ',num2str(Area)));
subplot(236); imshow(object);
title(cat(2,'Pick Up position: PU = ',num2str(PU)));
xlabel(cat(2,'z = ',num2str(round(XYZ(3))),' + (', num2str(round...
(-1000*a(2))/1000),').x + (', num2str(round(-1000*a(3))/1000),').y '));
ylabel('Camera x // robot x, camera y // robot y.')
figure(4);
for alfa = 0:360, co = cos(alfa); si = sin(alfa);
for Radius = 15:15:95
CharSE(100+round(co*Radius),100+round(si*Radius)) = true; end; end;
subplot(121); imshow(CharSE); title(text);
xlabel(cat(2,'CPUtime = ',num2str(t0)));
subplot(122); hist(Cloud,[10:15:99]); title('Histogram of the cloud point radii');
else disp('No objects found'); end;
Industrieel VisieLab:
[email protected] and
[email protected]
78
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
79
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
7.2. University College Limburg, Flanders (KHLim): peppers handling.
% Tetra project 100191: RGBd, TOF !
June 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
% Mesut Usul (Master student).
%
% Program: 'PepperD_short.m'.
%
% This program analyses the difference between an empty and a loaded pepper
% scene. The peppers are isolated and their orientation are found one by one.
% Paprika0 is the empty image giving the characteristics of the work plane.
% This plane can be used to calibrate the ToF camera in order to find the
% focal length, the distortion parameters ku en kv, the angles of the work plane
% relative to the camera...
%
% Image names are: paprika11 ->15 ; 21-> 25; ... ; 51 -> 55.
close all; clear all; home; Thres = 0.005; O4 = ones(4);
G = fspecial('gaussian',5,2); rep = 'replicate'; se3 = [0 1 0 ; 1 1 1 ; 0 1 0];
load Paprika D0; load('paprika54.mat'); L = ones(size(D));
t0 = cputime;
D = 1500*kron(D, O4); D = imfilter(D,G,rep);
% To millimeter + magnif.
% D0 = D; save Paprika D0; imshow(D0,[]); pause;
% Reference plane.
ff = find( D > (D0-0.005)); D(ff) = D0(ff);
% Remove below the work plane.
[I J] = size(D); I2 = round(I/2); J2 = round(J/2); Dw = D0 - D; L = kron(L, O4);
[gX gY] = gradient(Dw,7);
% Gradient distance = 3,5,7... .
[Firstlabel, count] = bwlabel(Dw,4);
% Label the connected regions.
for cc = 1:count, ff = find(Firstlabel == cc);
if length(ff) < 500 Dw(ff) = 0; end; end;
% Remove small objects.
gg = gX.*gX + gY.*gY; bwG = gg > 0.5;
% Find pepper border.
bwDw = Dw > 0.01; bw = bwDw & ~bwG;
% Shrink the blobs.
bw = imdilate(bw,ones(3)); bw = imerode(bw,strel('disk',10));
[label, count] = bwlabel(bw,4); CC = [];
for c = 1:count, FF = find(label==c);
% Remove small objects.
if length(FF) < 50 bw(FF) = false; else CC = cat(2,CC,c); end; end;
LenCC = length(CC); T = 0; Segment = zeros(I,J); paprika = false(I,J,LenCC);
if LenCC >0
for c = 1:LenCC, object = false(I,J); FF = find(label==CC(c));
object(FF)= true; papri = imdilate(object,strel('disk',12)) & bwDw;
T = T+1; paprika(:,:,c) = papri; FF = find(papri==true); Segment(FF) = T;
papri(:,J2) = true; papri(I2,:) = true;
s = regionprops(Segment, 'area','orientation','centroid');
Area = cat(2,s.Area); Orient = cat(2,s.Orientation);
Centroids = cat(1, s.Centroid);
Centroids(:,1) = Centroids(:,1) - J2; Centroids(:,2) = Centroids(:,2) - I2;
figure(c); imshow(papri); title(cat(2,'Pepper #',num2str(c)));
xlabel(cat(2,'A = ',num2str(Area(c)),' Orient = ',...
num2str(round(Orient(c)))));
ylabel(cat(2,'Center = ',num2str(round(Centroids(c,:)))));
end; end;
t0 = cputime-t0;
figure(10); subplot(221); imshow(Dw,[]); title('Approx. Thickness');
subplot(222); imshow(bwDw,[]);
title('bwDw = (D0-D) > 0.01 . ');
subplot(223); imshow(gg,[0 1]);
title('gg = (gradX² + gradY²) .');
subplot(224); imshow(Segment,[]);
title('Segmented Peppers.');
xlabel(cat(2,'Time to find regionprops = ',num2str(t0)));
Industrieel VisieLab:
[email protected] and
[email protected]
80
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
81
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Function regionprops: --> Region Properties.
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
'Image'
'Perimeter'
'Area'
'Centroid'
'BoundingBox'
'Extent'
'EquivDiameter'
'MajorAxisLength'
'MinorAxisLength'
'Eccentricity'
'Orientation'
'FilledImage'
'FilledArea'
'ConvexHull'
'ConvexImage'
'ConvexArea'
'Solidity'
'Extrema'
'EulerNumber'
Sub image per 'area', met afmetingen van de Bounding Box.
Omtreklengte, geteld in aantal pixel.
Oppervlakte, geteld in aantal pixel.
Zwaartepunt van de pixelcollectie.
Omsloten rechthoek volgens de rij en kolomrichting.
Vullingsgraad van de 'BoundingBox'
Traagsheidsstraal: 4*area/pi .
Lengte van de hoofd-as, gemeten in pixel.
Lengte van de neven-as, gemeten in pixel.
Verhouding: Minor/Major axis.
Oriëntatie van de hoofdas tegenover de rijrichting.
Opgevuld oppervlak.
Oppervlak na opvulling van de holten.
Kleinste, omsloten vierhoek. (Omhullende vierhoek).
Black/White image van de convex hull. (Mask).
Aantal 'true'-pixels in de 'ConvexImage'.
Vullingsgraad van de 'convex hull'.
Rij- en kolomcoördinaten van de 8 uiterst-gelegen punten.
Aantal objecten, verminderd met het aantal gaten.
% *******************************
% Function 'bwmorph' --> Morphological Operations:
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
'bridge'
Bridge previously unconnected pixels.
'clean'
Remove isolated pixels (1's surrounded by 0's).
'fill'
Fill isolated interior pixels (0's surrounded by 1's).
'open'
Perform binary opening (erosion followed by dilation).
'close'
Perform binary closure (dilation followed by erosion).
'bothat' Subtract the input image from its closing.
'tophat' Subtract the opening from the input image.
'diag'
Diagonal fill to eliminate 8-connectivity of background.
'dilate'
Perform dilation using the structuring element ones(3).
'erode'
Perform erosion using the structuring element ones(3).
'hbreak' Remove H-connected pixels.
'majority' Set a pixel to 1 if five or more pixels in its 3-by-3 neighbors are 1's.
'remove' Set a pixel to 0 if its 4-connected neighbors are all 1's,
thus leaving only boundary pixels.
'shrink'
With N = Inf, shrink objects to points;
shrink objects with holes to connected rings
'skel'
With N = Inf, 'remove' pixels on the boundaries of objects without
allowing objects to break apart.
'spur'
Remove end points of lines without removing small objects.
'thicken' With N = Inf, thicken objects by adding pixels to the exterior of
objects without connecting previously unconnected objects.
'thin' With N = Inf, remove pixels so that an object without holes shrinks to
a minimally connected stroke, and an object with holes shrinks
to a ring halfway between the hole and outer boundary.
Industrieel VisieLab:
[email protected] and
[email protected]
82
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
7.3. KdG: palet handling
RGBd
kke
ewi
g
n
I
ld !
DepthSense 311
1. Find the z –discontinuity
2. Look for vertical parts with
forward oriented normals
3. Inspect collineraity
4. Use geometrical laws
in order to find
x, y, z and b.
ToF
ikke
Ingew
ld !
Mesa SwissRanger 4000
1. Remove bright pixels
2. Find the z –discontinuity
3. Look for vertical parts with
forward oriented normals
4. Inspect collineraity
5. Use geometrical laws
in order to find
x, y, z and b.
Industrieel VisieLab:
[email protected] and
[email protected]
83
Association University and University Colleges Antwerp.
ToF
RGBd, ToF !
Final Report IWT 2012.
ld !
ikke
w
e
Ing
IFM O3D2xx.
1. Remove weak defined
pixels.
2. Find the z –discontinuity
3. Look for vertical parts with
forward oriented normals
4. Inspect collineraity
5. Use geometrical laws
in order to find
x, y, z and b.
7.3.1. Connect camera: O3D2xx.dll and O3D2xx.h should be present .
% Camera connect, ToF !
July 2012.
% Wim Abbeloos & Luc Mertens:
Industrial VisionLab.
if exist(cam) == 0
% If 'open camera' then 'close camera'.
for c = 1:3
% Disconnect the camera.
answer = calllib('O3D2xxCamera','O3D2XXDisconnect',1);
if answer == 0 disp('Camera disconnected'); break;
else disp(strcat('Failed to disconnect, attempt no',num2str(c)));pause(0.5);
end; end; end;
% Start live camera:
dllname = 'O3D2xxCamera'; inttime = 500; % Driver & camera integration time.
headername = 'O3D2xxCameraMatlab.h'; IP = '192.168.0.69'; XMLPort = uint32(8080);
hwnd = libpointer('uint32Ptr',0); FWversion = libpointer('stringPtr','xxxxxx'); SensorType =
libpointer( 'stringPtr', 'xxxxxxxxxx' );
if ~libisloaded(dllname) loadlibrary(dllname,headername); end; % Load library.
for c = 1:3
% Connect the camera.
[answer,hwnd,IP,FWversion,SensorType] = ...
calllib(dllname,'O3D2XXConnect',hwnd,IP,XMLPort,FWversion,SensorType);
if answer == 0 disp('Camera Connected');
calllib(dllname,'O3D2XXPerformHeartBeat'); break;
else calllib(dllname,'O3D2XXDisconnect',1);
disp(strcat('Failed to connect, attempt no', num2str(c)));
if c == 3 error('Failed to connect'); end; end; end;
% Software trigger type:
% 1 = positive edge, 2 = negative edge, 3 = free running, 4 = software based.
calllib(dllname,'O3D2XXSetTrigger',4);
head = libpointer('int32Ptr',zeros(1,21*4));
% Init variables.
Industrieel VisieLab:
[email protected] and
[email protected]
84
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
SIZE = uint32(64*50*4); dat = libpointer('uint8Ptr',zeros(1,SIZE));
TCPport = int32(50002);
cam = struct('dllname',dllname,'dat',dat,'SIZE',SIZE,'head',head,'TCPport',TCPport);
% Set front end data
% 1. Modulation Frequency and wave length code [0,1,2,3]; default = 0;
% 2. Single or double sampling corresponding with normal/high dynamic.
% 3. Illumination mode: 0 = off, 1 = A on, 2 = B on, 3 = A and B on.
% 4. First integration time [µs] (single sampling mode), 1-5000; default=2000.
% 5. Second integration time [µs] (double sampling mode), 1-5000.
% 6. Delay time [ms] default = 141.
setfrontend = libpointer('int32Ptr',[0,0,3,1,inttime,0]);
calllib(dllname,'O3D2XXSetFrontendData',setfrontend);
%%% END camera start up .
calllib(cam.dllname,'O3D2XXTriggerImage');
% Get new frame.
[answer,data,header] = calllib(cam.dllname,'O3D2XXGetImageData',...
int8('d'),cam.dat,cam.SIZE,cam.head,cam.TCPport);
7.3.2. Image analysis and measuring results
% Proof of concept, ToF !
July 2012.
% Luc Mertens & Wim Abbeloos:
Industrial VisionLab.
% Usul Mesut (student).
%
% Program: ifm_palette_GP.m
%
% Find the palettes visible in a ToF image. Palettes are near the floor (0-140 mm).
% Palettes have 2 predescribed holes. The following data are looked for:
% 1. Find the centre of gravity (xz, yz = Floor - 90 mm. , zz) relative to the AGV.
% 2. Find the orientation -90° < alfa < 90 relative to the AGV.
% Since the palettes must be placed on exact positions (+/- 1.5 cm) they must
% be picked up as correct as possible.
close all; clear all; home; rep = 'replicate'; ku = 0.965; kv = 1.0;
G = fspecial('gaussian',11,2.2); O2 = ones(2); O3 = ones(3); O4 = ones(4);
T = 20; D_left = 0; D_right = 0;
% T is the maximum # blobs.
Co = ones(3); xz = 0; zz = 0; alfa = 0;
% Co is a collinearity check matrix.
f = 80; f4 = 4*f; H1 = 50;
% Focal length + Rows of interest.
ThresCollin = 0.05;
% Threshold on the collinearity calculation.
ThresDist = 0.05; % Threshold on the square distance between the frontal blobs.
MatchFound = false;
% Result of the analysis.
load('ifm6.mat');
% [D L] = AcquireIFM(200); % With some intergration time, acquire D and L image.
t0 = cputime;
% D = D(end:-1:1,:); L = L(end:-1:1,:);
D = rot90(D,1); L = rot90(L,1);
% Rotation if necessary.
D = D(2:end-1,2:end-1); L = L(2:end-1,2:end-1);
% Never trust border pixels.
bwOUT = L < 0; NN = sum(bwOUT(:));
%%% Some points are out of control...
if NN > 0 for t = 1:5
bwE = imerode(bwOUT,O2); bwD = imdilate(bwOUT,O3);
OUTER = bwD & ~bwOUT; FF = find(OUTER==true);
INNER = bwOUT & ~bwE; ff = find(INNER==true);
for g = 1:length(ff) FFg = abs(FF-ff(g)); [mm gg] = min(FFg);
D(ff(g)) = D(FF(gg)); end;
figure(20); imshow(kron(bwOUT,O2)); title('Out of control');
xlabel(cat(2,'# OUT of control = ', num2str(length(ff)))); pause(0.5);
Industrieel VisieLab:
[email protected] and
[email protected]
85
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
bwOUT = bwE; end; end;
D(find(D > 3.5 | D < 0.4)) = 3.5; D = kron(D,O4); L = kron(L,O4);
D = imfilter(D,G,rep); LD = L./D;
% Confidence image.
[I J] = size(D); I2 = I/2; J2 = J/2; ff4 = f4*f4; % f4 is the adapted focal length.
u = ku*([0.5:J-0.5]-J2); uu = u.*u;
% column pixel values u = -J/2:J/2 .
v = kv*([0.5:I-0.5]-I2); vv = v.*v;
% row pixel values
v = -I/2:I/2 .
U = kron(u,ones(I,1)); UU = kron(uu,ones(I,1));
V = kron(v',ones(1,J)); VV = kron(vv',ones(1,J));
d = sqrt(VV+UU + ff4);
% Pythagoras. Internal camera distances --> LUT.
Dd = D./d;
% Distance ratios for world points.
x = U.*Dd;
% Camera x-coordinates.
y = V.*Dd;
% Camera y-coordinates. Downwards oriented !!
z = f4*Dd;
% Camera z-coordinates.
x = imfilter(x,G,rep); y = imfilter(y,G,rep); z = imfilter(z,G,rep);
xL = x(H1:end,:); yL = y(H1:end,:); zL = z(H1:end,:); IL = I-H1+1;
DL =sqrt(xL.*xL + yL.*yL + zL.*zL);
% Improved distance image.
[gXr gXc] = gradient(xL); [gYr gYc] = gradient(yL); [gZr gZc] = gradient(zL);
v1 = cat(3,gXr,gYr,gZr); v2 = cat(3,gXc,gYc,gZc); v = cross(v1,v2);
normV = sqrt(sum(v.*v, 3)); normV = repmat(normV,[ 1 1 3 ]);
normal = v./normV;
% Vectors are normalized as v = v/|v| .
nXL = normal(:,:,1); nYL = normal(:,:,2); nZL = normal(:,:,3);
% Find the floor: take care for the reflections of the plastic foil --> use medians.
i = I2/2; while median(y(i,J2-15:J2+15))<0 i=i+1; end; H = i; % Camera horizon.
i = H+50; while median(z(i,J2-15:J2+15)) < median(z(i+3,J2-15:J2+15)) + 0.10; i = i-1; end;
i = i-52; while median(nYL(i,J2-15:J2+15)) > 0.95 i = i-1; end; i = i+50;
Floor=median(y(i,J2-15:J2+15)); yz = Floor - 0.07; JJ =[]; SP=[]; mX=[]; mZ=[];
bwLP = ( yL < Floor ) & ( yL > Floor - 0.150 ); % Region near the floor.
bwROI = bwLP & nYL<0.5 & nYL>-0.1 & nZL>cos(pi/4); % Horizontal oriented.
bwROI = imdilate(bwROI,ones(1,5)); bwROI = imerode(bwROI,ones(1,5));
BWroi = bwROI;
% A copy of ROI.
sumBW = sum(bwROI); FF = find(sumBW>0); LenFF = length(FF);
if LenFF > 5 for j = FF, if sumBW(j) < 10 bwROI(:,j) = false; end; end; end;
sumBW = sum(bwROI); FF = find(sumBW>0); LenFF = length(FF);
if LenFF > 5 for j = FF
% Dealing with perception errors.
bwj = bwROI(:,j); zj = z(:,j); ff = find(bwj) == true; mm = min(zj(ff));
bwj( zj(ff) > mm+0.03) = false; bwROI(:,j) = bwj; end; end;
FF = find(bwROI == true); DL(FF) = 0.5; nYL(FF) = 1; % Proof the correct ROI.
[Labeled, count]=bwlabel(bwROI,4);
% Label the connected regions.
LABEL = Labeled;
% A copy of 'Labeled'.
for t = 1:count
FF = find(LABEL == t); if length(FF) < 20 bwROI(FF) = false; end; end;
[Labeled, count]=bwlabel(bwROI,4);
% Label the connected regions.
if count > 2 & count < 30
% At least 3 and no more than 10 blobs allowed !
for i=1:count,
% sp indicate: 'sub pixel level'.
bw = (Labeled==i); FF = find(sum(bw) > 0);
% Bounded box.
sp = mean(FF); jj = round(sp); JJ = cat(1,JJ,jj); SP = cat(1,SP,sp);
nZL(end-10:end,jj) = 1; ii = find(bw(:,jj) == true);
mX = cat(1, mX, mean(xL(ii,jj))); mZ = cat(1, mZ, mean(zL(ii,jj))); end;
DET = 100000;
for t = 1:count-2
Co = cat(2,mX(t:t+2),mZ(t:t+2),ones(3,1));
Det = abs(det(Co));
if Det < DET DET = Det; T = t; end;
end; end;
if T > 1 for t = 1:T-1, Labeled(find(Labeled==t)) = 0; end; end;
if count > T+2 for t = T+3:count, Labeled(find(Labeled==t)) = 0; end; end;
Industrieel VisieLab:
[email protected] and
[email protected]
86
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Co = cat(2,mX(T:T+2),mZ(T:T+2),ones(3,1)); Det = det(Co)
dX = Co(3,1)-Co(1,1); dZ = Co(3,2)-Co(1,2); btan13 = 180*atan2(dX,dZ)/pi
if Det < ThresCollin
% Collinearity will make the determinant = 0.
xz = Co(2,1); zz = Co(2,2); yz = yz;
dX12 = xz - Co(1,1); dZ12 = zz - Co(1,2); dX23 = Co(3,1) - xz; dZ23 = Co(3,2) - zz;
btan12 = 180*atan2(dX12,dZ12)/pi
btan23 = 180*atan2(dX23,dZ23)/pi
D_left = sqrt(dX12*dX12 + dZ12*dZ12); D_right = sqrt(dX23*dX23 + dZ23*dZ23);
if abs(btan12 - btan23)<5 & abs(btan13 - btan23)<5 & abs(btan13 - btan12)<5
alfa = sum(btan12 + btan23 + btan13)/3;
else alfa = btan13;
disp('Angle deviations from support to support bigger than 5 degrees'); end;
if abs(D_left-D_right) < ThresDist MatchFound = true; end;
else disp('Distances left and right are NOT EQUAL.'); end;
t0 = cputime-t0
Labeled(:,J2) = count+2;
Co = Co
D_left = D_left
D_right = D_right
xz = xz
yz = yz
zz = zz
alfa = alfa
Floor = Floor
MatchFound = MatchFound
T=T
SP = SP
figure(1);
subplot(231); imshow(D,[1.400 2.100]); title('Distances.');
xlabel('imshow(D,[1.400 2.100])');
subplot(232); imshow(L,[]); title('Luminances');
xlabel('Out of control points removed!');
subplot(233); imshow(LD,[]); title('Confidence values.');
subplot(234); imshow(x,[]); title('x-values');
subplot(235); imshow(y,[]); title('y-values');
subplot(236); imshow(z,[]); title('z-values');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
figure(2);
subplot(221); imshow(DL,[1.300 2.200]); title('Improved distances.');
xlabel('imshow(DL,[1300 2200])');
subplot(222); imshow(LD,[ ]); title('Confidence image.');
subplot(223); imshow(nYL,[ ]); title('nYL-values');
xlabel('imshow(nYL,[ ])');
subplot(224); imshow(nZL,[]); title('nZL-values');
xlabel('imshow(nZL,[])');
figure(3);
subplot(221); imshow(D,[1.000 2.500]); title('Original ToF image.')
xlabel('White spots indicate the ROI.')
subplot(222); imshow(L,[]); title('Intensity image.');
subplot(223); imshow(BWroi); title('From Floor+10 -> Floor + 130 mm.');
xlabel('Initial blobs encountered.');
subplot(224); imshow(bwROI); xlabel('Filtered blobs.');
title(cat(2,'MatchFound = ',num2str(MatchFound)));
figure(4); imshow(Labeled,[0 count]); title('Filtered labels');
xlabel(cat(2,'x = ',num2str(xz),' y = ',num2str(yz),' z = ',num2str(zz),...
Industrieel VisieLab:
[email protected] and
[email protected]
87
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
' b = ',num2str(alfa),'°'));
figure(5); plot3(xL,zL,-yL,'k.','MarkerSize',1); grid on;
xlabel('Lower x part'); ylabel('Lower z part'); zlabel('Lower y part');
Industrieel VisieLab:
[email protected] and
[email protected]
88
Association University and University Colleges Antwerp.
Industrieel VisieLab:
[email protected] and
RGBd, ToF !
Final Report IWT 2012.
[email protected]
89
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
7.4. Hero-technologies: barrel inspection
Object Handling (Robotics)
MESA camera: wide angle of view ; 144x174 pixels.
Suppose: a random set of empty beer barrels collected on a palette.
How to handle the barrels without ToF cameras: stereo vision ?
With ToF-information
this becomes an easy
task.
Look for the circular
edges of the barrels
(del2).
Convolute the inner
areas with ‘a little-bitto-small-disk’
Find the centres of
gravity.
Project the results to
the RGB image and
segment it.
uEye
% Tetra project 100191: RGBd, TOF !
July 2012.
% Luc Mertens & Wim Abbeloos:
Industrial Vision Lab.
% Stephanie Buyse & Rudi Penne.
%
% Program: barrel inspection
%
% The correspondence between a ToF and an RGB image must be used in
% order to find the exact position (x, y, z) of the barrels on a palette.
% The detailed RGB-image can also be used to evaluate the visible quality of
% the separated barrels. The segmentation is based on the ToF image.
% size(RGB) = 1280 x 1024 x 3
% size(ToF) = 64 x 50
% To do:
% 1. A 3D segmentation based on the Laplacian of the ToF image.
% 2. The correspondence ToF and RGB (one scale factor, two offset values.
% 3. Subplots(5,5,p): for every barrel one RGB region.
close all; clear all; format short; home; rep = 'replicate';
O2 = ones(2); O4 = ones(4); O6 = ones(6);
f= 79.5; f4 = 4*f; G1 = fspecial('gaussian',7,1.2);
Thres = 0.7;
% Threshold related to the convolution calculation.
Ro = 18; R1 = Ro+1; CR = false(Ro+R1,Ro+R1); Cr = CR; %'Circular matching'.
for i=-Ro+0.5:Ro-0.5, ii = i*i;
Industrieel VisieLab:
[email protected] and
[email protected]
90
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
for j=-Ro+0.5:Ro-0.5, r2 = ii+j*j; r = sqrt(r2);
if r <= Ro CR(round(i+R1),round(j+R1)) = true;
if r >= Ro-1 Cr(round(i+R1),round(j+R1)) = true; end; end; end; end;
% figure(11); subplot(121); imshow(CR); title('Inspection Disk');
% subplot(122); imshow(Cr); title('Border of the Inspection Disk');pause(0.2);
load('RGBd_Hero_Vat21.mat');
% Vat1, Vat21, Vat31,... Vat91, Vat101.
% [D L] = AcquireIFM(200); % With some intergration time, acquire D and L image.
%%%%%
%
Acquire RGB image if live camera --> 'rgbimg' matrix .
%%%%%
t0 = cputime; im = rgbimg(230:951,240:985,:); LD = L./D;
% ToF confidence.
Gray = rgb2gray(im); [Ig Jg] = size(Gray); Ig2 = round(Ig/2); Jg2 = round(Jg/2);
D = rot90(D,1); L = rot90(L,1); D = D(:,7:59); L = L(:,7:59); LD = L./D;
bwOUT = D < 0; % OUT = find(bwOUT == true);
for t = 1:5
bwE = imerode(bwOUT,O2); bwD = imdilate(bwOUT,O2);
OUTER = bwD & ~bwOUT; FF = find(OUTER==true); medianOUT = median(D(FF));
INNER = bwOUT & ~bwE; ff = find(INNER==true); D(ff) = medianOUT;
%
figure(20); imshow(bwOUT); title('Out of control');
%
xlabel(cat(2,'# OUT of control = ', num2str(length(ff)))); pause(0.5);
%
ylabel(cat(2,'Interpolated value = ', num2str(medianOUT))); pause(2)
bwOUT = bwE; end;
D = kron(D,O4); L = kron(L,O4); [It Jt] = size(D); It2 = It/2; Jt2 = Jt/2;
D = round(1000*D); FF = find(D < 1500); D(FF) = 1500 + 100*rand;
%figure(12); hist(D(:)); title('Histogram of distances D.');
D = imfilter(D,G1,rep);
ff = f4*f4; u = [0.5:Jt-0.5]-Jt2; uu = u.*u; v = [0.5:It-0.5]-It2; vv = v.*v;
U = kron(u,ones(It,1)); UU = kron(uu,ones(It,1));
V = kron(v',ones(1,Jt)); VV = kron(vv',ones(1,Jt)); d = sqrt(UU+VV+ff);
Dd = D./d; z = f4*Dd;
% Camera z-coordinates.
del2Z = del2(z); bwROI = del2Z > -1 & z < 1900 ;
se = strel('disk',4); bwROI = imdilate(bwROI,se);
se = strel('disk',10); bwROI = imerode(bwROI,se); bwROI = imerode(bwROI,se);
[labeled count] = bwlabel(bwROI,4);
bwC = false(size(bwROI)); bwC1 = bwC;
for cc = 1:count
bw = (labeled == cc); FF = find(bw == true); Len = length(FF);
FFi = find(sum(bw') > 0); iF = round(mean(FFi));
FFj = find(sum(bw) > 0); jF = round(mean(FFj));
bwC(iF:iF,jF:jF) = true; end;
p = 0; Locations = []
for i = R1:It-Ro, for j = R1:Jt-Ro,
if bwC(i,j) == true
bwC1(i-Ro:i+Ro,j-Ro:j+Ro) = Cr;
bwROI(i-10:i+10,j) = true; bwROI(i,j-10:j+10) = true;
Locations = cat(1,Locations, [i j])
end; end; end;
%figure(13);
%subplot(121); imshow(del2Z>-0.5); title('del2>-0.5');
%subplot(122); imshow(bwROI);
title('Expected centres of gravity')
scale = (Jg+50)/Jt; Positions = [];
for i = 1:It, for j = 1:Jt
if bwC(i,j)==true
u = i-0.5-It2; v = j-0.5-It2;
d = sqrt(u*u+v*v+ff); Dd = D(i,j)/d;
Positions = cat(1,Positions, [ v*Dd u*Dd 2370 - f4*Dd]);
ii = round(scale*i-20); jj = round(scale*j-30) ;
Gray(ii-1:ii+1,jj-1:jj+1) = 255; end; end; end;
Positions = round(Positions);
Industrieel VisieLab:
[email protected] and
[email protected]
91
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
t0 = cputime - t0;
figure(1);
subplot(221); imshow(D,[1700 1900]); title('Distances: filtered data');
subplot(222); imshow(LD,[]);
title('ToF Confidence L./D .');
subplot(223); imshow(im,[]);
title('RGB image');
subplot(224); imshow(Gray,[]);
title('Gray image');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
figure(2);
subplot(221); imshow(D,[1700 1900]); title('D, [1700 1900]');
subplot(222); imshow(Gray,[]);
title('Gray image');
subplot(223); imshow(z,[1700 2100]); title('z-values, [1700 2100]');
subplot(224); imshow(del2Z,[-1 5]);
title('Laplacian(z),[-1 5]');
xlabel(cat(2,'CPUtime = ',num2str(t0)));
figure(3);
subplot(121); imshow(Gray,[]);
title('Gray image.');
subplot(122); imshow(im,[]);
title('RGB image.');
Len = length(Locations); im1 = im; im1(:,Jg2-1:Jg2+1,1) = 255;
im1 = im; im1(:,Jg2-1:Jg2+1,1) = 255; im1(Ig2-1:Ig2+1,:,3) = 255;
if Len < 17 q = round(23*scale)
for t = 1:Len, i=round(Locations(t,1)*scale-20); j=round(Locations(t,2)*scale-30);
Object = im(i-q:i+q, j-q:j+q,:); figure(100+t);
subplot(121); imshow(Object); pause(0.2);
xlabel(num2str(Positions(t,:)));
ylabel(cat(2,'Object # ',num2str(t)));
subplot(122); imshow(im1); xlabel('Palette'); pause(0.5); end;
figure(116); imshow(im); xlabel('Palette');
else disp('To much objects') ; end;
Industrieel VisieLab:
[email protected] and
[email protected]
92
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
x
y
Industrieel VisieLab:
[email protected] and
[email protected]
93
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
8. Gesture based interfacing (DepthSense 311)
SoftKinetic
DepthSense 311
RGBd,
ToF
The future has begun
Confidence Map L/D
160 x 120 pix.
Industrieel VisieLab:
Anno 2011
Depth Map (ToF)
160 x 120 pix.
[email protected] and
Colour Map
640 x 480 pix.
[email protected]
94
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Algorithms useful for Time of Flight cameras: Wim Abbeloos.
The next set of algorithms were developed during the project. We keep them as a collection since
they can inspire programmers at a given moment. To keep a good overview most of these
functions are directly present in the main program.
Nevertheless in combination with toolboxes for the SwissRanger cameras, toolboxes for the Fotonic
cameras, the ToF-functionalities in Halcon, Matlab, C++ and OpenCV they give a practical
solution for typical problems of Material Handling (Robotics) and Navigation (AGVs and
Wheelchairs).
function alg = algorithms()
alg.startcamera = @ startcamera;
alg.getframe
= @ getframe;
alg.stopcamera
= @ stopcamera;
alg.calcnormal
= @ calcnormal;
alg.calcavgnormal = @ calcavgnormal;
alg.displaynormal = @ displaynormal;
alg.D2cam
= @ D2cam;
alg.z2cam
= @ z2cam;
alg.cam2vehicle = @ cam2vehicle;
alg.view2D
= @ view2D;
alg.view3D
= @ view3D;
alg.startmotor
= @ startmotor;
alg.stopmotor
= @ stopmotor;
alg.motorcmd
= @ motorcmd;
% Start / acquire image / stop .
% Calculate normal vector.
% Calculate average normal vector.
% Display normal.
% From distances to camera x, y, z.
% From camera z to camera x, y,D.
% From camera to AGV-world.
% Common 2D-plot.
% Common 3D-plot.
% Start/ command / stop motor.
function cam = startcamera( inttime )
dllname = 'O3D2xxCamera'; headername = 'O3D2xxCameraMatlab.h';
IP
= '192.168.0.69'; XMLPort = uint32( 8080 );
hwnd
= libpointer( 'uint32Ptr', 0 );
FWversion = libpointer( 'stringPtr', 'xxxxxx' );
SensorType = libpointer( 'stringPtr', 'xxxxxxxxxx' );
if ~libisloaded( dllname ) loadlibrary( dllname, headername ); end;
for c = 1:3
% Try to connect camera.
[ answer, hwnd, IP, FWversion, SensorType ] = calllib( dllname,…
'O3D2XXConnect', hwnd, IP, XMLPort, FWversion, SensorType );
if answer == 0 disp( 'Camera Connected' );
calllib( dllname, 'O3D2XXPerformHeartBeat' ); break;
else calllib( dllname, 'O3D2XXDisconnect', 1 );
disp( strcat( 'Failed to connect, attempt no', num2str(c) ) );
if ( c == 3 ) error( 'Failed to connect' ); end; end; end;
% Software trigger
% Trigger type: 1 for pos. edge, 2 for neg. edge, 3 for free running and 4
% for software trigger
calllib( dllname, 'O3D2XXSetTrigger', 4 );
head = libpointer( 'int32Ptr', zeros( 1, 21 * 4 ) );
SIZE = uint32( 64 * 50 * 4 );
dat
= libpointer( 'uint8Ptr', zeros( 1, SIZE ) ); TCPport = int32( 50002 );
cam
= struct( 'dllname', dllname, 'dat', dat, 'SIZE', SIZE, 'head', head,…
'TCPport', TCPport);
% Set frontend data
% 3 -> 6.5m, 1 -> 7.4, 0 -> 6.5
% 1. ModulationFrequency [0,1,2,3] default = 0
%
6.51m 7.38m 7.40m 45m
%
Modulation Frequency 0 (23MHz) 1 (20.4MHz) 2 (20.6MHz)
% 2. Single or double sampling normal/high dynamic
Industrieel VisieLab:
[email protected] and
[email protected]
95
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% 3. Illumode: 0 = turn all Illuminations off, 1 = Illumination a on,
2 = Illumination b off, 3 = a and b on.
% 4. First integration time [us] (single sampling mode), 1-5000, default 2000
% 5. Second integration time [us] (double sampling mode), 1-5000
% 6. Delay time [ms] default = 141
setfrontend = libpointer( 'int32Ptr', [1, 0, 3, inttime, inttime, 0] );
calllib( dllname, 'O3D2XXSetFrontendData', setfrontend );
function frame = getframe( cam )
calllib( cam.dllname, 'O3D2XXTriggerImage' );
datmode = int8( 'd' );
[ answer, data, header ] = calllib( cam.dllname, 'O3D2XXGetImageData',…
datmode, cam.dat, cam.SIZE, cam.head, cam.TCPport );
frame.D = double( typecast( data, 'single' ) );
frame.D = reshape( frame.D, 64, 50 );
datmode = int8( 'i' );
[ answer, data, header ] = calllib( cam.dllname, 'O3D2XXGetImageData', ...
datmode, cam.dat, cam.SIZE, cam.head, cam.TCPport );
frame.L = double( typecast( data, 'single' ) );
frame.L = reshape( frame.L, 64, 50 );
Head = double(typecast(header(1:21),'single'));
frame.time = Head(12:13);
function stopcamera()
dllname = 'O3D2xxCamera';
for c = 1:3
answer = calllib( dllname, 'O3D2XXDisconnect', 1 );
if answer == 0 disp( 'Camera disconnected' ); break;
else
disp( strcat( 'Failed to disconnect, attempt no', num2str(c) ) );
pause(0.5); end; end;
if libisloaded( dllname ) unloadlibrary( dllname ); end;
function normal = calcnormal( x, y, z, filtersize, fdir )
% fdir: filter direction
% Define filters
if fdir == 1 f1 = zeros( filtersize ); f1(1) = 1; f1(end) = -1;
f2 = fliplr( f1 );
else f1 = zeros( 1, filtersize ); f1(1) = 1; f1(end) = -1; f2 = f1'; end;
x1 = imfilter( x, f1 );
x2 = imfilter( x, f2 );
% Filter image.
y1 = imfilter( y, f1 );
y2 = imfilter( y, f2 );
z1 = imfilter( z, f1 );
z2 = imfilter( z, f2 );
v1 = cat( 3, x1, y1, z1 ); % Create vector1, vector2 and Normal vector.
v2 = cat( 3, x2, y2, z2 ); v = cross( v1, v2 );
SumV = sqrt( sum( v.*v, 3 ) );
% Normalize.
SumV = repmat( SumV, [ 1 1 3 ] ); normal = v ./ SumV;
function normal = calcavgnormal( x, y, z, filtersize )
normal1 = calcnormal( x, y, z, filtersize, 0 );
normal2 = calcnormal( x, y, z, filtersize, 1 );
mnorm = ( normal1 + normal2 ) / 2;
SumV = sqrt( sum( mnorm.*mnorm, 3 ) );
% Normalize.
SumV = repmat( SumV, [ 1 1 3 ] ); normal = mnorm ./ SumV;
function N = displaynormal( normal )
N = normal / 2 + 0.5; N(:,:,3) = 1 - N( :, :, 3 );
function [x y z R phi] = D2cam( D, f )
Industrieel VisieLab:
[email protected] and
[email protected]
96
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
[I J] = size( D ); I2 = I/2; J2 = J/2;
ff = f * f; u = (1:J) - (J2+0.5); uu = u .* u;
v = (1:I) - (I2+0.5); vv = v .* v;
U = repmat( u , [I 1]); UU = repmat( uu, [I 1]);
V = repmat( v', [1 J]); VV = repmat( vv',[1 J]);
UUff = UU + ff; r = sqrt( UUff ); d = sqrt( VV + UUff );
Dd = D ./ d; R = r .* Dd; phi = atan2( U, f );
x = U .* Dd; y = -V .* Dd; z = f * Dd;
function [x y z D] = z2cam( z, f )
[J I] = size( z ); I2 = I/2; J2 =J/2;
% Calculate pixel coordinates
x = repmat( ( (1:I) - (I2+0.5) ), J, 1 ) .* (z / f);
y = repmat( ( (J2+0.5) - (1:J)' ), 1, I ) .* (z / f);
D = sqrt( x .^ 2 + y .^ 2 + z .^ 2 );
function [x y z] = cam2vehicle( x, y, z, ca )
% ca: Camera Angle to horizon, negative for looking down
zt = z .* cosd(ca) - y.* sind(ca); yt = z .* sind(ca) + y.* cosd(ca);
z = zt; y = yt;
function view2D( x, z )
plot( x, z, 'ko', 'MarkerSize', 2 ); set( gca, 'DataAspectRatio', [1 1 1]); axis off;
function view3D( x, y, z )
plot3(x,y,z,'ko','MarkerSize',2); set(gca,'DataAspectRatio',[1 1 1]); axis off;
function startmotor()
global motor;
delete( instrfind ); % Start serial communication
motor = serial( 'COM7', 'BaudRate', 9600, 'Parity', 'none', 'DataBits', 8, …
'StopBits', 2, 'Timeout', 0.2 );
fopen( motor );
motorcmd( 'disabletimeout' ); motorcmd( 'enablereg' ); motorcmd( 'resetenc' );
motorcmd('setmode',3); motorcmd('setspeed1',0); motorcmd('setspeed2',0);
motorcmd( 'setaccel', 10 );
function stopmotor()
% Stop serial communication.
global motor;
motorcmd('setmode',3); motorcmd('setspeed1',0); motorcmd('setspeed2',0);
motorcmd( 'enabletimeout' );
fclose( motor ); delete( motor ); clear( 'motor' );
function varargout = motorcmd( cmd, varargin )
% MOTOR COMMANDS.
global motor;
if ~ischar( cmd ) error( 'Second argument must be a command string' ); end;
switch cmd
case 'getspeed1'
fwrite(motor,[0 33],'int8'); % returns the current requested speed of motor 1
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getspeed2'
fwrite(motor,[0 34],'int8'); % returns the current requested speed of motor 2
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getenc1'
% Motor 1.
fwrite(motor,[0 35],'uint8');
% 4 bytes returned high byte first (signed).
val = fread( motor, 4, 'uint8' );
val2 = uint32( bitcmp( uint8(val) ) );
val3 = bitshift(val2(1),24)+bitshift(val2(1),16)+bitshift(val2(3),8)+val2(4);
varargout(1) = { val3 };
case 'getenc2'
% Motor 2.
fwrite(motor,[0 36],'uint8');
% 4 bytes returned high byte first (signed).
val = fread( motor, 4, 'uint8' );
Industrieel VisieLab:
[email protected] and
[email protected]
97
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
val2 = uint32( bitcmp( uint8(val) ) );
val3 = bitshift(val2(1),24)+bitshift(val2(1),16)+bitshift(val2(3),8)+val2(4);
varargout(1) = { val3 };
case 'getencs'
fwrite(motor,[0 37],'uint8'); % Returns 8 bytes. Encoder1/encoder2 count.
varargout(1) = { fread( motor, 8, 'uint8' ) };
case 'getvolts'
fwrite( motor, [0 38], 'uint8' );
% Returns the input battery voltage level.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent1'
fwrite( motor, [0 39], 'uint8' );
% Returns the current drawn by motor 1.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent2'
fwrite( motor, [0 40], 'uint8' );
% returns the current drawn by motor 2.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getversion'
fwrite( motor, [0 41], 'uint8' );
% Returns the software version.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getaccel'
fwrite( motor, [0 42], 'uint8' );
% Returns the current acceleration level.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getmode'
fwrite( motor, [0 43], 'uint8' );
% Returns the currently selected mode.
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getVI'
fwrite( motor, [0 44], 'uint8' );
% Returns Volts, current1 and current2.
varargout(1) = { fread( motor, 1, 'uint8' ) }; % Battery voltage
varargout(2) = { fread( motor, 1, 'uint8' ) }; % Current motor 1
varargout(3) = { fread( motor, 1, 'uint8' ) }; % Current motor 2
case 'setspeed1'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
speed = cell2mat(varargin(1));
fwrite( motor, [0 49 speed], 'int8' ); % set new speed1
case 'setspeed2'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
speed = cell2mat(varargin(1));
fwrite( motor, [0 50 speed], 'int8' ); % set new speed2
case 'setaccel'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
accel = cell2mat(varargin(1));
fwrite( motor, [0 51 accel], 'uint8' ); % set new acceleration
case 'setmode'
if nargin ~= 2 error( 'Incorrect number of input arguments' ); end;
mode = cell2mat(varargin(1));
fwrite( motor, [0 52 mode], 'uint8' );
% Set the mode.
case 'resetenc'
fwrite( motor, [0 53], 'uint8' );
% Zero both of the encoder counts.
case 'disablereg'
fwrite(motor,[0 54],'uint8'); Power output not changed by encoder feedback
case 'enablereg'
fwrite(motor,[0 55],'uint8'); Power output is regulated by encoder feedback
case 'disabletimeout'
fwrite( motor, [0 56], 'uint8' ); % Continuous output if no-regular ommands.
case 'enabletimeout'
fwrite( motor, [0 57], 'uint8' );
% Watch dog, 2 seconds.
otherwise
error( 'Incorrect command' );
end;
Industrieel VisieLab:
[email protected] and
[email protected]
98
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Part 2 (pages 99 -> 170)
Deel 2 van het verslag handelt vooral in op de wijze waarop allerlei ToF-camera’s in Matlab en in
Halcon aangesproken kunnen worden. Een aantal programma’s werden meer als een totale
applicatie benaderd, zodat software en hardware aspecten meer inpliciet aan bod zullen komen.
Inhoud van deel 2.
1.
IFM O3D2xx cameras ( www.ifm-electronic.com )................................................................................ 100
1.1.
Camera connectie met behulp van de bijgeleverde files. ................................................................. 100
1.2.
Camera connection based on Java TCP IP ......................................................................................... 105
2.
MESA Swiss Ranger SR4000 ( www.mesa.com ) ................................................................................... 108
3.
Fotonic Z-70 ( www.fotonic.com ) ...................................................................................................... 110
4.
DepthSense 311 ( www.Softkinetic.com ) ............................................................................................. 112
5.
uEye RGB camera ( www.IDS-imaging.com )......................................................................................... 114
6.
De motoren van de AGV. ....................................................................................................................... 115
7.
Wheelchair navigation (Rolstoel Permobil). .......................................................................................... 121
8.
Wall segmentation in the outdoor application of Vision & Robotics. ................................................... 122
9.
Path planning for the indoor application at Vision & Robotics. ............................................................ 125
Free navigation in a world with a known map. ............................................................................................. 125
9.1.
The Brushfire algorithm ( Principles of Robot Motion: Howie Choset,… ) ........................................ 125
9.2.
The Wave Front Algorithm ................................................................................................................ 126
9.3.
Combined Algorithm: ( Wave Front and Distance Repulsion ). ......................................................... 127
10.
Localisation ........................................................................................................................................ 128
10.1.
Punten ........................................................................................................................................... 128
10.2.
Muren ......................................................................................... Fout! Bladwijzer niet gedefinieerd.
11.
AGV sturing ........................................................................................................................................ 136
12.
Camera calibrations: Color and TOF camera. .................................................................................. 137
13.
Halcon ( Industrial Vision Package of MVTec (www.mvtec.com )..................................................... 142
13.1.
Halcon in combination with IFM O3D201 (ifm-electronic) ........................................................... 142
13.2.
Halcon in combination with Mesa SR4000 ( www.mesa.com ) .................................................... 147
13.3.
Halcon used on an AGV in combination with a MESA SR4000. .................................................... 149
14.
Vision & Robotics 2012 demo. Fotonic camera................................................................................ 150
Industrieel VisieLab:
[email protected] and
[email protected]
99
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
1. IFM O3D2xx cameras ( www.ifm-electronic.com )
1.1.






Camera connectie met behulp van de bijgeleverde files.
We maken gebruik van de bijgeleverde functiebibliotheek voor alle communicatie tussen camera en
computer. Er is enkel een 32 bit dll bestand, dit is dus enkel mogelijk voor 32 bit applicaties (niet
mogelijk in 64-bit matlab!). De bijgevoegde header bestanden (met .h extensie ) dienen ook in
dezelfde directory aanwezig te zijn.
Er werden enkele wijzigingen in de header bestanden aangebracht om de compatibiliteit met de oudere
MATLAB versies te verzekeren.
Installeer de bijgevoegde software.
Voor computers onder toezicht dient een nieuwe regel aan de firewall settings te worden toegevoegd om
de applicaties toe te laten me de camera te communiceren.
Gebruik de bijgevoegde software om de netwerkparameters van de camera te achterhalen.
( Het IP-adres is standaard 192.168.0.69, maar kan gewijzigd zijn). (De netwerkparameters zijn ook
rechtstreeks op de camera op te vragen). Na wijziging dient de camera opnieuw te worden opgestart.
Gebruik de bijgevoegde software om de camera terug om te schakelen naar fabrieksinstellingen voor
verder gebruik.
Beschrijving van de ‘frontend-data’:
Setting front-end data
1. Modulation Frequency
Parameter
Value
0
Frequency
(MHz)
23
Max.
Range (m)
6.5172
1
20.4
7.3862
2
20.6
7.4059
3
Multiple
6.51
4
Multiple
45
Remarks


Default
Points outside of range will be
measured at distance with
equivalent phase angle in range.
(eg. 7.51m as 1m)
Points outside of range will be
measured at distance with
equivalent phase angle in range.
(eg. 8.39m as 1m)
 Only works when in double
sampling mode. In single
sampling mode returns -2 ( bug?
)
 Points outside of range will be
measured at distance with
equivalent phase angle in range.
(eg. 8.41m as 1m)
Points outside of range will be set
to -2
Only works when in double sampling
mode. In single sampling mode
returns -2 ( bug? )
2. Sampling mode
Parameter Value
0
1
Description
Single Sampling ( Use 1 integration time )
Double Sampling ( Use 2 integration times )
3. Illumination mode
Parameter Value
0
Industrieel VisieLab:
Description
Turn all illumination off
[email protected] and
[email protected]
100
Association University and University Colleges Antwerp.
1
2
3
RGBd, ToF !
Final Report IWT 2012.
Illumination a on
Illumination b off
Illumination a and b on ( recommended )
4. First integration time:
Minimum: 0 µs
Maximum: 5000 µs
Default: 125 µs.
5. Second integration time:
Minimum: 0 µs
Maximum: 5000 µs
Default: 200 µs.
6. Delay time (ms):
Default: 141 ms
Remark:
Underexposed pixels are set to -2, overexposed pixels are set to -1. Out-ofrange pixels are set to -2 (only) when using Modulation Frequency 3.
function IFM_dll_all3()
% Prepare new session
clear all; close all; clc;
% Declare global variables
global D L xc yc zc e f g frame;
% Camera communication parameters
cam.ip
= '192.168.0.71';
cam.xmlPort
= 8080;
cam.tcpPort
= 50002;
% Camera settings
cam.trigger
cam.averageDetermination
cam.meanFilter
cam.medianFilter
=
=
=
=
4;
1;
0;
0;
% Camera front-end data
cam.modulationFrequency
cam.samplingMode
cam.illuminationMode
cam.shortIntegrationTime
cam.longIntegrationTime
cam.delayTime
=
=
=
=
=
=
1;
0;
3;
300;
300;
141;
% Start camera
ifm_start( cam );
% Get a frame
ifm_getframe();
% Stop camera
ifm_stop();
% Convert
xt = D .*
yt = D .*
zt = D .*
D to x y z from distance and camera vectors
e;
f;
g;
Industrieel VisieLab:
[email protected] and
[email protected]
101
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Calculate conversion matrix
global d;
fl = 79; I = 64; J = 50;
u = (1:J) - (J/2+0.5); U = repmat( u , [I 1]);
v = (1:I) - (I/2+0.5); V = repmat( v', [1 J]);
d = sqrt( U.^2 + V.^2 + fl.^2 );
% Calculate x, y and z from camera distances and conversion matrix
global x y z;
Dd2xyz();
% Calculate normal components from x, y, z data
global filterSize nx ny nz;
filterSize = 5;
normals();
% Display
figure(1);
figure(2);
figure(3);
figure(4);
surf( xt, yt,
surf( x, y, z
surf( xc, yc,
imshow( L, []
zt );
);
zc );
);
axis
axis
axis
axis
equal;
equal;
equal;
equal;
% Store data
save( 'test.mat', 'D', 'L', 'x', 'y', 'z', 'frame' );
function ifm_start( cam )
global ifm e f g;
% Init variables
dllname
= 'O3D2xxCamera';
headername = 'O3D2xxCameraMatlab.h';
hwnd
= libpointer( 'uint32Ptr', 0 );
FWversion = libpointer( 'stringPtr', 'xxxxxx' );
SensorType = libpointer( 'stringPtr', 'xxxxxxxxxx' );
% load library
if ~libisloaded( dllname )
loadlibrary( dllname, headername );
end
disconnectErr = calllib( 'O3D2xxCamera', 'O3D2XXDisconnect', 1 );
pause(0.2);
% Connect
for c = 1:3
[ connectErr, hwnd, cam.ip, FWversion, SensorType ] = calllib( dllname, 'O3D2XXConnect',
hwnd, cam.ip, cam.xmlPort, FWversion, SensorType );
pause(0.2);
if connectErr == 0
disp( 'Camera Connected' );
calllib( dllname, 'O3D2XXPerformHeartBeat' );
break;
else
calllib( dllname, 'O3D2XXDisconnect', 1 );
disp( strcat( 'Failed to connect, attempt no', num2str(c) ) );
if ( c == 3 )
error( 'Failed to connect' );
end
Industrieel VisieLab:
[email protected] and
[email protected]
102
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
end
end
% Set parameters
setTriggerErr
= calllib( dllname, 'O3D2XXSetTrigger', cam.trigger );
setAverageDeterminationErr = calllib( dllname, 'O3D2XXSetAverageDetermination',
cam.averageDetermination );
setMeanFilterErr
= calllib( dllname, 'O3D2XXSetMeanFilterStatus', cam.meanFilter );
setMedianFilterErr = calllib( dllname, 'O3D2XXSetMedianFilterStatus', cam.medianFilter );
% Check filters
O3D2XXFilterStatus = struct( 'MedianFilter', 2, 'MeanFilter', 2 );
[getFilterStatusErr O3D2XXFilterStatus] = calllib( dllname, 'O3D2XXGetFilterStatus',
O3D2XXFilterStatus );
% Reset front-end data
resetFrontendErr
= calllib( dllname, 'O3D2XXResetFrontend' );
% Set front-end data
head = libpointer( 'int32Ptr', zeros( 1, 21 * 4 ) );
SIZE = uint32( 64 * 50 * 4 );
dat = libpointer( 'uint8Ptr', zeros( 1, SIZE ) );
ifm = struct( 'dllname', dllname, 'dat', dat, 'SIZE', SIZE, 'head', head, 'TCPport',
int32(cam.tcpPort) );
frontend = libpointer( 'int32Ptr', [ cam.modulationFrequency, cam.samplingMode,
cam.illuminationMode,cam.shortIntegrationTime,cam.longIntegrationTime,min( cam.delayTime,141)]);
setFrontendErr = calllib( dllname, 'O3D2XXSetFrontendData', frontend );
pause(0.2);
% Trigger image
triggerErr = calllib( 'O3D2xxCamera', 'O3D2XXTriggerImage' );
% Get pixel vectors
datmode = 'efg';
for c1 = 1:length(datmode)
[ getImageDataErr, data, header ] = calllib( 'O3D2xxCamera', 'O3D2XXGetImageData',
int8(datmode(c1)), ifm.dat, ifm.SIZE, ifm.head, ifm.TCPport );
eval([datmode(c1) '= reshape( double( typecast( data, ''single'' ) ), 64, 50 );']);
end
% Get first frame
ifm_getframe();
function ifm_getframe()
global ifm D L xc yc zc header;
% Trigger next image
triggerErr = calllib( 'O3D2xxCamera', 'O3D2XXTriggerImage' );
% Read data
datmode = 'Dixyz';
varname = { 'D' 'L' 'xc' 'yc' 'zc' };
for c1 = 1:length(datmode)
[ getImageDataErr, data, theader ] = calllib( 'O3D2xxCamera', 'O3D2XXGetImageData',
int8(datmode(c1)), ifm.dat, ifm.SIZE, ifm.head, ifm.TCPport );
eval([cell2mat(varname(c1)) '= reshape(double(typecast(data,''single'')),64,50);']);
header = double( typecast( theader, 'single') );
headerinfo();
end
Industrieel VisieLab:
[email protected] and
[email protected]
103
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
function ifm_stop()
for c = 1:3
disconnectErr = calllib( 'O3D2xxCamera', 'O3D2XXDisconnect', 1 );
if disconnectErr == 0
disp( 'Camera disconnected' );
break;
else
disp( strcat( 'Failed to disconnect, attempt no', num2str(c) ) );
pause(0.5);
end
end
if libisloaded( 'O3D2xxCamera' )
unloadlibrary( 'O3D2xxCamera' );
end
function headerinfo()
global header frame;
imageTypes = {'INVALID_IMAGE', 'DISTANCE_IMAGE', 'INTERNAL_DATA_A', 'AMPLITUDE_IMAGE',
'INTERNAL_DATA_B', 'NORMAL_X_IMAGE', 'NORMAL_Y_IMAGE', ...
'NORMAL_Z_IMAGE', 'KARTESIAN_X_IMAGE', 'KARTESIAN_Y_IMAGE',
'KARTESIAN_Z_IMAGE', 'INTERNAL_DATA_C', 'SEGMENTATION_IMAGE' };
frame.dataSize
= header(1); % Size of data (bytes)
frame.headerSize
= header(2); % Size of header (bytes)
frame.imageType
= imageTypes{header(3)+1};
frame.version
= header(4);
frame.samplingMode = header(5);
frame.illuMode
= header(6);
frame.frequencyMode = header(7);
frame.unambRange
= header(8); % Unambiguous range in meters
frame.evalTime
= header(9); % Evaluation time (in ms)
frame.intTime1
= header(10); % First intergration time (in single sampling mode)
frame.intTime2
= header(11); % Second intergration time (in double sampling mode)
frame.time
= header(12) + header(13)*10.^(-6); % Timestamp (number of seconds since
camera startup)
frame.medianav
= header(14);
frame.meanav
= header(15);
frame.average
= header(16);
frame.valid
= header(17);
frame.errorCode
= header(18);
frame.temperature
= header(19);
frame.trigger
= header(20);
frame.ifmTime
= header(21);
function normals()
global x y z nx ny nz filterSize;
% Calculate normal
f1 = zeros(1, filterSize); f1(1) = 1; f1(end) =
z1 = conv2( z, f1, 'same' ); z2 = conv2( z, f2,
x1 = conv2( x, f1, 'same' ); x2 = conv2( x, f2,
y1 = conv2( y, f1, 'same' ); y2 = conv2( y, f2,
-1; f2
'same'
'same'
'same'
= f1';
);
);
);
% Calculate normal components
nx = y1.*z2-z1.*y2; ny = z1.*x2-x1.*z2; nz = x1.*y2-y1.*x2;
Industrieel VisieLab:
[email protected] and
[email protected]
104
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Normalize
n = sqrt( nx.^2 + ny.^2 + nz.^2 );
nx = nx ./ n; ny = ny ./ n; nz = nz ./ n;
function Dd2xyz()
global D d x y z;
% Convert D to x, y, z using conversion matrix
Dd = D ./ d;
x = U .* Dd;
y = -V .* Dd;
z = fl * Dd;
1.2.



Camera connection based on Java TCP IP
Er wordt gebruik gemaakt van de functie jtcp (java TCP-IP communicatie) die terug te vinden is op de
mathworks File-Exchange website. De communicatie verloopt volgens de XML-RPC standaard.
De namen van de functies en hun respectievelijke parameters zijn terug te vinden in de IFM O3D201
programmeerhandleiding.
Voor elke instelling dient een bericht opgebouwd te worden uit verschillende delen dat vervolgens
wordt samengevoegd en doorgestuurd met een ‘write’ commando. Vervolgens kan het antwoord van de
camera uitgelezen worden met een ‘read’ commando.
function ifm_xml()
% Prepare new session
clear all; close all; clc;
% Declare global variables
global cam1 D L x y z;
% Define camera parameters
cam1.HOST
= '192.168.0.69';
cam1.DATAPORT
= 50002;
cam1.XMLPORT
= int16(8080);
cam1.TrigType
= 4;
cam1.ModFreq
= 0;
cam1.SampMode
= 0;
cam1.IntTimeBig
= 1000;
cam1.IntTimeSmall
= 1000;
cam1.ifmTime = 141; % Must be atleast 141 in triggermode 4 to prevent camera damage
cam1.averaging
= 1;
cam1.median
= 0;
cam1.mean
= 0;
ifmstart();
% Open new figure
figure(1); colormap( 'gray' );
h11 = subplot(121); h1 = imagesc(L); title( 'Intensity' ); axis image; axis off;
set( h11, 'CLim', [0 20] );
h22 = subplot(122); h2 = imagesc(D); title( 'Distance' ); axis image; axis off;
set( h22, 'CLim', [0 5] );
Industrieel VisieLab:
[email protected] and
[email protected]
105
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Acquisition loop
nloop = 100;
for c1 = 1:nloop
% Get next frame
ifmgetframe();
%Display data
set( h1, 'CData', L );
set( h2, 'CData', D );
drawnow;
end
ifmstop();
% Write data
save( 'test.mat', 'D', 'L', 'x', 'y', 'z' );
function ifmstart()
global cam1;
% Request connection configuration port
cam1.jTcpObjXML = jtcp('REQUEST',cam1.HOST,cam1.XMLPORT,'TIMEOUT',2000);
% Request connection data port
cam1.jTcpObj = jtcp('REQUEST',cam1.HOST,cam1.DATAPORT,'TIMEOUT',200);
cam1.jTcpObj.socket.setReceiveBufferSize(400000);
disp( 'Connected' );
% Disconnect camera
disconnect_data = sendXML( 'MDAXMLDisconnect', num2str(cam1.HOST) );
% Connect camera
connect_data = sendXML( 'MDAXMConnect', num2str(cam1.HOST), 1 );
% Reset camera
averaging_data = sendXML( 'MDAXMLSetProgram', 0, 0, 7 );
% Change trigger type
settrigger_data = sendXML( 'MDAXMLSetTrigger', 0, 0, cam1.TrigType );
% Set frontend data
setfrontend_data = sendXML( 'MDAXMLSetFrontendData', 0, cam1.ModFreq, cam1.SampMode, 0,
cam1.IntTimeSmall, cam1.IntTimeBig, 20, cam1.ifmTime );
% Set averaging
averaging_data = sendXML( 'MDAXMLSetAverageDetermination', 0, 0, cam1.averaging );
% Set median filter
median_data = sendXML( 'MDAXMLSetMedianFilterStatus', 0 );
% Set mean filter
mean_data = sendXML( 'MDAXMLSetMeanFilterStatus', 0 );
% Trigger
trigger_data = sendXML( 'MDAXMLTriggerImage' );
Industrieel VisieLab:
[email protected] and
[email protected]
106
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Get first frame
ifmgetframe();
function ifmgetframe()
global D L x y z cam1;
HEADERSIZE = 94;
OVERALLIMAGESIZE = (64*50 + HEADERSIZE) * 4;
% Trigger
trigger_data = sendXML( 'MDAXMLTriggerImage' );
% Request and read data
msg = int8('Dixyz');
jtcp('WRITE',cam1.jTcpObj,msg);
h = tic;
while (cam1.jTcpObj.dataInputStream.available < (OVERALLIMAGESIZE * length(msg)))
if toc(h) > 2
disconnect_data = sendXML( 'MDAXMLDisconnect', num2str(cam1.HOST) );
ifmstop();
error( 'Timeout: no response during image acquisition' );
end
end
data = jtcp('read',cam1.jTcpObj,'MAXNUMBYTES',OVERALLIMAGESIZE);
RealData=swapbytes(typecast(data, 'single'));
D = reshape(RealData(HEADERSIZE+1:end), 64, 50);
data = jtcp('read',cam1.jTcpObj,'MAXNUMBYTES',OVERALLIMAGESIZE);
RealData=swapbytes(typecast(data, 'single'));
L = reshape(RealData(HEADERSIZE+1:end), 64, 50);
data = jtcp('read',cam1.jTcpObj,'MAXNUMBYTES',OVERALLIMAGESIZE);
RealData=swapbytes(typecast(data, 'single'));
x = reshape(RealData(HEADERSIZE+1:end), 64, 50);
data = jtcp('read',cam1.jTcpObj,'MAXNUMBYTES',OVERALLIMAGESIZE);
RealData=swapbytes(typecast(data, 'single'));
y = reshape(RealData(HEADERSIZE+1:end), 64, 50);
data = jtcp('read',cam1.jTcpObj,'MAXNUMBYTES',OVERALLIMAGESIZE);
RealData=swapbytes(typecast(data, 'single'));
z = reshape(RealData(HEADERSIZE+1:end), 64, 50);
function ifmstop()
global cam1;
disconnect_data = sendXML( 'MDAXMLDisconnect', num2str(cam1.HOST) );
jtcp('close',cam1.jTcpObjXML);
msg = int8('q');
jtcp('WRITE',cam1.jTcpObj,msg);
jtcp('close',cam1.jTcpObj);
function answer = sendXML( func_name, varargin )
global cam1;
Industrieel VisieLab:
[email protected] and
[email protected]
107
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Create body
body = ['<?xml version="1.0" encoding="UTF-8"?>' 13 10 '<methodCall><methodName>' func_name
'</methodName>' 13 10 '<params>'];
% Add arguments
for c1 = 1:nargin-1
if ischar(varargin{c1})
body = [body '<param><value>' varargin{c1} '</value></param>'];
else
body = [body '<param><value><i4>' num2str(varargin{c1}) '</i4></value></param>'];
end
end
body = [body '</params></methodCall>' 13 10];
% Create header
header = ['POST /RPC2 HTTP/1.1' 13 10 'User-Agent: XMLRPC++ 0.7' 13 10 'Host: ' cam1.HOST
':' num2str(cam1.XMLPORT) 13 10 'Content-Type: text/xml' 13 10 'Content-length: '
num2str(length(body(:))) 13 10 13 10];
% Send message
jtcp('WRITE',cam1.jTcpObjXML,int8( [header body] ) );
% Wait for answer and receive data
h = tic;
while (cam1.jTcpObjXML.dataInputStream.available == 0)
if toc(h) > 2
disconnect_data = sendXML( 'MDAXMLDisconnect', num2str(cam1.HOST) );
ifmstop();
error( ['Timeout: no answer was received for following function: ' func_name] );
end
end
answer = jtcp('read',cam1.jTcpObjXML);
2. MESA Swiss Ranger SR4000 ( www.mesa.com )






Installeer de bijgeleverde MESA-software
Sluit de netwerk kabel en vervolgens de spanning (12V) aan ( Let op juiste polariteit ).
Stel het computer IP-adres in op 192.168.1.x
Voor computers onder toezicht is het noodzakelijk de gebruikte applicaties toe te voegen aan de firewall
regels om communicatie mogelijk te maken.
Gebruik ‘ping 192.168.1.y’ om te kijken of u het juiste adres van de camera kent.
Volg anders volgende instructies:
In order to set the static IP address of the camera, it is necessary to use a fall back address:


Apply power to the unit without connecting the Ethernet cable.
Wait 20 seconds before plugging in the network cable.
The camera now has a fixed IP address of 192.168.1.42. The camera cannot function normally using
this address: the only purpose is to set another static IP address.
In the following, the tool Telnet wil be used. This is not enabled by default on Windows platforms.
Here are the instructions to do this:
1. Start/Control Panel/Programs and Features
Industrieel VisieLab:
[email protected] and
[email protected]
108
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
2. On left side, select \Turn Windows features on or off
3. Check Telnet, wait until it has been installed
Start now a command prompt or equivalent console.
1. Telnet to the camera: telnet 192.168.1.42
2. set the static address, e.g. fw_setenv staticip 192.168.1.33
Exit telnet and repower the camera with the network cable connected. The camera will always use the static
address on power-on when attached to a host PC or network.

De camera is nu klaar voor gebruik.
% Start new session
clear all; close all; clc;
% Add camera control functions
addpath( strcat(cd,'/swissranger/') );
% Open camera connection
cam = sr_open;
% Set exposure
%res = sr_setautoexposure( cam, 0, 255, 100, 150 );
res = sr_setintegrationtime( cam, 15 );
% Automatic exposure
% Manual exposure
% Create figure
ha = axes( 'YDir', 'reverse', 'CLim', [0.5 1] );
hf = gcf;
set( hf, 'Colormap', colormap( 'gray' ) );
hi = image( 'cdata', zeros(144,176), 'CDataMapping', 'scaled', 'Parent', ha );
axis image;
for c1 = 1:50
% Trigger next image
sr_acquire( cam );
% Readout pointcloud
[ res, x, y, z ] = sr_coordtrf( cam );
%
D
L
D
Readout raw data
= sr_getimage( cam, 1 ); % Distance
= sr_getimage( cam, 2 ); % Intensity
= double( D )./ double( intmax( 'uint16' ) ) .* 5;
%
x
y
z
D
L
Rotate data
= x'; x2(:,:,c1)
= y'; y2(:,:,c1)
= z'; z2(:,:,c1)
= D'; D2(:,:,c1)
= L'; L2(:,:,c1)
=
=
=
=
=
% Convert phase to meters
x;
y;
z;
D;
L;
% Draw to screen
set( hi, 'cdata', z );
drawnow;
end
% Close camera connection
sr_close( cam );
Industrieel VisieLab:
[email protected] and
[email protected]
109
Association University and University Colleges Antwerp.
%
x
y
z
D
L
RGBd, ToF !
Final Report IWT 2012.
Convert all data to doubles
= double(x2);
= double(y2);
= double(z2);
= double(D2);
= double(L2);
% Store data
%save( 'test.mat', 'x', 'y', 'z', 'L', 'D' );
%save( 'test.mat', 'x', 'y', 'z', 'L', 'D' );
figure(100); surf(mean(x,3),mean(y,3),mean(z,3), 'LineStyle', 'none' ); axis equal;
cameratoolbar('Show'); cameratoolbar('SetMode','Orbit');
3. Fotonic Z-70 ( www.fotonic.com )







Installeer de bijgeleverde installatiebestanden.
Verbind alle connectoren (eerst netwerk, dan spanning aansluiten).
Verander het computer IP-adres naar 192.168.1.x
Voor computers onder toezicht moeten de firewall regels ingesteld worden die de programma’s toelaten
met de camera te communiceren!
Indien de spanning van de camera verbroken en terug aangesloten wordt en indien er geen netwerkkabel
is aangesloten, dan wordt het IP-adres na 50 seconden veranderd naar 192.168.1.10
Voer het EthConfig programma uit (\Fotonic\FZ-API\bin\x64\) om de camera IP in te stellen.
Type ‘ping 192.168.1.y’ in een commando venster om te controleren of de camera correct is
aangesloten.
Met behulp van ‘SetMode()’ kunnen verschillende modi geselecteerd worden (in matlab):
 'Temporal'
 'SpatioTemporal'
 'MultiSpatioTemporal'
 'zfine'
 'zfast'
 'MSSTcont'
 'burstzfine'
 'bursttemporal'
There are different measurement modes in the camera. Each mode uses frames
captured by sensor in different ways and most modes use several captures to
calculate one frame. The characteristics of a measurement, e.g. motion blur, noise
and accuracy will be different for the different modes. Generally the motion blur
that is seen on the image and also accuracy will increase with the number of
captures used to generate each frame.
Temporal mode
In temporal mode, the depth at each pixel is computed from the last four phase
captures. This mode provides highest depth resolution per pixel.
Spatio-Temporal mode
In Spatio-Temporal mode, two captures are used to compute one frame. Bias
cancellation is done temporally on the same pixel, whereas the arctangent function
is computed on two adjacent pixels of the same row.
Industrieel VisieLab:
[email protected] and
[email protected]
110
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Multi-frequency Spatio-Temporal mode
In Multi-frequency Spatio-Temporal mode, four captures are used to calculate one
frame. The four captures are used to disambiguate the distance of the objects
beyond the sensor nominal unambiguous range.
Z-fast
In zfast mode, the depth is calculated from a single capture, were the depth is
calculated from two adjacent pixels. Z-fast do not utilize bias cancellation. This
mode has the least motion artifacts. The resolution is lower and the noise levels
are higher than in other modes.
Z-fine
In Z-fine mode, the depth of each pixel is calculated using two consecutive
captures on each pixel. Z-fine does not utilize bias cancellation. This means
highest resolution, small motion artifacts but slightly more noise than in e.g.
temporal.
Multishutter Spatio-Temporal
Multi-shutter Spatio-Temporal is basically a High Dynamic version of SpatioTemporal. Instead of using two captures, four captures is used. The first two
frames are with the higher shutter time whilst capture three and four are using a
lower shutter time. The parameter Saturation is used to determine the limit when a
pixel is improper to use.If a pixel has to high signal(A-B > Saturation) it will
be replaced with the one using the lower shutter.
Burst Modes
All modes except Z-fast are possible to run in Burst mode. The modes has the same
characteristics as non burst but it uses a different image capture sequence. In
non burst the camera sensor is set to capture a new image every x ms. This will
make the camera produce a new frame every x:s ms since each frame needs for
captures but each capture is used up 2-4 times. In Burst mode however, the camera
sensor is set to capture 2-4 images as fast as possible. These captures are than
used to produce one new frame. This continues so each capture is only used once
for each frame. The big benefit of this is that the time between each capture can
be kept short so there will be very little motion blur. The drawback is that the
camera will not be able to send as many frames per second as with non burst modes.
clear all; close all; clc; format long;
addpath('CameraCtrl\')
Closeldu;
global cont;
cont.first = 1;
OpenCamera();
StartSensor();
SetMode('Temporal');
% Open sensor communication interface
it = 40;
SetShutter(it);
SetFrameRate(40);
SetLightSwitchState(1);
%
%
%
%
Integration time
Value in 0.1 ms
Set frame rate to 20 fps
Turn on LED's
for i=1:3
[x, y, z, L] = GrabImage();
end
tic;
for c1 = 1:50
[x, y, z, L] = GrabImage;
Industrieel VisieLab:
[email protected] and
[email protected]
111
Association University and University Colleges Antwerp.
x2(:,:,c1) =
y2(:,:,c1) =
z2(:,:,c1) =
L2(:,:,c1) =
pause(0.02);
RGBd, ToF !
Final Report IWT 2012.
x;
y;
z;
L;
end
toc;
StopSensor();
CloseCamera();
Closeldu;
%
x
y
z
L
Convert all data to doubles
= double(x2);
= double(y2);
= double(z2);
= double(L2);
% Store data
%save( 'B0_fot_exp40_d1920_o330.mat', 'x', 'y', 'z', 'L' );
ih1 = imshow( z(:,:,50), [0 500] );
% figure(100); surf(mean(x,3),mean(y,3),mean(z,3), 'LineStyle', 'none' ); axis equal;
%
cameratoolbar('Show'); cameratoolbar('SetMode','Orbit');
4. DepthSense 311 ( www.Softkinetic.com )



Er wordt gebruik gemaakt van een meegeleverde 32-bit .dll functiebibliotheek voor alle
cameracommunicatie.
De nieuwste drivers ( na de versie 2.3.10.0) zijn NIET compatibel met Matlab.
De optrima.h header-file werd aangepast om compatibiliteit met oudere Matlab versies te verzekeren.
function depthsense()
clear all; close all; clc;
global intens D L x y z nx ny nz f;
f = 150; intens = 20;
start_DS();
update_data();
stop_DS();
figure(1); imshow(D, [0 3]); title('Distance');
figure(2); imshow(L, []);
title('Intensity');
figure(3); imshow(z, [0 3]); title('z');
function start_DS()
global pmap lmap plength llength confthresh range U V d f intens;
% LOAD LIBRARY
if libisloaded( 'optrima' )
unloadlibrary( 'optrima' );
end
dllname = 'liboptrima.dll';
headername = 'Optrima2.h';
warning('off');
[notfound warnings] = loadlibrary( dllname, headername, 'alias', 'optrima' );
Industrieel VisieLab:
[email protected] and
[email protected]
112
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
warning('on');
% INITIALIZE VARIABLES
plength = libpointer( 'uint32Ptr', zeros( 1 ) );
llength = libpointer( 'uint32Ptr', zeros( 1 ) );
rangeval = libpointer( 'singlePtr', zeros( 1 ) );
pmap = libpointer( 'int16Ptr', zeros( 160,120,'int16' ) );
lmap = libpointer( 'uint16Ptr', zeros( 160,120,'uint16' ) );
confthresh = single(5);
% START CAMERA AND SET PROPERTIES
calllib( 'optrima', 'optrima_init');
pause(3);
errmsgx1 = calllib( 'optrima', 'optrima_set_property',
errmsgx2 = calllib( 'optrima', 'optrima_set_property',
errmsgx3 = calllib( 'optrima', 'optrima_set_property',
errmsgx4 = calllib( 'optrima', 'optrima_set_property',
errmsgx5 = calllib( 'optrima', 'optrima_set_property',
errmsgx6 = calllib( 'optrima', 'optrima_set_property',
'ENABLE_RGB_EVENT_HANDLERS', 0 );
'ENABLE_DENOISING', 0 );
'ENABLE_LEAKAGE_ALGORITHM', 0 );
'ENABLE_DENOISING', 0 );
'OC310_ENABLE_SATURATION', 1 );
'OC310_FRAMERATE', 25 );
% RESTART CAMERA
calllib( 'optrima', 'optrima_exit');
pause(1);
calllib( 'optrima', 'optrima_init');
pause(3);
errmsg1 = calllib( 'optrima', 'optrima_enable_camera' );
errmsg2 = calllib( 'optrima', 'optrima_enable_camera_rgb' );
pause(3);
% Get range
[errmsg4 range] = calllib( 'optrima', 'optrima_get_range', rangeval );
% Set intensity
calllib( 'optrima', 'optrima_set_light_intensity', uint8(intens));
I = 120; J = 160;
I2 = I/2; J2 = J/2;
ff = f * f;
u = (1:J) - (J2+0.5);
v = (1:I) - (I2+0.5);
U = repmat( u , [I 1]);
UU = repmat( uu, [I 1]);
V = repmat( v', [1 J]);
VV = repmat( vv',[1 J]);
UUff = UU + ff;
d = sqrt( VV + UUff );
uu = u .* u;
vv = v .* v;
function stop_DS()
% Shut down camera
errmsg7 = calllib( 'optrima', 'optrima_disable_camera' );
errmsg8 = calllib( 'optrima', 'optrima_disable_camera_rgb' );
calllib( 'optrima', 'optrima_exit');
function update_data()
global pmap plength confthresh range D lmap llength L d x y z U V f nx ny nz;
% Get camera data
[errmsg5 P q]
= calllib( 'optrima', 'optrima_get_phasemap', pmap, plength, confthresh);
[errmsg7 L q]
= calllib( 'optrima', 'optrima_get_confidencemap', lmap, llength );
Industrieel VisieLab:
[email protected] and
[email protected]
113
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
%pause(0.05);
% Calculate distance from phase data
D = double(P') * (range / 2^15);
L = L';
Dd
x
=
=
D ./ d;
U .* Dd;
y = -V .* Dd; z = f
* Dd;
f1 = zeros(1, 9); f1(1) = 1; f1(end) = -1; f2 = f1';
% Filter image
z1 = conv2( z, f1, 'same' ); z2 = conv2( z, f2, 'same' );
x1 = conv2( x, f1, 'same' ); x2 = conv2( x, f2, 'same' );
y1 = conv2( y, f1, 'same' ); y2 = conv2( y, f2, 'same' );
% Create X vector, Y vector and Normal
nx = y1.*z2-z1.*y2; ny = z1.*x2-x1.*z2; nz = x1.*y2-y1.*x2;
% Normalize
n = sqrt( nx.^2 + ny.^2 + nz.^2 );
nx = nx ./ n; ny = ny ./ n; nz = nz ./ n;
5. uEye RGB camera ( www.IDS-imaging.com )


Installeer de drivers en de software (http://www.ids-imaging.com)
Verbind de camera met een USB kabel aan de computer, de LED op de achterzijde verandert van rood
naar groen.
% KdG Industrieel Visielab 2011
% Luc Mertens, Rudi Penne, Stephanie Buyse, Wim Abbeloos
% uEye camera image acquisition
% Prepare new session
clear all; close all; clc;
delete(imaqfind);
% Display debugging information?
debug = 1;
% Create camera object
if exist( 'cam' )
stop( cam );
flushdata( cam );
clear( 'cam' );
end
cam = videoinput('winvideo', 1, 'RGB24_1280x1024' );
% Display camera properties
prop = get( cam, 'Source' );
if debug
warning( 'on' );
disp( 'Hardware Properties:' ); imaqhwinfo( 'winvideo', 1 )
disp( 'Camera Properties:' );
get( cam )
disp( 'Exposure Properties:' ); propinfo( prop )
else warning( 'off' );
Industrieel VisieLab:
[email protected] and
[email protected]
114
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
end
% Set Properties
triggerconfig( cam, 'manual' );
set( cam, 'FramesPerTrigger', 1 );
set( prop, 'VerticalFlip', 'on' );
set( prop, 'ExposureMode', 'manual', 'Exposure', -3 ); % range: [-16 -3]
set( prop, 'GainMode', 'manual', 'Gain', 0 );
set( prop, 'ContrastMode', 'manual', 'Contrast', 0 );
% Start camera
start( cam );
% Trigger acquisition
trigger( cam );
wait( cam );
% Get image
img = getdata( cam, 1 ); imshow( img ); title( 'Image' );
% Write image
imwrite( img , 'testimg.png' );
% Close camera
stop( cam ); clear( 'cam' );
6. De motoren van de AGV.
Industrieel VisieLab:
[email protected] and
[email protected]
115
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Het aandrijfsysteem
Er wordt gebruik gemaakt van een aandraafsysteem RD03 - 24v Robot drive (http://www.robotelectronics.co.uk/acatalog/Drive_Systems.html).
Dit bestaat uit:




2 x 24V DC motoren
2 x Wielen
2 x motorsteunen
1 x sturingsmodule
De motoren en hun encoders dienen verbonden te worden met de sturingsmodule. De sturingsmodule
dient voorzien te worden van 24V DC.
Industrieel VisieLab:
[email protected] and
[email protected]
116
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
De communicatie
De sturingsmodule kan aangestuurd worden met behulp van seriële communicatie.
We gebruiken een USB->serieel adapter om communicatie over USB mogelijk te maken. Hiervoor
gebruiken we de S27 USB to Serial module (http://www.robotelectronics.co.uk/acatalog/Serial_Interface.html). De drivers voor de virtuele COM poort zijn te
vinden op http://www.ftdichip.com/Drivers/VCP.htm .
De Baudrate voor de communicatie kan ingesteld worden met jumpers (beide contacten open voor
9600bps).
De batterijen
3 x 14.8V ( 14V -> 16.8V ) 5 Ah lithium polymeer. Deze batterijen bestaan uit 4 serieel geschakelde
cellen van 3.7V per stuk. OPGELET: DE SPANNING VAN DE BATTERIJEN MAG NOOIT
ONDER DE 14V ZAKKEN.
De batterijlader
 Sluit de oplader aan op de netspanning
 Selecteer LiPo Batt ( druk enkele malen op stop, druk vervolgens start om te bevestigen)
 Selecteer LiPo Balance (gebruik pijltjes, druk op start)
Industrieel VisieLab:
[email protected] and
[email protected]
117
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
 Wijzig stroom naar 5.0 A, druk op start
 Wijzig spanning naar 14.8V(4S)
 Sluit de balanceerstekker van de batterij aan op de oplader
 Gebruik banaanstekkers om de spanningsaansluitingen met de oplader te verbinden (opgepast,
de banaanstekkers mogen elkaar nooit raken!)
 Druk enkele seconden op start om laden te starten
 Wanneer opladen klaar is:
 Verwijder spanningsaansluiting en banaanstekkers
 Verwijder balanceerstekker
De spanningsomvormers
De spanningsomvormers zorgen ervoor dat er steeds een stabiele spanning van 12V en 24V
beschikbaar is. De spanning van de batterij kan niet rechtstreeks gebruikt worden vermits de spanning
te sterk varieert (16.8v wanneer volledig opgeladen, 14V wanneer volledig ontladen).
Indien de output spanning niet volledig correct zou zijn dan kan die worden bijgeregeld door de
achterzijde van de omzetter te verwijderen (4 schroeven) en de regelbare weerstand met een kleine
schroevendraaier een beetje te verdraaien.
function motorcontroldemo()
% Open controller communication
startmotor( 6 ); % COM port connected to motor controller
% Readout motor controller voltage
Vcontrol = motorcmd( 'getvolts' );
% Set motor speeds
motorcmd( 'setspeed1', 2 ); motorcmd( 'setspeed2', 0 ); pause(2);
motorcmd( 'setspeed1', 0 ); motorcmd( 'setspeed2', 2 ); pause(2);
motorcmd( 'setspeed1', 0 ); motorcmd( 'setspeed2', 0 );
% Close controller communication
stopmotor();
function startmotor( portnr )
global motor;
% Start serial communication
delete( instrfind );
port = strcat('COM', num2str(portnr));
motor = serial( port, 'BaudRate', 9600, 'Parity', 'none', 'DataBits', 8, 'StopBits', 2,
'Timeout', 0.2 );
fopen( motor );
motorcmd(
motorcmd(
motorcmd(
motorcmd(
'disabletimeout' );
'enablereg' );
'resetenc' );
'setmode', 1 ); motorcmd( 'setspeed1', 0 ); motorcmd( 'setspeed2', 0 );
Industrieel VisieLab:
[email protected] and
[email protected]
118
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
motorcmd( 'setaccel', 1 ); %motorcmd( 'setaccel', 10 );
function stopmotor()
global motor;
% Stop serial communication
motorcmd( 'setmode', 1 ); motorcmd( 'setspeed1', 0 ); motorcmd( 'setspeed2', 0 );
motorcmd( 'enabletimeout' );
fclose( motor ); delete( motor ); clear( 'motor' );
function varargout = motorcmd( cmd, varargin )
global motor;
if ~ischar( cmd )
error( 'Second argument must be a command string' );
end
switch cmd
case 'getspeed1'
fwrite( motor, [0 33], 'int8' ); % returns the current requested speed of motor 1
varargout(1) = { -fread( motor, 1, 'uint8' ) };
case 'getspeed2'
fwrite( motor, [0 34], 'int8' ); % returns the current requested speed of motor 2
varargout(1) = { -fread( motor, 1, 'uint8' ) };
case 'getenc1'
fwrite( motor, [0 35], 'uint8' );
% motor 1 encoder count, 4 bytes returned high
byte first (signed)
val = fread( motor, 4, 'uint8' );
val2 = uint32( bitcmp( uint8(val) ) );
val3 = bitshift( val2(1), 24 ) + bitshift( val2(1), 16 ) + bitshift( val2(3), 8 ) +
val2(4);
varargout(1) = { double(val3) };
case 'getenc2'
fwrite( motor, [0 36], 'uint8' );
% motor 2 encoder count, 4 bytes returned high
byte first (signed)
val = fread( motor, 4, 'uint8' );
val2 = uint32( bitcmp( uint8(val) ) );
val3 = bitshift( val2(1), 24 ) + bitshift( val2(1), 16 ) + bitshift( val2(3), 8 ) +
val2(4);
varargout(1) = { double(val3) };
case 'getencs'
fwrite( motor, [0 37], 'uint8' );
% returns 8 bytes - encoder1 count, encoder2
count
varargout(1) = { fread( motor, 8, 'uint8' ) };
case 'getvolts'
fwrite( motor, [0 38], 'uint8' );
% returns the input battery voltage level
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent1'
fwrite( motor, [0 39], 'uint8' );
% returns the current drawn by motor 1
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getcurrent2'
fwrite( motor, [0 40], 'uint8' );
% returns the current drawn by motor 2
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getversion'
fwrite( motor, [0 41], 'uint8' );
% returns the software version
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getaccel'
fwrite( motor, [0 42], 'uint8' );
% returns the current acceleration level
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getmode'
Industrieel VisieLab:
[email protected] and
[email protected]
119
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
fwrite( motor, [0 43], 'uint8' );
% returns the currently selected mode
varargout(1) = { fread( motor, 1, 'uint8' ) };
case 'getVI'
fwrite( motor, [0 44], 'uint8' );
% returns battery volts, motor1 current and
then motor2 current
varargout(1) = { fread( motor, 1, 'uint8' ) };
% Battery voltage
varargout(2) = { fread( motor, 1, 'uint8' ) };
% Current motor 1
varargout(3) = { fread( motor, 1, 'uint8' ) };
% Current motor 2
case 'setspeed1'
if nargin ~= 2
error( 'Incorrect number of input arguments' );
end
speed = cell2mat(varargin(1));
fwrite( motor, [0 49 -speed], 'int8' );
% set new speed1
case 'setspeed2'
if nargin ~= 2
error( 'Incorrect number of input arguments' );
end
speed = cell2mat(varargin(1));
fwrite( motor, [0 50 -speed], 'int8' );
% set new speed2
case 'setaccel'
if nargin ~= 2
error( 'Incorrect number of input arguments' );
end
accel = cell2mat(varargin(1));
fwrite( motor, [0 51 accel], 'uint8' );
% set new acceleration
case 'setmode'
if nargin ~= 2
error( 'Incorrect number of input arguments' );
end
mode = cell2mat(varargin(1));
fwrite( motor, [0 52 mode], 'uint8' );
% set the mode
case 'resetenc'
fwrite( motor, [0 53], 'uint8' );
% zero both of the encoder counts
case 'disablereg'
fwrite( motor, [0 54], 'uint8' );
% power output not changed by encoder feedback
case 'enablereg'
fwrite( motor, [0 55], 'uint8' );
% power output is regulated by encoder feedback
case 'disabletimeout'
fwrite( motor, [0 56], 'uint8' );
% Continuously output with no regular commands
case 'enabletimeout'
fwrite( motor, [0 57], 'uint8' );
% Output will stop after 2 seconds without
communication
otherwise
error( 'Incorrect command' );
% Incorrect command string
end
Industrieel VisieLab:
[email protected] and
[email protected]
120
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
7. Wheelchair navigation
(Rolstoel Permobil van www.hmc-products.com ).




Installatie drivers USB-serieel converter.
Communicatie kabel (USB) aansluiten.
Rolstoel aanzetten.
Groene knop gebruiken om in mode 3 of 4 te zetten.
function rolstoeldemo()
% Prepare new session
clear all; close all; clc;
% Change number to number of used COM-port
COMport = 4;
% Start connection
startmotor( COMport );
% Rotate right
motorcmd( 30, 60 ); pause(2);
% Rotate left
motorcmd( 30, -30 ); pause(2);
% Forward
motorcmd( 40, 25 ); pause(2);
% Stop
motorcmd( 0, 0 );
% Stop connection
stopmotor();
function startmotor( COMport )
global motor;
COMport_str = ['COM' num2str( COMport )];
% Start serial communication
delete( instrfind );
motor = serial( COMport_str, 'BaudRate', 38400, 'Parity', 'none', 'DataBits', 8, 'StopBits', 2,
'Timeout', 0.2 );
fopen( motor );
motorcmd( 0, 0 );
function stopmotor()
global motor;
% Stop serial communication
motorcmd( 0, 0 );
fclose( motor ); delete( motor ); clear( 'motor' );
function motorcmd( fwd, trn )
global motor;
str1 = '<XY X=''';
str2 = num2str(trn);
str3 = ''' Y=''';
str4 = num2str(fwd);
str5 = ''' S=''100''/>';
fprintf( motor, strcat(str1,str2,str3,str4,str5) );
Industrieel VisieLab:
[email protected] and
[email protected]
121
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
8. Wall segmentation in the outdoor application of Vision &
Robotics.
% Start new session
clear all; close all; clc;
load walltest;
% Parameters
wallsize = 200;
T = single( 0.4 );
% Minimum size of wall in pixels
% Threshold
L = rot90(L,3);
D = rot90(D,3);
% Calculate xyz
f = 78; ff = f * f;
I = 50; J = 64;
I2 = I/2; J2 = J/2;
u = (1:J) - (J2+0.5);
uu = u .* u;
v = (1:I) - (I2+0.5);
vv = v .* v;
U = repmat( u , [I 1]);
V = repmat( v', [1 J]);
UU = repmat( uu, [I 1]);
VV = repmat( vv',[1 J]);
d = sqrt( VV + UU + ff );
Dd = D ./ d;
x
= U .* Dd;
y
= -V .* Dd;
z
= f * Dd;
% Filter image
fs = 5;
f1 = zeros(1, fs);
z1 = conv2( z, f1,
x1 = conv2( x, f1,
y1 = conv2( y, f1,
f1(1) = 1; f1(end) = -1;
'same' ); z2 = conv2( z,
'same' ); x2 = conv2( x,
'same' ); y2 = conv2( y,
f2 = f1';
f2, 'same' );
f2, 'same' );
f2, 'same' );
% Create X vector, Y vector and Normal
nx = y1.*z2-z1.*y2; ny = z1.*x2-x1.*z2; nz = x1.*y2-y1.*x2;
% Normalize
n = sqrt( nx.^2 + ny.^2 + nz.^2 );
nx = nx ./ n; ny = ny ./ n; nz = nz ./ n;
% Enter normals into 3D matrix
img = single(cat( 3, nx, ny, nz ));
% Image size
h = uint16( size( img, 1)); w = uint16( size( img, 2));
% Pixels to check
check = abs(ny) < 0.2;
check(:,1:uint8(fs)/2)
= 0;
check(:,end-uint8(fs)/2:end) = 0;
% Vertical, add height constraint on y
% Exclude borders
% Region
Industrieel VisieLab:
[email protected] and
[email protected]
122
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
region = zeros( size( img, 1 ), size( img, 2 ), 'uint16' );
cur_reg = uint16(1);
% Neighbours, connectedness
NB = [ -1 0; 0 1; 1 0; 0 -1 ];
NBS = uint8( size(NB,1) );
% Initialize arrays
list
= zeros( w*h, 2, 'uint16' );
num_el = zeros( w*h, 1, 'uint16' );
color = zeros( w*h, 2);
tic;
for a = 1:h
for b = 1:w
if check( a, b )
region( a, b ) = cur_reg;
cur_regs = 1;
m = [ img( a, b, 1 ) img( a, b, 3 )];
list( 1, : ) = [a b];
last = uint16(1);
while last > 0
u = list( last, 1 ); v = list( last, 2 );
last = last - 1;
if check( u, v )
for c1 = 1:NBS
iu = u + NB( c1, 1 ); iv = v + NB( c1, 2 );
% Inside?
if iu > 0 && iu <= h && iv > 0 && iv <= w && check( iu, iv )
% Add to region?
d = sqrt(( m(1)-img(iu,iv,1)).^2 + (m(2)-img(iu,iv,3)).^2);
if d <= T
last = last + 1;
region(iu,iv) = cur_reg;
m = m + [img(iu, iv, 1)-m(1) img(iu, iv, 3)-m(2)] ./ cur_regs;
cur_regs = cur_regs + 1;
list( last, 1 ) = iu; list( last, 2 ) = iv;
end
end
end
check( u, v ) = false;
end
end
num_el( cur_reg )
= cur_regs;
color( cur_reg, : ) = m;
cur_reg = cur_reg + 1;
end
end
end
toc;
goodwalls = find( num_el > wallsize );
Industrieel VisieLab:
[email protected] and
[email protected]
123
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Find parameters for good walls (perpencidular distance, normal-x, normal-z)
tic;
for c1 = 1:size(goodwalls,1)
cur_wall = region == goodwalls(c1);
p = polyfit(x(cur_wall),z(cur_wall),1);
goodwalls(c1)
wd = abs(p(2)) ./ sqrt(p(1).^2+1)
wnx = mean(nx(cur_wall))
wnz = mean(nz(cur_wall))
end
toc;
% Display walls
for c1 = 1:h
for c2 = 1:w
if region(c1,c2) ~= 0
if num_el(region(c1,c2)) < wallsize
region(c1,c2) = 0;
% remove if not good
end
end
end
end
figure(1);
subplot(121); imshow( D, [] );
title( 'Distance' );
subplot(122); imshow( region, [0 max(goodwalls)] );
title( 'Vertical planes' );
Industrieel VisieLab:
[email protected] and
[email protected]
124
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
9. Path planning for the indoor application at Vision & Robotics.
Free navigation in a world with a known map.
9.1.
The Brushfire algorithm (Principles of Robot Motion)
Because of its IP value the program is not given free.
% Prepare new session
clear all; close all; clc;
% Generate new map
map = false(120,250);
% 240 * 500 cm
% Define startpoint and endpoint
ep = [25 225];
sp = [100 20];
% Prefer straight line
line = 0;
% Walls
map(1,:)
map(end,:)
map(:,1)
map(:,end)
=
=
=
=
1;
1;
1;
1;
% Objects
map(1:30,50) = 1;
map(1:30,100) = 1;
map(1:30,200) = 1;
map(30,170:200) = 1;
map(end-90:end,140) = 1;
map(end-30:end,190) = 1;
map(70:90,70:90) = 1;
ent' );
colormap( 'jet' );
Industrieel VisieLab:
[email protected] and
[email protected]
125
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
As can be seen the path is not OK. The algorithm encounters a boogie trap. Another algorithm should
be found.
9.2.
The Wave Front Algorithm
% Prepare new session
clear all; close all; clc;
% Generate new map
map = false(120,250); % 240 * 500 cm
% Define startpoint and endpoint
ep = [25 225];
sp = [100 10];
% Walls
map(1,:)
= 1;
map(end,:) = 1;
map(:,1)
= 1;
map(:,end) = 1;
% Objects
map(1:30,50) = 1;
map(1:30,100) = 1;
map(1:30,200) = 1;
map(30,170:200) = 1;
map(end-90:end,140) = 1;
map(end-30:end,190) = 1;
map(70:90,70:90) = 1;
Industrieel VisieLab:
[email protected] and
[email protected]
126
Association University and University Colleges Antwerp.
9.3.
RGBd, ToF !
Final Report IWT 2012.
Combined Algorithm: ( Wave Front and Distance Repulsion ).
% Prepare new session
clear all; close all; clc;
% Generate new map
map = false(120,250); % 240 * 500 cm
% Define startpoint and endpoint
ep = [25 225];
sp = [100 10];
% Walls
map(1,:)
= 1;
map(end,:) = 1;
map(:,1)
= 1;
map(:,end) = 1;
% Objects
map(1:30,50) = 1;
map(1:30,100) = 1;
map(1:30,200) = 1;
map(30,170:200) = 1;
map(end-90:end,140) = 1;
map(end-30:end,190) = 1;
map(70:90,70:90) = 1;
% Dilate map
map = imdilate(map,ones(10));
Industrieel VisieLab:
[email protected] and
[email protected]
127
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
Repulsio
n
Remark: take into account that the final theoretical path depends on the weights used to balance
the Wave Front and the Repulsion Force relative to each other.
10. Localization
10.1.
Localization based on known landmarks
function pointnav()
% Navigate using points
% Prepare new session
clear all; close all; clc;
lm = 1;
pp = 1;
% Random landmarks or square
% Display planned path or not
% Landmarks
if lm == 1
P = 100 * randn(2,200);
P = cat( 1, P, ones( 1, size(P,2) ));
else
P0 = -50:10:50;
P1 = cat(1,P0,-50 * ones(1,size(P0,2)) );
P2 = cat(1,P0, 50 * ones(1,size(P0,2)) );
P3 = cat(1,-50 * ones(1,size(P0,2)), P0 );
P4 = cat(1, 50 * ones(1,size(P0,2)), P0 );
P = cat(2, P1, P2, P3, P4);
P = cat(1, P, ones(1,size(P,2)));
end
Industrieel VisieLab:
[email protected] and
[email protected]
128
Association University and University Colleges Antwerp.
% Parameters
T = [0 0 0]; R = T; E = T;
p = [1 20 18;
2 20 20;
2 10 9;
2 30 30];
dt = 0.1;
wb = 0.5;
fov = pi/3;
dm = 100;
me = 0.02;
se = 0.5;
RGBd, ToF !
Final Report IWT 2012.
% Start position
% Path definition
% Time | Left speed | Right speed
%
%
%
%
%
%
Simulation time step
Vehicle wheel base
Camera field of view
Max. distance
Measurement error
Speed error
% Triangulation
if ~exist('DelaunayTri')
TRI = delaunay(P(1,:)',P(2,:)');
else
TRI = DelaunayTri(P(1,:)',P(2,:)');
end
figure(1);
plot(P(1,:), P(2,:), 'k*'); title( 'Points and Positions' );
xlim([-50 50]); ylim([-50 50]); daspect([1 1 1]); hold on;
RelPos = zeros(3,1);
% Start simulation
for c1 = 1:size(p,1)
% number of sub-steps
n = p(c1,1) / dt;
vl = p(c1,2);
vr = p(c1,3);
for c2 = 1:n
% Update position
vl2 = vl - 1/3*RelPos(2) + se * randn(1);
vr2 = vr + 1/3*RelPos(2) + se * randn(1);
[dx dy da] = move( T(3), dt, wb, vl, vr );
[dx2 dy2 da2] = move( R(3), dt, wb, vl2, vr2 );
[dx3 dy3 da3] = move( E(3), dt, wb, vl, vr );
T = T + [dx dy
da];
% Theoretical position
R = R + [dx2 dy2 da2];
% Real
E = E + [dx3 dy3 da3];
% Estimate
% Calculate visible points
RT = [cos(R(3)) -sin(R(3)) R(1);
sin(R(3)) cos(R(3)) R(2);
0
0
1];
Pc = RT \ P;
d = sqrt( Pc(1,:).^2 + Pc(2,:).^2 );
m = d .* ( me * randn(size(d)) + 1);
r = m < dm;
a = atan2( Pc(1,:), Pc(2,:) );
a1 = a > pi()/2 - fov/2;
a2 = a < pi()/2 + fov/2;
v = r & a1 & a2;
Industrieel VisieLab:
% Noise on speed
% Theoretical path
% Real
% Estimate
% Current position
% Points in camera coordinate system
% Distance from camera
% Distance with measurement noise
% Range, max. distance
% Field of view
% Visible points
[email protected] and
[email protected]
129
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Measurements
Pmc = [ m .* sin(a); m .* cos(a); ones(size(m)) ];
Pm = RT * Pmc;
% Find better estimate by minimizing distance of measurements to points
if ~exist('DelaunayTri')
PI = dsearch( P(1,:)', P(2,:)', TRI, Pm(1,v)', Pm(2,v)' );
else
PI = nearestNeighbor( TRI, Pm(1,v)', Pm(2,v)' );
end
E = fminsearch( @(t) cost( PI, P, Pmc, t), E );
ET = [cos(E(3)) -sin(E(3)) E(1);
sin(E(3)) cos(E(3)) E(2);
0
0
1];
Pe = ET * Pmc;
% Correct speeds
RelPos = ET \ [E(1); E(2); 1];
figure(1);
if pp
quiver(T(1),T(2),10*cos(T(3)),10*sin(T(3)), 'g');
end
quiver(R(1),R(2),10*cos(R(3)),10*sin(R(3)), 'b');
quiver(E(1),E(2),10*cos(E(3)),10*sin(E(3)), 'c');
plot(Pm(1,v), Pm(2,v), 'b*');
plot(Pe(1,v), Pe(2,v), 'r*');
%pause();
end
% Theoretical path
%
%
%
%
Real
Estimated
Measurements
Corrected measurements
end
function C = cost( PI, P, Pmc, t)
ET = [cos(t(3)) -sin(t(3)) t(1);
sin(t(3)) cos(t(3)) t(2);
0
0
1];
Pe = ET * Pmc;
D = ( Pe(1,PI) - P(1,PI) ).^2 + ( Pe(2,PI) - P(2,PI) ).^2;
C = sum( D );
function [ dx dy da ] = move( a, dt, wb, vl, vr )
if vl == vr
da = 0;
l = vl * dt;
dx = l * cos(a);
dy = l * sin(a);
else
v
= ( vr + vl ) / 2;
r
= ( vr * wb ) / ( vr - vl ) - wb/2;
da = v / r * dt;
dx1 = r * sin(da);
dy1 = r - r * cos(da);
dx = cos(a) * dx1 - sin(a) * dy1;
dy = sin(a) * dx1 + cos(a) * dy1;
end
Industrieel VisieLab:
[email protected] and
[email protected]
130
Association University and University Colleges Antwerp.
10.2.
RGBd, ToF !
Final Report IWT 2012.
Localization based on known Walls
(seen as specific landmarks).
function wallnav_test5()
%
%
%
%
%
Navigate using walls
Green is 'predicted path'
Blue is 'true path'
Cyan is 'current estimated location after optimalisation'
Black is 'next estimated location'
clear all; close all; clc;
global wall L1 L2 D2 nx2 nz2 mo;
% Define walls
L1 = [ 250 250 -250 -250;
-120 120 120 -120]; L1 = L1/2;
L2 = [ 250 -250 -250 250;
120 120 -120 -120]; L2 = L2/2;
L1 = cat( 1, L1, ones(1,size(L1,2)) );
L2 = cat( 1, L2, ones(1,size(L2,2)) );
% Define path and specify vehicle parameters
p = [1 20 18;
2 20 20;
2 9 10;
2 30 30];
dt = 0.1;
% Simulation time step
wb = 0.5;
% Wheel base (m)
fov = pi/3;
% Camera field of view
Industrieel VisieLab:
[email protected] and
[email protected]
131
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Transforms
T = [0 0 0]; R = T; E = T;
% Create figure to display path
figure(1); hold on; title( 'World' ); axis equal;
xlim( [min(L1(1,:))-10 max(L1(1,:))+10] ); ylim( [min(L1(2,:)-10) max(L1(2,:))+10] );
% Display current position
quiver( T(1), T(2), 10*cos(T(3)), 10*sin(T(3)), 'g' );
quiver( R(1), R(2), 10*cos(R(3)), 10*sin(R(3)), 'b' );
quiver( E(1), E(2), 10*cos(E(3)), 10*sin(E(3)), 'c' );
drawnow;
for c1 = 1:size(p,1)
% number of sub-steps
n = p(c1,1) / dt;
vl = p(c1,2);
vr = p(c1,3);
for c2 = 1:n
% Update position
if E(3) > 2*pi
E(3) = E(3) - 2*pi;
end
if E(3) < 0
E(3) = E(3) + 2*pi;
end
Eold = E;
vl2 = vl + 0.5 * randn(1);
vr2 = vr + 0.5 * randn(1);
[dx dy da db1 dd1 dc1 ] = move1( T(3), dt, wb, vl, vr );
[dx2 dy2 da2 db2 dd2 dc2 ] = move1( R(3), dt, wb, vl2, vr2 );
[dx3 dy3 da3 db3 dd3 dc3 ] = move1( E(3), dt, wb, vl, vr );
T = T + [dx dy da];
% Theoretical
R = R + [dx2 dy2 da2];
% Real
E = E + [dx3 dy3 da3];
% Estimate
if E(3) > 2*pi
E(3) = E(3) - 2*pi;
end
if E(3) < 0
E(3) = E(3) + 2*pi;
end
quiver( E(1), E(2), 10*cos(E(3)), 10*sin(E(3)), 'k' );
% New transformation matrix
RT = [cos(R(3)) -sin(R(3)) R(1);
sin(R(3)) cos(R(3)) R(2);
0
0
1];
% Transform lines
LT1 = RT \ L1;
LT2 = RT \ L2;
la1 = atan2(LT1(2,:),LT1(1,:));
la2 = atan2(LT2(2,:),LT2(1,:));
leq = cross(LT1,LT2);
% Find visible planes
Industrieel VisieLab:
[email protected] and
[email protected]
132
Association University and University Colleges Antwerp.
alc1
alc2
vec
temp
temp
alc3
ac
=
=
=
=
=
=
=
RGBd, ToF !
Final Report IWT 2012.
la1 < -fov/2 & la2 < -fov/2;
la1 > fov/2 & la2 > fov/2;
cross( [0 0 1], [1 0 1] );
cross( leq, repmat( vec', [1 size(leq,2)] ) );
temp ./ repmat( temp(3,:), [3 1] );
temp(1,:) > 0;
~( alc1 | alc2 ) & alc3;
% Plane parameters
D = abs( leq(3,:) ) ./ sqrt( leq(1,:).^2 + leq(2,:).^2 );
nx = -sin( atan2( leq(2,:), leq(1,:) ) );
nz = -cos( atan2( leq(2,:), leq(1,:) ) );
% Measurement noise
D2 = D + 0.01 .* randn(size( D)) .* D;
nx2 = nx + 0.05 .* randn(size(nx));
nz2 = nz + 0.05 .* randn(size(nz));
nx2(nx2(:)> 1) = 1; nx2(nx2(:)<-1) = -1;
nz2(nz2(:)> 1) = 1; nz2(nz2(:)<-1) = -1;
% Find
wall =
for c4
if
association
zeros(size(ac));
= 1:size(wall,2)
ac(c4) == 1
de = abs( (D-D2(c4)) ./ ( 0.01 * D ));
xe = abs((nx-nx2(c4)) ./ 0.05);
ze = abs((nz-nz2(c4)) ./ 0.05);
C = de + xe + ze;
[mval mind] = min(C);
wall(c4) = mind;
end
end
% Optimization
m = [db3 dd3 dc3]
[E mval] = fminsearch( @(t) cost(t,Eold,m), E );
mo
% Display visible walls
for c3 = 1:size(L1,2)
plot( [L1(1,c3) L2(1,c3)], [L1(2,c3) L2(2,c3)], 'b' );
if ac(c3)
plot( [L1(1,c3) L2(1,c3)], [L1(2,c3) L2(2,c3)], 'r' );
end
end
% Display current position
quiver( T(1), T(2), 10*cos(T(3)), 10*sin(T(3)), 'g' );
quiver( R(1), R(2), 10*cos(R(3)), 10*sin(R(3)), 'b' );
quiver( E(1), E(2), 10*cos(E(3)), 10*sin(E(3)), 'c' );
drawnow;
end
end
function [ dx dy da db dd dc ] = move1( a, dt, wb, vl, vr )
%
sf = 0.00588; % m/s per motor speed unit ( 0.00589 a bit to high)
%
vl = vl * sf;
%
vr = vr * sf;
if vl == vr
da = 0;
Industrieel VisieLab:
[email protected] and
[email protected]
133
Association University and University Colleges Antwerp.
l
dx
dy
db
dd
dc
=
=
=
=
=
=
RGBd, ToF !
Final Report IWT 2012.
vl * dt;
l * cos(a);
l * sin(a);
0;
l;
0;
else
v
r
da
dx1
dy1
dx
dy
=
=
=
=
=
=
=
( vr + vl ) / 2;
( vr * wb ) / ( vr - vl ) - wb/2;
v / r * dt;
r * sin(da);
r - r * cos(da);
cos(a) * dx1 - sin(a) * dy1;
sin(a) * dx1 + cos(a) * dy1;
ta = atan2(dy,dx);
if abs(ta) > 2*pi
tms = fix(ta/(2*pi)) + sign(ta);
ta = ta - tms*2*pi;
end
if abs(ta) > pi
ta = ta - sign(ta)*2*pi;
end
db = ta - a;
if abs(db) > 2*pi
tms = fix(db/(2*pi)) + sign(db);
db = db - tms*2*pi;
end
if abs(db) > pi
db = db - sign(db)*2*pi;
end
dd = sqrt((dx)^2+(dy)^2);
dc = ta - a;
if abs(dc) > 2*pi
tms = fix(dc/(2*pi)) + sign(dc);
dc = dc - tms*2*pi;
end
if abs(dc) > pi
dc = dc - sign(dc)*2*pi;
end
end
function C = cost( t, E, m )
global wall L1 L2 D2 nx2 nz2 mo;
ET = [cos(t(3)) -sin(t(3)) t(1);
sin(t(3)) cos(t(3)) t(2);
0
0
1];
LT1 = ET \ L1;
LT2 = ET \ L2;
% Cross product
u = LT1(2,:) .* LT2(3,:) - LT1(3,:) .* LT2(2,:);
v = LT1(3,:) .* LT2(1,:) - LT1(1,:) .* LT2(3,:);
w = LT1(1,:) .* LT2(2,:) - LT1(2,:) .* LT2(1,:);
D
nx
nz
C
= abs( w ) ./ sqrt( u.^2 + v.^2 );
= -sin( atan2( v, u ) );
= -cos( atan2( v, u ) );
= 0;
Industrieel VisieLab:
[email protected] and
[email protected]
134
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
for c4 = 1:size(wall,2)
if wall(c4) ~= 0
de = abs(( D(wall(c4))- D2(c4)) ./ ( 0.01 * D(wall(c4)) ));
xe = abs((nx(wall(c4))-nx2(c4)) ./ 0.05);
ze = abs((nz(wall(c4))-nz2(c4)) ./ 0.05);
C = C + de + xe + ze;
end
end
ta = atan2(t(2)-E(2),t(1)-E(1));
if abs(ta) > 2*pi
tms = fix(ta/(2*pi)) + sign(ta);
ta = ta - tms*2*pi;
end
if abs(ta) > pi
ta = ta - sign(ta)*2*pi;
end
dbl = ta - E(3);
if abs(dbl) > 2*pi
tms = fix(dbl/(2*pi)) + sign(dbl);
dbl = dbl - tms*2*pi;
end
if abs(dbl) > pi
dbl = dbl - sign(dbl)*2*pi;
end
ddl = sqrt((E(1)-t(1))^2+(E(2)-t(2))^2);
dcl = t(3) - ta;
if abs(dcl) > 2*pi
tms = fix(dcl/(2*pi)) + sign(dcl);
dcl = dcl - tms*2*pi;
end
if abs(dcl) > pi
dcl = dcl - sign(dcl)*2*pi;
end
mo = [dbl ddl dcl];
C = C * ( 1 + ( (dbl-m(1))^2 + 100*(ddl-m(2))^2 + (dcl-m(3))^2 ) );
Industrieel VisieLab:
[email protected] and
[email protected]
135
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
11. AGV sturing
We gebruiken het eerder besproken ‘wave front’ algoritme om van een gekende locatie ‘A’ naar
een willekeurige locatie ‘B’ te rijden. Er wordt gebruik gemaakt van een eenvoudige sturing die
‘bijstuurt’ aan de hand van de hoekfout ten opzichte van de ideale rijrichting. De sturing bevat
een proportionele en een integrerende term.
function AGVsturing()
% Prepare new session
clear all; close all; clc;
% Parameters
wb = 36.5;
v = 20;
dt = 0.1;
wf = 0.5;
vf = 1;
v_err = 0;
l_err = 0;
%
%
%
%
%
%
%
Vehicle wheelbase (cm)
Vehicle speed (units in motor controller)
Simulation time step (s)
Weigth factor of distance vectorfield
Turn vector field display on or off
Speed error
Localization error
% Display
hh = 10;
oc = [0.5
fc = [0.7
vc = [0.4
%
%
%
%
Wall and object height
Object color
Floor color
Vehicle color
parameters
0.5 0.5];
0.7 0.7];
0.7 1.0];
% Generate new map
map = false(120,250);
Industrieel VisieLab:
% 240 * 500 cm
[email protected] and
[email protected]
136
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
12. Camera calibrations:
12.1.
ToF Camera kalibratie
function camcal()
% Kalibreer camera aan de hand van een foto van een vlak
% Resultaat: gekende interne parameters + rotaties rond camera x en y - as
% TODO: uitbreiding om rotatie rond 'z'-as en translatie ten opzichte van het wereld
assenstelsel mee op te nemen
% TODO: programma uitvoeren met foto's van vlakker calibratie vlak
clear all; close all; clc;
start_values = [ 79 0 0];
%start_values = [ 85.7 -3.2 3.5];
P = start_values;
for c1 = 1:20
c1
filename = strcat( 'camcal', num2str(c1), '.mat' );
load(filename, 'D' );
% Focal Length, Center1, Center2
tic;
[P cost] = fminsearch( @(x) costfunction(x), P )
toc;
end
function res = costfunction(k)
global D x y z;
f = k(1);%79.5;
I = 64; J = 50;
I2 = I/2; J2 = J/2;
ff = f * f;
c1 = k(2); c2 = k(3);
u = (1:J) - (J2+0.5) + c1; uu = u .* u;
v = (1:I) - (I2+0.5) + c2; vv = v .* v;
U = repmat( u , [I 1]);
UU = repmat( uu, [I 1]);
V = repmat( v', [1 J]);
VV = repmat( vv',[1 J]);
UUff = UU + ff;
d = sqrt( VV + UUff );
% Calculate XYZ
Dd = D ./ d;
x
= U .* Dd;
y
= -V .* Dd;
z
= f * Dd;
xl = x(6:end-5,6:end-5); yl = y(6:end-5,6:end-5); zl = z(6:end-5,6:end-5);
X = xl(:); Y = yl(:); Z = zl(:);
Industrieel VisieLab:
[email protected] and
[email protected]
137
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
% Vlak door punten schatten
XYZ = cat(1,X',Y',Z');
P2 = plane(XYZ);
P2 = P2 ./ P2(4);
% Normaal van vlak
nt = sqrt(P2(1)^2+P2(2)^2+P2(3)^2);
n = P2(1:3)./nt;
% Rotatiematrix om vlak horizontaal te leggen
R = [ 1-n(1)^2
0
n(1);
0
1-n(2)^2
n(2);
n(1)
n(2)
n(3) ];
XYZr = R * XYZ;
% Rotatie en translatie in één stap uitvoeren
P = cat(2, R, [0; 0; -mean(XYZr(3,:))] );
XYZ2 = cat(1, XYZ, ones(1,size(XYZ,2)));
XYZtest = P * XYZ2;
% Std van Z waarden als maat van vlakheid
res = std(XYZtest(3,:));
function B = plane(XYZ)
[rows,npts] = size(XYZ);
if rows ~=3
error('data is not 3D');
end
if npts < 3
error('too few points to fit plane');
end
% Set up constraint equations of the form AB = 0,
% where B is a column vector of the plane coefficients
% in the form
b(1)*X + b(2)*Y +b(3)*Z + b(4) = 0.
A = [XYZ' ones(npts,1)]; % Build constraint matrix
if npts == 3
A = [A; zeros(1,4)];
end
% Pad A with zeros
[u d v] = svd(A);
B = v(:,4);
% Singular value decomposition.
% Solution is last column of v.
Industrieel VisieLab:
[email protected] and
[email protected]
138
Association University and University Colleges Antwerp.
12.2.
RGBd, ToF !
Final Report IWT 2012.
Calibration: Color relative to TOF camera.
% Prepare new session
clear all; close all; clc;
% Load data
load XYZ
load RGBd_tof_corners
X
Y
Z
D
=
=
=
=
XYZ(1,:,:); X = X(:);
XYZ(2,:,:); Y = Y(:);
XYZ(3,:,:); Z = Z(:);
corners_D(:,2:25); D = 1000 * D(:);
%
%
%
%
Select data-subset
a1 = 1; a2 = 20;
p1 = a1*80+1; p2 = a2*80;
X = X(p1:p2); Y = Y(p1:p2); Z = Z(p1:p2); D = D(p1:p2);
% Find translation vector: Minimalize cost function
startpoint = [80 0 0];
minfunc = @(t) sum((( X + t(1) ).^2 + ( Y + t(2) ).^2 + ( Z + t(3) ).^2 - D.^2) .^2) ;
[t2 t_cost] = fminsearch( minfunc , startpoint )
%
u
v
x
Find intrinsic parameters of TOF camera
= corners(1,:,2:25); u = u(:) / 10;
= corners(2,:,2:25); v = v(:) / 10;
= cat(2, u, v, ones(size(u)) );
% Iterate to refine translation and TOF internal parameters
for c2 = 1:10
A = []; b = [];
for c1 = 1 : size(X(:))
A = cat(1,A,[ (X(c1)+t2(1))/(Z(c1)+t2(3)) 0 1 0; 0 (Y(c1)+t2(2))/(Z(c1)+t2(3)) 0 1 ]);
b = cat( 1, b, [ u(c1); v(c1) ]);
end
P = A \ b
temp = inv([P(1) 0 P(3); 0 P(2) P(4); 0 0 1]) * x';
n = sqrt( temp(1,:).^2 + temp(2,:).^2 + temp(3,:).^2 );
n = repmat( n, [3 1]);
d = repmat( D', [3 1]);
xyz = d .* temp ./ n;
t2 = [ mean(xyz(1,:)-X') mean(xyz(2,:)-Y') mean(xyz(3,:)-Z') ]
end
% Nearest Neighbours (later: using voronoi diagram)
% Trasform distance to XYZ
load('RGBd'); D = D(:,:,12); L = L(:,:,12); rgb = rgb(:,:,:,12);
errorp = D < 0; D(errorp) = 5;
Industrieel VisieLab:
[email protected] and
[email protected]
139
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
ups = 1;
% Upscale to achieve higher color resolution (use 2, 3, ...)
D = interp2(D,ups);
L = interp2(L,ups);
[I J] = size(D);
u = repmat( 0:J-1, [I 1] );
v = repmat( (0:I-1)', [1 J] );
u = u(:); v = v(:); D = D(:);
x = cat(2, u, v, ones(size(u)) );
temp = inv([2^(ups)*P(1) 0 2^(ups)*P(3); 0 2^(ups)*P(2) 2^(ups)*P(4); 0 0 1]) * x';
n = sqrt( temp(1,:).^2 + temp(2,:).^2 + temp(3,:).^2 );
n = repmat( n, [3 1] );
d = repmat( D', [3 1] );
xyz = d .* temp ./ n;
figure(100);
surf(reshape(xyz(1,:),I,J),reshape(xyz(2,:),I,J),reshape(xyz(3,:),I,J),L,'LineStyle', 'None');
xlim( [-0.3 0.3] ); ylim( [-0.3 0.3] ); zlim( [0.4 1] );
xlabel( 'X' ); ylabel( 'Y' ); zlabel( 'Z' );
daspect( [1 1 1] ); colormap( 'gray' );
cameratoolbar( 'Show' ); cameratoolbar( 'SetMode', 'Orbit' );
title( '3D reconstruction in TOF camera coordinates' );
set(gca,'ZDir','reverse'); view(180,45);
%
x
y
z
Transform from TOF coordinate system to RGB coordinate system
= xyz(1,:)*1000 - t2(1);
= xyz(2,:)*1000 - t2(2);
= xyz(3,:)*1000 - t2(3);
% Focal Length:
f = [ 1153.99786
1154.35200 ];
% Principal point:
c = [ 485.32366
582.87738 ];
% Distortion:
kc = [ -0.18174
0.15183
-0.00045
0.00201
0.00000 ];
% Project 3D coordinates onto color image
a = x./z; b = y./z;
r = sqrt(a.^2 + b.^2);
xx = a .* (1 + kc(1)*r.^2 + kc(2).*r.^4)
yy = b .* (1 + kc(1)*r.^2 + kc(2).*r.^4)
+
+
2*kc(3)*a.*b + kc(4)*(r.^2 + 2*a.^2);
kc(3)*(r.^2 + 2*b.^2) + 2*kc(4)*a.*b;
xxp = f(1)*xx + c(1); xxp = max(xxp, 1); xxp = min(xxp, size(rgb,2));
yyp = f(2)*yy + c(2); yyp = max(yyp, 1); yyp = min(yyp, size(rgb,1));
figure(1);
imshow( rgb ); hold on;
plot( xxp, yyp, 'r+' ); title('TOF 3D points projected onto color image');
% Assign color to TOF pixels
C = zeros( size(xxp(:)),3 );
for c1=1:size(xxp(:))
C(c1,:) = rgb( round(yyp(c1)), round(xxp(c1)), : );
end
Industrieel VisieLab:
[email protected] and
[email protected]
140
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
figure(2);
surf( reshape(xyz(1,:),I,J), reshape(xyz(2,:),I,J), reshape(xyz(3,:),I,J),
reshape(C/255,I,J,3), 'LineStyle', 'None' );
xlim( [-0.3 0.3] ); ylim( [-0.3 0.3] ); zlim( [0.4 1] );
xlabel( 'X' ); ylabel( 'Y' ); zlabel( 'Z' );
daspect( [1 1 1] );
cameratoolbar( 'Show' ); cameratoolbar( 'SetMode', 'Orbit' );
title( '3D + color reconstruction' );
set(gca,'ZDir','reverse'); view(180,45);
%
%
%
%
%
%
%
%
%
%
%
%
dt =
NN =
rgbu
rgbv
DelaunayTri(xxp(:),yyp(:));
zeros(size(rgb,1),size(rgb,2));
= repmat( [0:size(rgb,2)-1], [size(rgb,1) 1]);
= repmat( [0:size(rgb,1)-1]', [1 size(rgb,2)]);
NN = dt.nearestNeighbor([rgbu(:) rgbv(:)]);
X = xyz(1,NN)';
Y = xyz(2,NN)';
Z = xyz(3,NN)';
C = reshape(double(rgb), [size(rgb,1)*size(rgb,2) 3]) / 255;
figure(3);
scatter3( X(1:100:end), Y(1:100:end), Z(1:100:end), 10, C(1:100:end,:) );
Color to Depth
Industrieel VisieLab:
Depth to Color
[email protected] and
[email protected]
141
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
13. Halcon ( Industrial Vision Package of MVTec (www.mvtec.com )).
13.1.
Halcon in combination with IFM O3D201 (ifm-electronic)
* IWT TETRA RGBd, ToF!
* IFM O3D201 data acquisition demo
* Wim Abbeloos & Luc Mertens
* Turn update off
dev_update_off ()
* Camera
CamIP
XMLPort
DataPort
connection parameters
:= '192.168.0.69'
:= 8080
:= 50002
* Camera
ModFreq
SampMode
IlluMode
IntTime1
IntTime2
Delay
settings
:= 0
:= 0
:= 3
:= 500
:= 500
:= 141
* Camera control settings
Trigger := 3
* Image processing settings
MeanFilt
:= 0
MedianFilt := 0
Averaging := 1
* Convert parameter values to strings
tuple_string (ModFreq, 'd', ModFreqStr)
tuple_string (SampMode, 'd', SampModeStr)
tuple_string (IlluMode, 'd', IlluModeStr)
tuple_string (IntTime1, 'd', IntTime1Str)
tuple_string (IntTime2, 'd', IntTime2Str)
tuple_string (Delay,
'd',
DelayStr)
tuple_string (XMLPort, 'd', XMLPortStr)
tuple_string (Trigger, 'd', TriggerStr)
tuple_string (MeanFilt,
'd',
MeanFiltStr)
tuple_string (MedianFilt, 'd', MedianFiltStr)
tuple_string (Averaging, 'd', AveragingStr)
* Close windows
dev_close_window ()
dev_close_window ()
* Open new graphics windows
dev_open_window (0,
0, 50*6, 64*6, 'black', WindowHandle1)
dev_open_window (0, 500, 50*6, 64*6, 'black', WindowHandle2)
* Create blank images
gen_image_const (Dimg,
gen_image_const (Limg,
gen_image_const (ximg,
gen_image_const (yimg,
gen_image_const (zimg,
Industrieel VisieLab:
'real',
'real',
'real',
'real',
'real',
50,
50,
50,
50,
50,
64)
64)
64)
64)
64)
[email protected] and
[email protected]
142
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
* Create indexing tuples
dev_update_off ()
s := []
l := []
for sindex := 0 to 49 by 1
for lindex := 0 to 63 by 1
s := [s, sindex]
l := [l, lindex]
endfor
endfor
* Open XML and data sockets
open_socket_connect (CamIP, XMLPort, ['protocol','timeout'], ['TCP',0.2],
XMLSocket)
open_socket_connect (CamIP, DataPort, ['protocol','timeout'], ['TCP',0.2],
DataSocket)
wait_seconds(0.1)
* Disconnect camera
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLDisconnectCP</methodName>\r\n<params
><param><value>'+CamIP+'</value></param><param><value><i4>1</i4></value></
param></params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive disconnect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', DisconnectData, From10)
* Connect to camera
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLConnectCP</methodName>\r\n<params><p
aram><value>'+CamIP+'</value></param><param><value><i4>1</i4></value></par
am></params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive connect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', ConnectData, From1)
* Set program
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLSetProgram</methodName>\r\n<params><
param><value><i4>0</i4></value></param><param><value><i4>0</i4></value></p
aram><param><value><i4>7</i4></value></param></params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive connect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
Industrieel VisieLab:
[email protected] and
[email protected]
143
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
receive_data (XMLSocket, 'z', SetProgram, FromSP)
* Set triggering
body := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost:
'+CamIP+':'+XMLPortStr+'\r\nContent-Type: text/xml\r\nContent-length:
247\r\n\r\n<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLSetTrigger</methodName>\r\n<params><
param>\r\n\t<value><i4>0</i4></value></param><param>\r\n\t<value><i4>0</i4
></value></param><param>\r\n\t<value><i4>'+TriggerStr+'</i4></value></para
m></params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive connect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', SetCtTriggerData, From2)
* Set averaging
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLSetAverageDetermination</methodName>
\r\n<params><param><value><i4>0</i4></value></param><param><value><i4>0</i
4></value></param><param><value><i4>'+AveragingStr+'</i4></value></param><
/params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive connect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', SetAverage, FromAv)
* Set median
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLSetMedianFilterStatus</methodName>\r
\n<params><param><value><i4>'+MedianFiltStr+'</i4></value></param></params
></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive connect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', SetMedian, FromMedian)
* Set mean
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLSetMeanFilterStatus</methodName>\r\n
<params><param><value><i4>'+MeanFiltStr+'</i4></value></param></params></m
ethodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
Industrieel VisieLab:
[email protected] and
[email protected]
144
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive connect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', SetMean, FromMean)
* Set camera frontend data
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLSetFrontendData</methodName>\r\n<par
ams><param><value><i4>0</i4></value></param><param><value><i4>'+ModFreqStr
+'</i4></value></param><param><value><i4>'+SampModeStr+'</i4></value></par
am><param><value><i4>0</i4></value></param><param><value><i4>'+IntTime1Str
+'</i4></value></param><param><value><i4>'+IntTime2Str+'</i4></value></par
am><param><value><i4>20</i4></value></param><param><value><i4>'+DelayStr+'
</i4></value></param></params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive frontend data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', SetFrontEndData, Fromx)
* Data acquisition loop
for index := 1 to 100 by 1
* Perform HeartBeat
send_data (XMLSocket, 'z', 'POST /RPC2 HTTP/1.1\r\nUser-Agent:
XMLRPC++ 0.7\r\nHost: '+CamIP+':'+XMLPortStr+'\r\nContent-Type:
text/xml\r\nContent-length: 109\r\n\r\n<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLHeartbeat</methodName>\r\n</methodCa
ll>\r\n', [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', HeartBeatData, FromH)
* Request and receive Distance and Intensity data
send_data (DataSocket, 'z', 'D', [CamIP,DataPort])
receive_data (DataSocket, 'f94',
Dheader, From5)
receive_data (DataSocket, 'f3200', D, From6)
send_data (DataSocket, 'z', 'i', [CamIP,DataPort])
receive_data (DataSocket, 'f94',
Lheader, From7)
receive_data (DataSocket, 'f3200', L, From8)
send_data (DataSocket, 'z', 'x', [CamIP,DataPort])
receive_data (DataSocket, 'f94',
xheader, From7)
receive_data (DataSocket, 'f3200', x, From8)
send_data (DataSocket, 'z', 'y', [CamIP,DataPort])
receive_data (DataSocket, 'f94',
yheader, From7)
receive_data (DataSocket, 'f3200', y, From8)
send_data (DataSocket, 'z', 'z', [CamIP,DataPort])
receive_data (DataSocket, 'f94',
zheader, From7)
receive_data (DataSocket, 'f3200', z, From8)
* Add new data to images and display
set_grayval (Dimg, l, s, D)
set_grayval (Limg, l, s, L)
set_grayval (ximg, l, s, x)
set_grayval (yimg, l, s, y)
set_grayval (zimg, l, s, z)
dev_set_window(WindowHandle1)
Industrieel VisieLab:
[email protected] and
[email protected]
145
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
dev_display(Dimg)
dev_set_window(WindowHandle2)
dev_display(Limg)
endfor
* Disconnect camera and close XML and Data sockets
body := '<?xml version="1.0" encoding="UTF8"?>\r\n<methodCall><methodName>MDAXMLDisconnectCP</methodName>\r\n<params
><param><value>'+CamIP+'</value></param><param><value><i4>1</i4></value></
param></params></methodCall>\r\n'
* Get message length
tuple_strlen (body, Length)
* Create header
header := 'POST /RPC2 HTTP/1.1\r\nUser-Agent: XMLRPC++ 0.7\r\nHost: ' +
CamIP + ':' + XMLPortStr + '\r\nContent-Type: text/xml\r\nContent-length:
' + Length + '\r\n\r\n'
* Send and receive disconnect data
send_data (XMLSocket, 'z', header+body, [CamIP,XMLPort])
wait_seconds(0.1)
receive_data (XMLSocket, 'z', DisconnectData, From10)
send_data (DataSocket, 'z', 'q', [CamIP,DataPort])
close_socket (DataSocket)
close_socket (XMLSocket)
* Convert last x/y/z image to object model and store for further
processing
xyz_to_object_model_3d (ximg, yimg, zimg, ObjectModel3DID)
write_object_model_3d (ObjectModel3DID, 'om3', 'ObjectModel1', [], [])
* Save all images
write_image (Dimg,
write_image (Limg,
write_image (ximg,
write_image (yimg,
write_image (zimg,
'tiff',
'tiff',
'tiff',
'tiff',
'tiff',
Industrieel VisieLab:
0,
0,
0,
0,
0,
'Dimg')
'Limg')
'ximg')
'yimg')
'zimg')
[email protected] and
[email protected]
146
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
13.2. Halcon in combination with Mesa SR4000
( www.mesa.com )
* Example for the usage of the SwissRanger interface
close_all_framegrabbers ()
* check interface revision
info_framegrabber ('SwissRanger', 'revision', RevInfo, RevInfoValues)
* check actual configuration
info_framegrabber ('SwissRanger', 'info_boards', BoardInfo,
BoardInfoValues)
* select camera type ('usb' or 'eth')
CamType := 'eth'
* camera ip
CamIP := '192.168.1.33'
* Set camera integration time
IntegrationTime := 45
* open camera
open_framegrabber ('SwissRanger', 1, 1, 0, 0, 0, 0, 'default', -1,
'default', -1, 'false', CamType, CamIP, 0, -1, AcqHandle)
* open some graphics windows
get_framegrabber_param (AcqHandle, 'image_width', Width)
get_framegrabber_param (AcqHandle, 'image_height', Height)
dev_close_window ()
dev_close_window ()
dev_close_window ()
dev_close_window ()
dev_close_window ()
dev_close_window ()
dev_close_window ()
dev_open_window (0, 0, Width*2, Height*2, 'black', WindowID1)
dev_open_window (0, Width*2+20, Width*2, Height*2, 'black', WindowID2)
dev_open_window (0, Width*4+40, Width*2, Height*2, 'black', WindowID3)
dev_open_window (Height*2+60, 0, Width*2, Height*2, 'black', WindowID4)
dev_open_window (Height*2+60, Width*2+20, Width*2, Height*2, 'black',
WindowID5)
dev_open_window (Height*2+60, Width*4+40, Width*2, Height*2, 'black',
WindowID6)
dev_update_off()
* query available parameter names
get_framegrabber_param (AcqHandle, 'available_param_names',
ParameterNames)
* query current integration time
*get_framegrabber_param (AcqHandle, 'integration_time', IntegrationTime)
* Set integration time
set_framegrabber_param (AcqHandle, 'integration_time', IntegrationTime)
* use grab_data[_async] to acquire all images (as float / UINT2 images)
Industrieel VisieLab:
[email protected] and
[email protected]
147
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
* query current acquire mode
get_framegrabber_param (AcqHandle, 'acquire_mode', AcquireMode)
* turn on confidence image
tuple_bor (AcquireMode, 256, AcquireModeWithConf)
set_framegrabber_param (AcqHandle, 'acquire_mode', AcquireModeWithConf)
for i := 1 to 20 by 1
grab_data (ImageData, Region, Contours, AcqHandle, Data)
count_obj (ImageData, NumImageData)
*
select_obj (ImageData, ImageX, 1)
dev_set_window (WindowID1)
dev_display (ImageX)
disp_message (WindowID1, 'grab_data: calibrated x image (float)',
'window', 10, 10, 'black', 'true')
*
select_obj (ImageData, ImageY, 2)
dev_set_window (WindowID2)
dev_display (ImageY)
disp_message (WindowID2, 'grab_data: calibrated y image (float)',
'window', 10, 10, 'black', 'true')
*
select_obj (ImageData, ImageZ, 3)
dev_set_window (WindowID3)
dev_display (ImageZ)
disp_message (WindowID3, 'grab_data: calibrated z image (float)',
'window', 10, 10, 'black', 'true')
*
select_obj (ImageData, DistanceImage, 4)
dev_set_window (WindowID4)
dev_display (DistanceImage)
disp_message (WindowID4, 'grab_data: distance image (uint2)',
'window', 10, 10, 'black', 'true')
*
select_obj (ImageData, AmplitudeImage, 5)
dev_set_window (WindowID5)
dev_display (AmplitudeImage)
disp_message (WindowID5, 'grab_data: amplitude image (uint2)',
'window', 10, 10, 'black', 'true')
*
if (NumImageData > 5)
select_obj (ImageData, ConfidenceImage, 6)
dev_set_window (WindowID6)
dev_display (ConfidenceImage)
disp_message (WindowID6, 'grab_data: confidence image (uint2)',
'window', 10, 10, 'black', 'true')
endif
endfor
close_framegrabber (AcqHandle)
* convert last x/y/z image to object model and store for further
processing
xyz_to_object_model_3d (ImageX, ImageY, ImageZ, ObjectModel3DID)
write_object_model_3d (ObjectModel3DID, 'om3', 'ObjectModel1', [], [])
Industrieel VisieLab:
[email protected] and
[email protected]
148
Association University and University Colleges Antwerp.
13.3.
RGBd, ToF !
Final Report IWT 2012.
Halcon used on an AGV in combination with a MESA SR4000.
dev_close_window ()
*
* Parameters
speedl0 := [0,49,0]
speedr0 := [0,50,0]
speedl1 := [0,49,-10]
disabletimeout := [0,56]
setmode := [0,52,3]
*
close_all_framegrabbers ()
*
* Open camera connection
open_framegrabber ('SwissRanger', 1, 1, 0, 0, 0, 0, 'default', -1,
'default', -1, 'false', 'eth', '192.168.1.33', 0, -1, AcqHandle)
*
* Set integration time to 100
set_framegrabber_param (AcqHandle, 'integration_time', 10)
*
* Get z image
grab_image_async (Image, AcqHandle, -1)
*
* Get Distance
get_grayval (Image, 72, 88, Distance)
*
* DistanceOK
tuple_greater (Distance, 1000, DistanceOK)
*
* Open connection
open_serial ('COM6', SerialHandle)
set_serial_param (SerialHandle,9600, 8, 'none', 'none', 2, 1000, 1000)
*
* Disable time-out
write_serial (SerialHandle, disabletimeout)
* Set mode
write_serial (SerialHandle, setmode)
*
* Stop
write_serial (SerialHandle, speedl0)
write_serial (SerialHandle, speedr0)
*
while (DistanceOK)
* Get z
grab_image_async (Image, AcqHandle, -1)
* Get Distance
get_grayval (Image, 72, 88, Distance)
* DistanceOK
tuple_greater (Distance, 1000, DistanceOK)
* Drive
write_serial (SerialHandle, speedl1)
wait_seconds (0.01)
endwhile
* Stop
write_serial (SerialHandle, speedl0)
* Close connection
close_serial (SerialHandle)
* Close camera connection
close_framegrabber (AcqHandle)
* Display last frame
dev_open_window (0, 0, 176*3, 144*3, 'black', WindowID1)
dev_display (Image)
Industrieel VisieLab:
[email protected] and
[email protected]
149
Association University and University Colleges Antwerp.
RGBd, ToF !
Final Report IWT 2012.
14. Vision & Robotics 2012 demo. Fotonic camera.
Indoor application: free navigation in a known world (map).
function fot_app_VR2()
clear all; close all; clc;
global D L x y z nx ny nz L1 L2 wall ftime cd cnx cnz mo;
% Parameters
wb = 0.3625;
v = 17;
wf = 0.5;
Kp = 1;
Ki = 0;
% Wheel base
% Vehicle speed
% Weight factor of distance vector (to wavefront)
% Define walls
L1 = [ 510 510
0
80
0 36
220;
0 366 366
330 125 125
0];
L2 = [ 510
0
0 36
220;
366 366
330 125
72];
0 390 390 294 294 215
36 ...%140
...%80
0
36
...%366
0 230 366 326 326
...%0
0 510 390 390 294 215 215
36 115 ...%140
0
36
...%80
0 110 366 326 326 366 ...%330
36 ...%72
Industrieel VisieLab:
[email protected] and
[email protected]
150