10.02.2013 Views

HALCON Application Note 1D Metrology - MVTec Software GmbH

HALCON Application Note 1D Metrology - MVTec Software GmbH

HALCON Application Note 1D Metrology - MVTec Software GmbH

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Application</strong> Guide<br />

<strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong><br />

Building Vision for Business


<strong>Application</strong> Guide for <strong>HALCON</strong>, Version 7.1.4.<br />

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or<br />

transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise,<br />

without prior written permission of the publisher.<br />

Edition 1 June 2002 (<strong>HALCON</strong> 6.1)<br />

Edition 1a May 2003 (<strong>HALCON</strong> 6.1.2)<br />

Edition 2 December 2003 (<strong>HALCON</strong> 7.0)<br />

Edition 2a July 2004 (<strong>HALCON</strong> 7.0.1)<br />

Edition 2b April 2005 (<strong>HALCON</strong> 7.0.2)<br />

Edition 3 July 2005 (<strong>HALCON</strong> 7.1)<br />

Edition 3a April 2006 (<strong>HALCON</strong> 7.1.1)<br />

Edition 3b December 2006 (<strong>HALCON</strong> 7.1.2)<br />

Copyright c○ 2002-2008 by <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>, München, Germany <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong><br />

Microsoft, Windows, Windows NT, Windows 2000, Windows XP, Windows 2003, Windows Vista, Visual<br />

Studio, and Visual Basic are either trademarks or registered trademarks of Microsoft Corporation.<br />

Linux is a trademark of Linus Torvalds.<br />

All other nationally and internationally recognized trademarks and tradenames are hereby recognized.<br />

More information about <strong>HALCON</strong> can be found at:<br />

http://www.halcon.com/


Contents<br />

1. <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

The Art of Image Acquisition<br />

2. <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

How to Use Shape-Based Matching to Find and Localize Objects<br />

3. <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

How to Read 2D Data Codes<br />

4. <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

<strong>1D</strong> <strong>Metrology</strong><br />

5. <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Machine Vision in World Coordinates


Provided Functionality<br />

<strong>HALCON</strong> <strong>Application</strong> <strong>Note</strong><br />

The Art of Image Acquisition<br />

⊲ Connecting to simple and complex configurations of frame grabbers and cameras<br />

⊲ Acquiring images in various timing modes<br />

⊲ Configuring frame grabbers and cameras online<br />

Involved Operators<br />

open_framegrabber<br />

info_framegrabber<br />

grab_image, grab_image_async, grab_image_start<br />

set_framegrabber_param, get_framegrabber_param<br />

close_framegrabber, close_all_framegrabbers<br />

gen_image1, gen_image3, gen_image1_extern<br />

Copyright c○ 2002-2008 by <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>, München, Germany <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>


Overview<br />

Obviously, the acquisition of images is a task to be solved in all machine vision applications. Unfortunately,<br />

this task mainly consists of interacting with special, non-standardized hardware in form of the<br />

frame grabber board. To let you concentrate on the actual machine vision problem, <strong>HALCON</strong> already<br />

provides interfaces performing this interaction for a large number of frame grabbers (see section 1 on<br />

page 4).<br />

Within your <strong>HALCON</strong> application, the task of image acquisition is thus reduced to a few lines of code,<br />

i.e., a few operator calls, as can be seen in section 2 on page 5. What’s more, this simplicity is not<br />

achieved at the cost of limiting the available functionality: Using <strong>HALCON</strong>, you can acquire images<br />

from various configurations of frame grabbers and cameras (see section 3 on page 7) in different timing<br />

modes (see section 5 on page 16).<br />

Unless specified otherwise, the example programs can be found in the subdirectory image_acquisition<br />

of the directory <strong>HALCON</strong>ROOT \examples\application_guide. <strong>Note</strong> that most<br />

programs are preconfigured to work with a certain <strong>HALCON</strong> frame grabber interface; in this case,<br />

the name of the program contains the name of the interface. To use the program with another frame<br />

grabber, please adapt the parts which open the connection to the frame grabber. More example programs<br />

for the different <strong>HALCON</strong> frame grabber interfaces can be found in the subdirectory hdevelop\Image\Framegrabber<br />

of the directory %<strong>HALCON</strong>ROOT%\examples.<br />

Please refer to the Programmer’s Guide, chapter 6 on page 57 and chapter 14 on page 107, for information<br />

about how to compile and link the C++ and C example programs; among other things, they describe how<br />

to use the example UNIX makefiles which can be found in the subdirectories c and cpp of the directory<br />

%<strong>HALCON</strong>ROOT%\examples. Under Windows, you can use Visual Studio workspaces containing the<br />

examples, which can be found in the subdirectory i586-nt4 parallel to the source files.<br />

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in<br />

any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written<br />

permission of the publisher.<br />

Edition 1 June 2002 (<strong>HALCON</strong> 6.1)<br />

Edition 2 December 2003 (<strong>HALCON</strong> 7.0)<br />

Microsoft, Windows, Windows NT, Windows 2000, Windows XP, Visual Studio, and Visual Basic are either trademarks<br />

or registered trademarks of Microsoft Corporation.<br />

Linux is a trademark of Linus Torvalds.<br />

All other nationally and internationally recognized trademarks and tradenames are hereby recognized.<br />

More information about <strong>HALCON</strong> can be found at:<br />

http://www.halcon.com/


Contents<br />

1 The Philosophy Behind the <strong>HALCON</strong> Frame Grabber Interfaces 4<br />

2 A First Example 5<br />

3 Connecting to Your Frame Grabber 7<br />

3.1 Opening a Connection to a Specified Configuration . . . . . . . . . . . . . . . . . . . . 7<br />

3.2 Connecting to Multiple Boards and Cameras . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

3.3 Requesting Information About the Frame Grabber Interface . . . . . . . . . . . . . . . . 11<br />

4 Configuring the Acquisition 12<br />

4.1 General Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

4.2 Special Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

4.3 Fixed vs. Dynamic Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

5 The Various Modes of Grabbing Images 16<br />

5.1 Real-Time Image Acquisition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

5.2 Using an External Trigger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

5.3 Acquiring Images From Multiple Cameras . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

6 Miscellaneous 29<br />

6.1 Acquiring Images From Unsupported Frame Grabbers . . . . . . . . . . . . . . . . . . 29<br />

6.2 Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

6.3 Line Scan Cameras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

A <strong>HALCON</strong> Images 37<br />

A.1 The Philosophy of <strong>HALCON</strong> Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

A.2 Image Tuples (Arrays) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

A.3 <strong>HALCON</strong> Operators for Handling Images . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

B Parameters Describing the Image 40<br />

B.1 Image Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />

B.2 Frames vs. Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41<br />

B.3 Image Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

3


4 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

1 The Philosophy Behind the <strong>HALCON</strong> Frame Grabber Interfaces<br />

From the point of view of a user developing software for a machine vision application, the acquisition<br />

of images is only a prelude to the actual machine vision task. Of course it is important that images are<br />

acquired at the correct moment or rate, and that the camera and the frame grabber are configured suitably,<br />

but these tasks seem to be elementary, or at least independent of the used frame grabber.<br />

The reality, however, looks different. Frame grabbers differ widely regarding the provided functionality,<br />

and even if their functionality is similar, the SDKs (software development kit) provided by the frame<br />

grabber manufacturers do not follow any standard. Therefore, switching to a different frame grabber<br />

probably requires to rewrite the image acquisition part of the application.<br />

<strong>HALCON</strong>’s answer to this problem are its frame grabber interfaces (HFGI) which are provided for<br />

currently more than 50 frame grabbers in form of dynamically loadable libraries (Windows: DLLs;<br />

UNIX: shared libraries). <strong>HALCON</strong> frame grabber interfaces bridge the gap between the individual<br />

frame grabbers and the <strong>HALCON</strong> library, which is independent of the used frame grabber, computer<br />

platform, and programming language (see figure 1). In other words, they<br />

• provide a standardized interface to the <strong>HALCON</strong> user in form of 11 <strong>HALCON</strong> operators, and<br />

• encapsulate details specific to the frame grabber, i.e., the interaction with the frame grabber SDK<br />

provided by the manufacturer.<br />

Therefore, if you decide to switch to a different frame grabber, all you need to do is to install the corresponding<br />

driver and SDK provided by the manufacturer and to use different parameter values when<br />

calling the <strong>HALCON</strong> operators; the operators themselves stay the same.<br />

camera<br />

computer<br />

frame<br />

grabber<br />

software<br />

Figure 1: From the camera to a <strong>HALCON</strong> application.<br />

<strong>HALCON</strong> application<br />

HDevelop / C / C++ / C# / Visual Basic<br />

<strong>HALCON</strong> image processing library<br />

halcon.dll & halconc/cpp/dotnet/x.dll<br />

<strong>HALCON</strong> xyz acquisition interface<br />

hAcqxyz.dll<br />

device driver & SDK<br />

In fact, the elementary tasks of image acquisition are covered by two <strong>HALCON</strong> operators:<br />

• open_framegrabber connects to the frame grabber and sets general parameters, e.g., the type of<br />

the used camera or the port the camera is connected to, then<br />

• grab_image (or grab_image_async, see section 5.1 on page 16 for the difference) grabs images.<br />

If a frame grabber provides additional functionality, e.g., on-board modification of the image signal, special<br />

grabbing modes, or digital output lines, it is available via the operator set_framegrabber_param<br />

(see section 4 on page 12).


a)<br />

Figure 2: a) Acquired image; b) processed image (automatic segmentation).<br />

b)<br />

2 A First Example 5<br />

<strong>Note</strong>, that for some frame grabbers the full functionality is not available within <strong>HALCON</strong>; please refer<br />

to the corresponding online documentation which can be found in the directory %<strong>HALCON</strong>ROOT%<br />

\doc\html\manuals or via the <strong>HALCON</strong> folder in the Windows start menu (if you installed the documentation).<br />

The latest information can be found under http://www.halcon.com/framegrabber.<br />

If the frame grabber you want to use is not (yet) supported by <strong>HALCON</strong>, you can nevertheless use it<br />

together with <strong>HALCON</strong>. Please refer to section 6.1 on page 29 for more details.<br />

2 A First Example<br />

In this section we start with a simple image acquisition task, which uses the frame grabber in its default<br />

configuration and the standard grabbing mode. The grabbed images are then segmented. To follow the<br />

example actively, start the HDevelop program hdevelop\first_example_acquisition_ids.dev,<br />

then press Run once to initialize the application. <strong>Note</strong> that the program is preconfigured for the <strong>HALCON</strong><br />

frame grabber interface IDS; to use it with a different frame grabber, please adapt the parts which open<br />

the connection.<br />

Step 1: Connect to the frame grabber<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’gray’, -1,<br />

’false’, ’ntsc’, ’default’, -1, -1, FGHandle)<br />

When opening the connection to your frame grabber using the operator open_framegrabber, the main<br />

parameter is the Name of the corresponding <strong>HALCON</strong> frame grabber interface. As a result, you obtain<br />

a so-called handle (FGHandle), by which you can access the frame grabber, e.g., in calls to the operator<br />

grab_image.<br />

In the example, default values are used for most other parameters (’default’ or -1); section 4.1 on<br />

page 13 takes a closer look at this topic. How to connect to more complex frame grabber and camera<br />

configurations is described in section 3 on page 7.<br />

First Example


6 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Step 2: Grab an image<br />

grab_image (Image, FGHandle)<br />

After successfully connecting to your frame grabber you can grab images by calling the operator<br />

grab_image with the corresponding handle FGHandle. More advanced modes of grabbing images are<br />

described in section 5 on page 16.<br />

Step 3: Grab and process images in a loop<br />

while (Button # 1)<br />

grab_image (Image, FGHandle)<br />

auto_threshold (Image, Regions, 4)<br />

connection (Regions, ConnectedRegions)<br />

get_mposition (WindowHandleButton, Row, Column, Button)<br />

endwhile<br />

In the example, the grabbed images are then automatically segmented using the operator<br />

auto_threshold (see figure 2). This is done in a loop which can be exited by clicking into a window<br />

with the left mouse button.


3 Connecting to Your Frame Grabber<br />

3 Connecting to Your Frame Grabber 7<br />

In this section, we show how to connect to different configurations of frame grabber(s) and camera(s),<br />

ranging from the simple case of one camera connected to one frame grabber board to more complex<br />

ones, e.g., multiple synchronized cameras connected to one or more boards.<br />

3.1 Opening a Connection to a Specified Configuration<br />

With the operator open_framegrabber you open a connection to a frame grabber, or to be more exact,<br />

via a frame grabber to a camera. This connection is described by four parameters (see figure 3): First,<br />

you select a frame grabber (family) with the parameter Name. If multiple boards are allowed, you can<br />

select one with the parameter Device; depending on the frame grabber interface, this parameter can<br />

contain a string describing the board or simply a number (in form of a string!).<br />

Typically, the camera can be connected to the frame grabber at different ports, whose number can be<br />

selected via the parameter Port (in rare cases LineIn). The parameter CameraType describes the<br />

connected camera: For analog cameras, this parameter usually specifies the used signal norm, e.g.,<br />

’ntsc’; more complex frame grabber interfaces use this parameter to select a camera configuration file.<br />

As a result, open_framegrabber returns a handle for the opened connection in the parameter FGHandle.<br />

<strong>Note</strong> that if you use <strong>HALCON</strong>’s COM or C ++ interface and call the operator via the classes<br />

HFramegrabberX or HFramegrabber, no handle is returned because the instance of the class itself acts<br />

as your handle.<br />

In HDevelop, you can quickly check an opened connection by double-clicking FGHandle in the Variable<br />

Window as shown in figure 4. A dialog appears which describes the status of the connection. If you<br />

AcqHandle<br />

which interface?<br />

SDK & IAI A<br />

SDK & IAI B<br />

which device?<br />

frame<br />

grabber<br />

board 0<br />

frame<br />

grabber<br />

board 1<br />

port 0<br />

port 1<br />

port 0<br />

port 1<br />

which port?<br />

Name Device Port CameraType<br />

camera type abc<br />

camera type xyz<br />

which camera?<br />

Figure 3: Describing a connection with the parameters of open_framegrabber .<br />

Connecting


8 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Figure 4: Online grabbing in HDevelop .<br />

check box to start online grabbing<br />

double−click handle to open dialog<br />

check the corresponding box, images are grabbed online and displayed in the Graphics Window. This<br />

mode is very useful to setup your vision system (illumination, focus, field of view).<br />

3.2 Connecting to Multiple Boards and Cameras<br />

Most <strong>HALCON</strong> frame grabber interfaces allow to use multiple frame grabber boards and cameras. However,<br />

there is more than one way to connect cameras and boards and to access these configurations from<br />

within <strong>HALCON</strong>. Below, we describe the different configurations; please check the online documentation<br />

of the <strong>HALCON</strong> interface for your frame grabber (see %<strong>HALCON</strong>ROOT% \doc\html\manuals,<br />

the <strong>HALCON</strong> folder in the Windows start menu, or http://www.halcon.com/framegrabber) which<br />

configurations it supports.<br />

3.2.1 Single Camera<br />

Figure 5a shows the simplest configuration: a single camera connected to a single board, accessible<br />

via a single handle. Some frame grabbers, especially digital ones, only support this configuration; as<br />

described in the following section, you can nevertheless use multiple cameras with such frame grabbers<br />

by connecting each one to an individual board.


a)<br />

c)<br />

e)<br />

handle 0<br />

handle 0<br />

handle 1<br />

handle 2<br />

handle 0<br />

HImage[2]<br />

frame grabber<br />

board 0<br />

frame grabber<br />

board 0<br />

frame grabber<br />

board 1<br />

frame grabber<br />

board 0<br />

port 0<br />

port 0<br />

port 1<br />

port 0<br />

port 0<br />

port 1<br />

b)<br />

d)<br />

f)<br />

handle 0 frame grabber port 0<br />

board 0<br />

handle 1 frame grabber port 0<br />

handle 0<br />

port switch<br />

handle 0<br />

HImage[3]<br />

board 1<br />

frame grabber<br />

board 0<br />

frame grabber<br />

board 0<br />

frame grabber<br />

board 1<br />

3.2.2 Multiple Boards 9<br />

Figure 5: a) single board with single camera; b) multiple boards with one camera each; c) multiple boards<br />

with one or more cameras; d) single board with multiple cameras and port switching; e) single<br />

board with multiple cameras and simultaneous grabbing; f) simultaneous grabbing with multiple<br />

boards and cameras.<br />

3.2.2 Multiple Boards<br />

Figure 5b shows a configuration with multiple cameras, each connected to a separate board. In this case<br />

you call the operator open_framegrabber once for each connection as in the HDevelop example program<br />

hdevelop\multiple_boards_px.dev. <strong>Note</strong> that the program is preconfigured for the <strong>HALCON</strong><br />

PX interface; to use it with a different frame grabber, please adapt the parts which open the connection.<br />

port 0<br />

port 1<br />

port 0<br />

port 1<br />

port 0<br />

Connecting


10 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’default’, ’default’, Board0, -1, -1, FGHandle0)<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’default’, ’default’, Board1, -1, -1, FGHandle1)<br />

In this example, the two calls differ only in the value for the parameter Device (’0’ and ’1’); of course,<br />

you can use different values for other parameters as well, and even connect to different frame grabber<br />

interfaces.<br />

To grab images from the two cameras, you simply call the operator grab_image once with the two<br />

handles returned by the two calls to open_framegrabber:<br />

grab_image (Image0, FGHandle0)<br />

grab_image (Image1, FGHandle1)<br />

3.2.3 Multiple Handles Per Board<br />

Many frame grabbers provide multiple input ports and thus allow to connect more than one camera to the<br />

board. Depending on the <strong>HALCON</strong> frame grabber interface, this configuration is accessed in different<br />

ways which are described in this and the following sections.<br />

The standard <strong>HALCON</strong> method to connect to the cameras is depicted in figure 5c: Each connection<br />

gets its own handle, i.e., open_framegrabber is called once for each camera with different values<br />

for the parameter Port, like in the HDevelop example program hdevelop\multiple_ports_px.dev<br />

(preconfigured for the <strong>HALCON</strong> PX interface, please adapt the parts which open the connection for your<br />

own frame grabber):<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’default’, ’default’, ’default’, Port0, -1, FGHandle0)<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’default’, ’default’, ’default’, Port1, -1, FGHandle1)<br />

grab_image (Image0, FGHandle0)<br />

grab_image (Image1, FGHandle1)<br />

As figure 5c shows, you can also use multiple boards with multiple connected cameras.<br />

3.2.4 Port Switching<br />

Some frame grabber interfaces do not access the cameras via multiple handles, but by switching the<br />

input port dynamically (see figure 5d). Therefore, open_framegrabber is called only once, like in<br />

the HDevelop example program hdevelop\port_switching_inspecta.dev (preconfigured for the<br />

<strong>HALCON</strong> INSPECTA interface, please adapt the parts which open the connection for your own frame<br />

grabber):<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’default’, MyCamType, ’default’, 0, -1, FGHandle)<br />

Between grabbing images you switch ports using the operator set_framegrabber_param (see section<br />

4.2 on page 14 for more information about this operator):


set_framegrabber_param (FGHandle, ’port’, Port0)<br />

grab_image (Image0, FGHandle)<br />

set_framegrabber_param (FGHandle, ’port’, Port1)<br />

grab_image (Image1, FGHandle)<br />

3.2.5 Simultaneous Grabbing 11<br />

<strong>Note</strong> that port switching only works for compatible (similar) cameras because open_framegrabber<br />

is only called once, i.e., the same set of parameters values is used for all cameras. In contrast, when<br />

using multiple handles as described above, you can specify different parameter values for the individual<br />

cameras (with some board-specific limitations).<br />

3.2.5 Simultaneous Grabbing<br />

In the configurations described above, images were grabbed from the individual cameras by multiple<br />

calls to the operator grab_image. In contrast, some frame grabber interfaces allow to grab images<br />

from multiple cameras with a single call to grab_image, which then returns a multi-channel image (see<br />

figure 5e; appendix A.1 on page 37 contains more information about multi-channel images). This mode<br />

is called simultaneous grabbing (or parallel grabbing); like port switching, it only works for compatible<br />

(similar) cameras. For example, you can use this mode to grab synchronized images from a stereo camera<br />

system.<br />

In this mode, open_framegrabber is called only once, as can be seen in the HDevelop example program<br />

hdevelop\simultaneous_grabbing_inspecta.dev (preconfigured for the <strong>HALCON</strong> INSPECTA interface,<br />

please adapt the parts which open the connection for your own frame grabber):<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’default’, MyCamType, ’default’, 0, -1, FGHandle)<br />

You can check the number of returned images (channels) using the operator count_channels<br />

grab_image (SimulImages, FGHandle)<br />

count_channels (SimulImages, num_channels)<br />

and extract the individual images, e.g., using decompose2, decompose3 etc., depending on the number<br />

of images:<br />

if (num_channels = 2)<br />

decompose2 (SimulImages, Image0, Image1)<br />

Alternatively, you can convert the multi-channel image into an image array using image_to_channels<br />

and then select the individual images via select_obj.<br />

<strong>Note</strong> that some frame grabber interfaces allow simultaneous grabbing also for multiple boards (see figure<br />

5f). Please refer to section 5.3.2 on page 28 for additional information.<br />

3.3 Requesting Information About the Frame Grabber Interface<br />

As mentioned already, the individual <strong>HALCON</strong> frame grabber interfaces are described in detail on<br />

HTML pages which can be found in the directory %<strong>HALCON</strong>ROOT% \doc\html\manuals or in the HAL-<br />

CON folder in the Windows start menu (if you installed the documentation). Another way to access<br />

information about a frame grabber interface is to use the operator info_framegrabber.<br />

Connecting


12 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Figure 6: An example result of the operator info_framegrabber .<br />

In the HDevelop example program hdevelop\info_framegrabber_ids.dev (preconfigured for the<br />

<strong>HALCON</strong> IDS interface, please adapt the interface name for your own frame grabber) this operator is<br />

called multiple times to query the version number of the interface, the available boards, port numbers,<br />

camera types, and the default values for all parameters of open_framegrabber; the result, i.e., the<br />

values displayed in the HDevelop Variable Windows, is depicted in figure 6.<br />

info_framegrabber (FGName, ’general’, GeneralInfo, GeneralValue)<br />

info_framegrabber (FGName, ’revision’, RevisionInfo, RevisionValue)<br />

info_framegrabber (FGName, ’info_boards’, BoardsInfo, BoardsValue)<br />

info_framegrabber (FGName, ’ports’, PortsInfo, PortsValue)<br />

info_framegrabber (FGName, ’camera_types’, CamTypeInfo, CamTypeValue)<br />

info_framegrabber (FGName, ’defaults’, DefaultsInfo, DefaultsValue)<br />

The operator info_framegrabber can be called before actually connecting to a frame grabber with<br />

open_framegrabber. The only condition is that the <strong>HALCON</strong> frame grabber interface and the frame<br />

grabber SDK and driver have been installed.<br />

4 Configuring the Acquisition<br />

As explained in section 1 on page 4, the intention of <strong>HALCON</strong>’s frame grabber interfaces is to provide<br />

the user with a common interface for many different frame grabbers. This interface is kept as simple<br />

as possible; as shown, you can connect to your frame grabber and grab a first image using only two<br />

operators.<br />

However, <strong>HALCON</strong>’s second goal is to make the full functionality of a frame grabber available to the<br />

user. As frame grabbers differ widely regarding the provided functionality, this is a difficult task to realize


4.1 General Parameters 13<br />

within a simple, common interface. <strong>HALCON</strong> solves this problem by dividing the task of configuring<br />

a frame grabber connection into two parts: Those parameters which are common to most frame grabber<br />

interfaces (therefore called general parameters) are set when calling the operator open_framegrabber.<br />

In contrast, the functionality which is not generally available can be configured by setting so-called<br />

special parameters using the operator set_framegrabber_param.<br />

4.1 General Parameters<br />

When opening a connection via open_framegrabber, you can specify the following general parameters:<br />

HorizontalResolution,<br />

VerticalResolution<br />

ImageWidth, ImageHeight,<br />

StartRow, StartColumn<br />

spatial resolution of the transferred image in relation to the<br />

original size (see appendix B.1 on page 40)<br />

size and upper left corner of the transferred image in relation<br />

to the original size (see appendix B.1 on page 40)<br />

Field grabbing mode for analog cameras, e.g., interlaced-scan,<br />

progressive-scan, field grabbing (see appendix B.2 on page 41)<br />

BitsPerChannel, ColorSpace data contained in a pixel (number of bits, number of channels,<br />

color encoding, see appendix B.3 on page 44)<br />

Gain amplification factor for the video amplifier on the frame grabber<br />

board (if available)<br />

ExternalTrigger hooking the acquisition of images to an external trigger signal<br />

(see also section 5.2 on page 25)<br />

CameraType, Device, Port,<br />

LineIn<br />

configuration of frame grabber(s) and camera(s) from which<br />

images are to be acquired (see section 3.1 on page 7)<br />

In section 3.1 on page 7, we already encountered the parameters describing the frame grabber / camera<br />

configuration. Most of the other parameters of open_framegrabber specify the image format; they are<br />

described in more detail in appendix B on page 40. The parameter ExternalTrigger activates a special<br />

grabbing mode which is described in detail in section 5.2 on page 25. Finally, the parameter Gain can be<br />

used to manipulate the acquired images on the frame grabber board by configuring the video amplifier.<br />

<strong>Note</strong> that when calling open_framegrabber you must specify values for all parameters, even if your<br />

frame grabber interface does not support some of them or uses values specified in a camera configuration<br />

file instead. To alleviate this task, the <strong>HALCON</strong> frame grabber interfaces provide suitable default values<br />

which are used if you specify ’default’ or -1 for string or numeric parameters, respectively. The actually<br />

used default values can be queried using the operator info_framegrabber as shown in section 3.3<br />

on page 11.<br />

After connecting to a frame grabber, you can query the current value of general parameters using the<br />

operator get_framegrabber_param; some interfaces even allow to modify general parameters dynamically.<br />

Please refer to section 4.3 on page 15 for more information about these topics.<br />

Configuring


14 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

4.2 Special Parameters<br />

Even the functionality which is not generally available for all frame grabber can be accessed and<br />

configured with a general mechanism: by setting corresponding special parameters via the operator<br />

set_framegrabber_param. Typical parameters are, for example:<br />

’grab_timeout’ timeout after which the operators grab_image and<br />

grab_image_async stop waiting for an image and return<br />

an error (see also section 5.2.1 on page 27 and section 6.2<br />

on page 30)<br />

’volatile’ enable volatile grabbing (see also section 5.1.3 on page<br />

18)<br />

’continuous_grabbing’ switch on a special acquisition mode which is necessary<br />

for some frame grabbers to achieve real-time performance<br />

(see also section 5.1.5 on page 22)<br />

’trigger_signal’ signal type used for external triggering, e.g., rising or<br />

falling edge<br />

’image_width’, ’image_height’,<br />

’start_row’, ’start_column’,<br />

’gain’, ’external_trigger’,<br />

’port’<br />

“duplicates” of some of the general parameters described<br />

in section 4.1 on page 13, allowing to modify them dynamically,<br />

i.e., after opening the connection (see also section<br />

4.3)<br />

Depending on the frame grabber, various other parameters may be available, which allow, e.g., to add<br />

an offset to the digitized video signal or modify the brightness or contrast, to specify the exposure time<br />

or to trigger a flash. Some frame grabbers also offer special parameters for the use of line scan cameras<br />

(see also section 6.3 on page 34), or parameters controlling digital output and input lines.<br />

Which special parameters are provided by a frame grabber interface is described in the already mentioned<br />

online documentation. You can also query this information by calling the operator info_framegrabber<br />

as shown below; figure 7 depicts the result of double-clicking ParametersValue in the Variable Window<br />

after executing the line:<br />

info_framegrabber (FGName, ’parameters’, ParametersInfo, ParametersValue)<br />

To set a parameter, you call the operator set_framegrabber_param, specifying the name of the parameter<br />

to set in the parameter Param and the desired value in the parameter Value. For example, in<br />

section 3.2.4 on page 10 the following line was used to switch to port 0:<br />

set_framegrabber_param (FGHandle, ’port’, Port0)<br />

You can also set multiple parameters at once by specifying tuples for Param and Value as in the following<br />

line:<br />

set_framegrabber_param (FGHandle, [’image_width’,’image_height’], [256,<br />

256])<br />

For all parameters which can be set with set_framegrabber_param, you can query the current value<br />

using the operator get_framegrabber_param. Some interfaces also allow to query additional infor-


Figure 7: Querying available special parameters via info_framegrabber .<br />

4.3 Fixed vs. Dynamic Parameters 15<br />

mation like minimum and maximum values for the parameters. For example, the <strong>HALCON</strong> Fire-i<br />

interface allows to query the minimum and maximum values for the brightness:<br />

get_framegrabber_param (FGHandle, ’brightness_min_value’, MinBrightness)<br />

get_framegrabber_param (FGHandle, ’brightness_max_value’, MaxBrightness)<br />

Thus, you can check a new brightness value against those boundaries before setting it:<br />

get_framegrabber_param (FGHandle, ’brightness’, CurrentBrightness)<br />

NewBrightness := CurrentBrightness + 10<br />

if (NewBrightness > MaxBrightness)<br />

NewBrightness := MaxBrightness<br />

endif<br />

set_framegrabber_param (FGHandle, ’brightness’, NewBrightness)<br />

4.3 Fixed vs. Dynamic Parameters<br />

The distinction between fixed and dynamic parameters is made relating to the lifetime of a frame<br />

grabber connection. Fixed parameters, e.g., the CameraType, are set once when opening the<br />

connection with open_framegrabber. In contrast, those parameters which can be modified via<br />

set_framegrabber_param during the use of the connection are called dynamic parameters.<br />

As already noted in section 4.2 on page 14, some frame grabber interfaces allow to modify general<br />

parameters like ImageWidth or ExternalTrigger dynamically via set_framegrabber_param, by<br />

providing a corresponding special parameter with the same name but written with small letters and<br />

underscores, e.g., ’image_width’ or ’external_trigger’.<br />

Independent of whether a general parameter can be modified dynamically, you can query its current value<br />

by calling the operator get_framegrabber_param with its “translated” name, i.e., capitals replaced by<br />

small letters and underscores as described above.<br />

Configuring


16 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

!<br />

5 The Various Modes of Grabbing Images<br />

Section 2 on page 5 showed that grabbing images is very easy in <strong>HALCON</strong> – you just call grab_image!<br />

But of course there’s more to image grabbing than just to get an image, e.g., how to assure an exact<br />

timing. This section therefore describes more complex grabbing modes.<br />

5.1 Real-Time Image Acquisition<br />

As a technical term, the attribute real-time means that a process guarantees that it meets given deadlines.<br />

Please keep in mind that none of the standard operating systems, i.e., neither Windows nor Linux,<br />

are real-time operating systems. This means that the operating system itself does not guarantee that<br />

your application will get the necessary processing time before its deadline expires. From the point of<br />

view of a machine vision application running under a non-real-time operating system, the most you can<br />

do is assure that real-time behavior is not already prevented by the application itself.<br />

In a machine vision application, real-time behavior may be required at multiple points:<br />

Image delay: The camera must “grab” the image, i.e., expose the chip, at the correct moment, i.e., while<br />

the part to be inspected is completely visible.<br />

Frame rate: The most common real-time requirement for a machine vision application is to “reach<br />

frame rate”, i.e., acquire and process all images the camera produces.<br />

Processing delay: The image processing itself must complete in time to allow a reaction to its results,<br />

e.g., to remove a faulty part from the conveyor belt. As this point relates only indirectly to the<br />

image acquisition it is ignored in the following.<br />

5.1.1 Non-Real-Time Grabbing Using grab_image<br />

Figure 8 shows the timing diagram for the standard grabbing mode, i.e., if you use the operator<br />

grab_image from within your application. This operator call is “translated” by the <strong>HALCON</strong> frame<br />

grabber interface and the SDK into the corresponding signal to the frame grabber board (marked with<br />

’Grab’).<br />

The frame grabber now waits for the next image. In the example, a free-running analog progressive-scan<br />

camera is used, which produces images continuously at a fixed frame rate; the start of a new image is<br />

indicated by a so-called vertical sync signal. The frame grabber then digitizes the incoming analog image<br />

signal and transforms it into an image matrix. If a digital camera is used, the camera itself performs the<br />

digitizing and transfers a digital signal which is then transformed into an image matrix by the frame<br />

grabber. Please refer to appendix B.2 on page 41 for more information about interlaced grabbing.<br />

The image is then transferred from the frame grabber into computer memory via the PCI bus using DMA<br />

(direct memory access). This transfer can either be incremental as depicted in figure 8, if the frame<br />

grabber has only a FIFO buffer, or in a single burst as depicted in figure 9 on page 19, if the frame<br />

grabber has a frame buffer on board. The advantage of the incremental transfer is that the transfer is<br />

concluded earlier. In contrast, the burst mode is more efficient; furthermore, if the incremental transfer<br />

via the PCI bus cannot proceed for some reason, a FIFO overflow results, i.e., image data is lost. <strong>Note</strong>


camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

wait for<br />

vsync<br />

delay<br />

image<br />

original<br />

frame rate<br />

create<br />

HImage<br />

original<br />

frame rate<br />

5.1.1 Non-Real-Time Grabbing Using grab_image 17<br />

original<br />

frame rate<br />

expose expose expose expose<br />

digitize<br />

wait for<br />

vsync<br />

digitize<br />

Grab Grab<br />

grab_image<br />

wait for<br />

image<br />

delay image<br />

wait for<br />

image<br />

frame rate<br />

processing<br />

create<br />

HImage<br />

grab_image<br />

process process<br />

Figure 8: Standard timing using grab_image (configuration: free-running progressive-scan camera, frame<br />

grabber with incremental image transfer).<br />

that in both modes the transfer performance depends on whether the PCI bus is used by other devices as<br />

well!<br />

When the image is completely stored in the computer memory, the <strong>HALCON</strong> frame grabber interface<br />

transforms it into a <strong>HALCON</strong> image and returns the control to the application which processes the image<br />

and then calls grab_image again. However, even if the processing time is short in relation to the frame<br />

rate, the camera has already begun to transfer the next image which is therefore “lost”; the application<br />

can therefore only process every second image.<br />

You can check this behavior using the HDevelop example program hdevelop\real_time_grabbing_ids.dev<br />

(preconfigured for the <strong>HALCON</strong> IDS interface, please<br />

adapt the parts which open the connection for your own frame grabber), which determines achievable<br />

frame rates for grabbing and processing (here: calculating a difference image) first separately and then<br />

together as follows:<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

Grabbing


18 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

grab_image (BackgroundImage, FGHandle)<br />

count_seconds (Seconds1)<br />

for i := 1 to 20 by 1<br />

grab_image (Image, FGHandle)<br />

sub_image (BackgroundImage, Image, DifferenceImage, 1, 128)<br />

endfor<br />

count_seconds (Seconds2)<br />

TimeGrabImage := (Seconds2-Seconds1)/20<br />

FrameRateGrabImage := 1 / TimeGrabImage<br />

To see the non-deterministic image delay, execute the operator grab_image in the step mode by pressing<br />

Step; the execution time displayed in HDevelop’s status bar will range between once and twice the<br />

original frame period. Please note that on UNIX systems, the time measurements are performed with a<br />

lower resolution than on Windows systems.<br />

5.1.2 Grabbing Without Delay Using Asynchronously Resettable Cameras<br />

If you use a free-running camera, the camera itself determines the exact moment an image is acquired<br />

(exposed). This leads to a delay between the moment you call grab_image and the actual image acquisition<br />

(see figure 8 on page 17). The delay is not deterministic, but at least it is limited by the frame<br />

rate; for example, if you use an NTSC camera with a frame rate of 30 Hz, the maximum delay can be 33<br />

milliseconds.<br />

Of course, such a delay is not acceptable in an application that is to inspect parts at a high rate. The<br />

solution is to use cameras that allow a so-called asynchronous reset. This means that upon a signal<br />

from the frame grabber, the camera resets the image chip and (almost) immediately starts to expose it.<br />

Typically, such a camera does not grab images continuously but only on demand.<br />

An example timing diagram is shown in figure 9. In contrast to figure 8, the image delay is (almost) zero.<br />

Furthermore, because the application now specifies when images are to be grabbed, all images can be<br />

processed successfully; however, the achieved frame rate still includes the processing time and therefore<br />

may be too low for some machine vision applications.<br />

5.1.3 Volatile Grabbing<br />

As shown in figure 8 on page 17, after the image has been transferred into the computer memory, the<br />

<strong>HALCON</strong> frame grabber interface needs some time to create a corresponding <strong>HALCON</strong> image which is<br />

then returned in the output parameter Image of grab_image. Most of this time (about 3 milliseconds on<br />

a 500 MHz Athlon K6 processor for a gray value NTSC image) is needed to copy the image data from<br />

the buffer which is the destination of the DMA into a newly allocated area.<br />

You can switch off the copying by using the so-called volatile grabbing, which can be enabled via the<br />

operator set_framegrabber_param (parameter ’volatile’):<br />

set_framegrabber_param (FGHandle, ’volatile’, ’enable’)<br />

Then, the time needed by the frame grabber interface to create the <strong>HALCON</strong> image is significantly<br />

reduced as visualized in figure 9. <strong>Note</strong> that usually volatile grabbing is only supported for gray value<br />

images!


camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

application<br />

Expose<br />

wait for<br />

vsync<br />

Grab<br />

software grab_image<br />

delay<br />

image<br />

= 0<br />

original<br />

frame rate<br />

expose expose<br />

digitize<br />

wait for<br />

image<br />

create<br />

HImage<br />

Expose<br />

wait for<br />

vsync digitize<br />

Grab<br />

wait for<br />

image<br />

frame rate<br />

processing<br />

create<br />

HImage<br />

grab_image<br />

process process<br />

5.1.3 Volatile Grabbing 19<br />

Figure 9: Using a asynchronously resettable camera together with grab_image (configuration:<br />

progressive-scan camera, frame grabber with burst transfer, volatile grabbing).<br />

The drawback of volatile grabbing is that grabbed images are overwritten by subsequent grabs. To be<br />

more exact, the overwriting depends on the number of image buffers allocated by the frame grabber interface<br />

or SDK. Typically, at least two buffers exist; therefore, you can safely process an image even if the<br />

next image is already being grabbed as in figure 11 on page 23. Some frame grabber interfaces allow to<br />

use more than two buffers, and even to select their number dynamically via set_framegrabber_param<br />

(parameter ’num_buffers’).<br />

You can check this behavior using the HDevelop example program hdevelop\volatile_grabbing_ids.dev<br />

(preconfigured for the <strong>HALCON</strong> IDS interface, please<br />

adapt the parts which open the connection for your own frame grabber). After grabbing a first image<br />

and displaying it via<br />

grab_image (FirstImage, FGHandle)<br />

dev_open_window (0, 0, Width/2, Height/2, ’black’, FirstWindow)<br />

dev_display (FirstImage)<br />

change the scene and grab a second image which is displayed in an individual window:<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

Grabbing


20 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

!<br />

grab_image (SecondImage, FGHandle)<br />

dev_open_window (0, Width/2 + 8, Width/2, Height/2, ’black’, SecondWindow)<br />

dev_display (SecondImage)<br />

Now, images are grabbed in a loop and displayed in a third window. The two other images are also<br />

displayed each time. If you change the scene before each grab you can see how the first two images are<br />

overwritten in turn, depending on the number of buffers.<br />

dev_open_window (Height/2 + 66, Width/4 + 4, Width/2, Height/2, ’black’,<br />

ThirdWindow)<br />

for i := 1 to 10 by 1<br />

grab_image (CurrentImage, FGHandle)<br />

dev_set_window (ThirdWindow)<br />

dev_display (CurrentImage)<br />

dev_set_window (FirstWindow)<br />

dev_display (FirstImage)<br />

dev_set_window (SecondWindow)<br />

dev_display (SecondImage)<br />

endfor<br />

5.1.4 Real-Time Grabbing Using grab_image_async<br />

The main problem with the timing using grab_image is that the two processes of image grabbing and<br />

image processing run sequentially, i.e., one after the other. This means that the time needed for processing<br />

the image is included in the resulting frame rate, with the effect that the frame rate provided by the<br />

camera cannot be reached by definition.<br />

This problem can be solved by using the operator grab_image_async. Here, the two processes are<br />

decoupled and can run asynchronously, i.e., an image can be processed while the next image is already<br />

being grabbed. Figure 10 shows a corresponding timing diagram: The first call to grab_image_async<br />

is processed similar to grab_image (compare figure 8 on page 17). The difference becomes apparent<br />

after the transfer of the image into computer memory: Almost immediately after receiving the image,<br />

the frame grabber interface automatically commands the frame grabber to acquire a new image. Thus,<br />

the next image is grabbed while the application processes the previous image. After the processing, the<br />

application calls grab_image_async again, which waits until the already running image acquisition is<br />

finished. Thus, the full frame rate is now reached. <strong>Note</strong> that some frame grabbers fail to reach the full<br />

frame rate even with grab_image_async; section 5.1.5 on page 22 shows how to solve this problem.<br />

In the HDevelop example program hdevelop\real_time_grabbing_ids.dev, which was already<br />

described in section 5.1.1 on page 16, the reached frame rate for asynchronous processing is determined<br />

as follows:


camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

Grab<br />

wait for<br />

vsync<br />

delay<br />

image<br />

original<br />

frame rate<br />

delay<br />

image<br />

"negative"<br />

create<br />

HImage<br />

5.1.4 Real-Time Grabbing Using grab_image_async 21<br />

original<br />

frame rate<br />

frame rate<br />

processing<br />

original<br />

frame rate<br />

expose expose expose expose<br />

grab_image_async<br />

wait for<br />

image<br />

wait for<br />

vsync<br />

wait for<br />

vsync<br />

digitize digitize digitize<br />

Grab Grab Grab<br />

wait for<br />

image<br />

create<br />

HImage<br />

wait for<br />

image<br />

create<br />

HImage<br />

grab_image_async grab_image_async<br />

process process process<br />

Figure 10: Grabbing and processing in parallel using grab_image_async .<br />

grab_image (BackgroundImage, FGHandle)<br />

count_seconds (Seconds1)<br />

for i := 1 to 20 by 1<br />

grab_image_async (Image, FGHandle, -1)<br />

sub_image (BackgroundImage, Image, DifferenceImage, 1, 128)<br />

endfor<br />

count_seconds (Seconds2)<br />

TimeGrabImageAsync := (Seconds2-Seconds1)/20<br />

FrameRateGrabImageAsync := 1 / TimeGrabImageAsync<br />

As can be seen in figure 10, the first call to grab_image_async has a slightly different effect than<br />

the following ones, as it also triggers the first grab command to the frame grabber. As an alternative,<br />

you can use the operator grab_image_start which just triggers the grab command; then, the first call<br />

to grab_image_async behaves as the other ones. This is visualized, e.g., in figure 11; as you can<br />

see, the advantage of this method is that the application can perform some processing before calling<br />

grab_image_async.<br />

In the example, the processing was assumed to be faster than the acquisition. If this is not the case,<br />

the image will already be ready when the next call to grab_image_async arrives. In this case, you can<br />

specify how “old” the image is allowed to be using the parameter MaxDelay. Please refer to section 5.1.7<br />

on page 24 for details.<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

Grabbing


22 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Please note that when using grab_image_async it is not obvious anymore which image is returned by<br />

the operator call, because the call is decoupled from the command to the frame grabber! In contrast<br />

to grab_image, which always triggers the acquisition of a new image, grab_image_async typically<br />

returns an image which has been exposed before the operator was called, i.e., the image delay is negative<br />

(see figure 10)! Keep this effect in mind when changing parameters dynamically; contrary to intuition,<br />

the change will not affect the image returned by the next call of grab_image_async but by the following<br />

ones! Another problem appears when switching dynamically between cameras (see section 5.3.1 on page<br />

28).<br />

5.1.5 Continuous Grabbing<br />

For some frame grabbers, grab_image_async fails to reach the frame rate because the grab command<br />

to the frame grabber comes too late, i.e., after the camera has already started to transfer the next image<br />

(see figure 11a).<br />

As a solution to this problem, some frame grabber interfaces provide the so-called continuous grabbing<br />

mode, which can be enabled only via the operator set_framegrabber_param (parameter ’continuous_grabbing’):<br />

set_framegrabber_param (FGHandle, ’continuous_grabbing’, ’enable’)<br />

In this mode, the frame grabber reads images from a free-running camera continuously and transfers<br />

them into computer memory as depicted in figure 11b. Thus, the frame rate is reached. If your<br />

frame grabber supports continuous grabbing, you can test this effect in the example program hdevelop\real_time_grabbing_ids.dev,<br />

which was already described in the previous sections; the<br />

program measures the achievable frame rate for grab_image_async without and with continuous grabbing.<br />

We recommend to use continuous grabbing only if you want to process every image; otherwise, images<br />

are transmitted over the PCI bus unnecessarily, thereby perhaps blocking other PCI transfers.<br />

<strong>Note</strong> that some frame grabber interfaces provide additional functionality in the continuous grabbing<br />

mode, e.g., the <strong>HALCON</strong> BitFlow interface. Please refer to the corresponding documentation for more<br />

information.<br />

5.1.6 Using grab_image_async Together With Asynchronously Resettable Cameras<br />

As described in section 5.1.2 on page 18, you can acquire images without delay by using an asynchronously<br />

resettable camera. Figure 12 shows the resulting timing when using such a camera together<br />

with grab_image_async. When comparing the diagram to the one in figure 9 on page 19, you can see<br />

that a higher frame rate can now be reached, because the processing time is not included anymore.


a)<br />

camera<br />

b)<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

Grab<br />

wait for<br />

vsync<br />

etc<br />

grab_image_start<br />

5.1.6 Using grab_image_async Together With Asynchronously Resettable Cameras 23<br />

original<br />

frame rate<br />

original<br />

frame rate<br />

create<br />

HImage<br />

create<br />

HImage<br />

frame rate<br />

processing<br />

frame rate<br />

processing<br />

original<br />

frame rate<br />

expose expose expose expose<br />

wait for<br />

image<br />

grab_image_async<br />

Grab<br />

etc<br />

grab_image_start<br />

set ’continuous_grabbing’<br />

wait for<br />

image<br />

grab_image_async<br />

digitize<br />

wait for<br />

vsync<br />

digitize<br />

Grab<br />

wait for<br />

image<br />

digitize digitize<br />

digitize<br />

wait for<br />

image<br />

wait for<br />

image<br />

create<br />

HImage<br />

grab_image_async<br />

process process<br />

create<br />

HImage<br />

Grab<br />

Grab Grab Grab<br />

create<br />

HImage<br />

grab_image_async grab_image_async<br />

process process process<br />

Figure 11: a) grab_image_async fails to reach frame rate; b) problem solved using continuous grabbing.<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

Grabbing


24 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

Expose<br />

wait for<br />

vsync<br />

Grab<br />

delay<br />

image<br />

= 0<br />

original<br />

frame rate<br />

expose expose<br />

digitize<br />

wait for<br />

image<br />

grab_image_async<br />

Expose<br />

Grab<br />

create<br />

HImage<br />

wait for<br />

vsync<br />

digitize<br />

frame rate<br />

processing<br />

wait for<br />

image<br />

create<br />

HImage<br />

grab_image_async<br />

process process<br />

Figure 12: Using a asynchronously resettable camera together with grab_image_async (configuration as<br />

in figure 9 on page 19 .<br />

5.1.7 Specifying a Maximum Delay<br />

In contrast to grab_image, the operator grab_image_async has an additional parameter MaxDelay,<br />

which lets you specify how “old” an already grabbed image may be in order to be accepted. Figure 13 visualizes<br />

the effect of this parameter. There are two cases to distinguish: If the call to grab_image_async<br />

arrives before the next image has been grabbed (first call in the example), the parameter has no effect.<br />

However, if an image has been grabbed already (second and third call in the example), the elapsed time<br />

since the last grab command to the frame grabber is compared to MaxDelay. If it is smaller (second call<br />

in the example), the image is accepted; otherwise (third call), a new image is grabbed.<br />

Please note that the delay is not measured starting from the moment the image is exposed, as you might<br />

perhaps expect! Currently, only a few frame grabber SDKs provide this information; therefore, the last<br />

grab command from the interface to the frame grabber is used as the starting point instead.<br />

Grab<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t


camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

expose expose<br />

expose expose<br />

Grab<br />

digitize digitize<br />

digitize digitize<br />

wait for<br />

image<br />

Grab<br />

Grab<br />

> MaxDelay? NO > MaxDelay? YES<br />

create<br />

HImage<br />

create<br />

HImage<br />

5.2 Using an External Trigger 25<br />

wait for<br />

image<br />

process process process process<br />

grab_image_async<br />

Figure 13: Specifying a maximum delay for grab_image_async (using continuous grabbing).<br />

5.2 Using an External Trigger<br />

In the previous section, the software performing the machine vision task decided when to acquire an<br />

image (software trigger). In industrial applications, however, the moment for image acquisition is typically<br />

specified externally by the process itself, e.g., in form of a hardware trigger signal indicating the<br />

presence of an object to be inspected. Most frame grabber boards are therefore equipped with at least<br />

one input line for such signals, which are called external triggers.<br />

From <strong>HALCON</strong>’s point of view, external triggers are dealt with by the frame grabber board, the only<br />

thing to do is to inform the frame grabber to use the trigger. You can do this simply by setting the parameter<br />

ExternalTrigger of open_framegrabber to ’true’. Some frame grabber interfaces also allow<br />

to enable or disable the trigger dynamically using the operator set_framegrabber_param (parameter<br />

’external_trigger’).<br />

Figure 14a shows the timing diagram when using an external trigger together with grab_image and a<br />

free-running camera. After the call to grab_image, the frame grabber board waits for the trigger signal.<br />

When it appears, the procedure described in the previous section follows: The frame grabber waits for<br />

the next image, digitizes it, and transfers it into computer memory; then, the <strong>HALCON</strong> frame grabber<br />

interface transforms it into a <strong>HALCON</strong> image and returns the control to the application which processes<br />

the image and then calls grab_image again, which causes the frame grabber board to wait for the next<br />

trigger signal.<br />

Grab<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

Grabbing


26 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

a)<br />

b)<br />

camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

trigger<br />

camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

software<br />

application<br />

trigger<br />

Grab<br />

expose expose<br />

expose expose<br />

wait for<br />

trigger<br />

wait for<br />

image<br />

grab_image<br />

Grab<br />

etc<br />

grab_image_start<br />

wait for<br />

trigger<br />

Expose<br />

Trigger<br />

Trigger<br />

delay<br />

image<br />

= 0<br />

wait for<br />

vsync<br />

delay<br />

image<br />

expose<br />

wait for<br />

vsync<br />

wait for<br />

image<br />

grab_image_async<br />

digitize<br />

digitize<br />

Trigger<br />

delay<br />

image<br />

= 0<br />

expose<br />

create<br />

HImage<br />

process<br />

create<br />

HImage<br />

process<br />

wait for<br />

image<br />

delay<br />

image<br />

= 0<br />

wait for<br />

trigger<br />

Trigger Trigger<br />

wait for<br />

image<br />

expose<br />

Expose wait for Expose wait for Expose<br />

vsync<br />

vsync<br />

Grab<br />

digitize<br />

Grab<br />

grab_image<br />

Grab<br />

Trigger<br />

create<br />

HImage<br />

process<br />

digitize<br />

wait for<br />

image<br />

grab_image_async grab_image_async<br />

Figure 14: Using an external trigger together with: a) free-running camera and grab_image; b) asynchronously<br />

resettable camera and grab_image_async .<br />

The (bad) example in figure 14a was chosen on purpose to show an unsuitable configuration for using<br />

an external trigger: First of all, because of the free-running camera there is a non-deterministic delay<br />

Grab<br />

Trigger<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t


5.2.1 Special Parameters for External Triggers 27<br />

between the arrival of the trigger signal and the exposure of the image, which may mean that the object<br />

to be inspected is not completely visible anymore. Secondly, because grab_image is used, trigger<br />

signals which arrive while the application is processing an image are lost.<br />

Both problems can easily be solved by using an asynchronously resettable camera together with the<br />

operator grab_image_async as depicted in figure 14b.<br />

The C++ example program cpp\error_handling_timeout_picport.cpp (preconfigured for the<br />

<strong>HALCON</strong> Leutron interface) shows how simple it is to use an external trigger: The connection is<br />

opened with ExternalTrigger set to ’true’:<br />

HFramegrabber framegrabber;<br />

framegrabber.OpenFramegrabber(fgname, 1, 1, 0, 0, 0, 0, "default", -1,<br />

"gray", -1, "true", camtype, device,<br />

-1, -1);<br />

Then, images are grabbed:<br />

HImage image;<br />

do<br />

{<br />

image = framegrabber.GrabImageAsync(-1);<br />

} while (button == 0);<br />

The example contains a customized error handler which checks whether there is an external trigger; this<br />

part is described in detail in section 6.2.3 on page 32.<br />

5.2.1 Special Parameters for External Triggers<br />

Most frame grabber interfaces allow to further configure the use of external triggering via the operator<br />

set_framegrabber_param. As mentioned in section 4.2 on page 14, some interfaces allow to enable<br />

and disable the external trigger dynamically via the parameter ’external_trigger’. Another useful<br />

parameter is ’grab_timeout’, which sets a timeout for the acquisition process (some interfaces provide<br />

an additional parameter ’trigger_timeout’ just for triggered grabbing). Without such a timeout, the<br />

application would hang if for some reason no trigger signal arrives. In contrast, if a timeout is specified,<br />

the operators grab_image and grab_image_async only wait the specified time and then return an error<br />

code or raise an exception, depending on the programming language used. Section 6.2 on page 30 shows<br />

how to handle such errors.<br />

Other parameters allow to further specify the form of the trigger signal (’trigger_signal’), e.g.,<br />

whether the falling or the rising edge is used as the trigger, select between multiple trigger input lines,<br />

or even filter trigger signals. Some frame grabber interfaces also allow to influence the exposure via the<br />

trigger signal.<br />

5.3 Acquiring Images From Multiple Cameras<br />

The timing diagrams shown in the previous sections depicted the case of a single camera. Below we<br />

discuss some issues which arise when acquiring images from multiple cameras (see section 3.2 on page<br />

8 for possible configurations).<br />

Grabbing


28 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

5.3.1 Dynamic Port Switching and Asynchronous Grabbing<br />

If you switch dynamically between multiple cameras connected to a single board as described in section<br />

3.2.4 on page 10, you must be careful when using grab_image_async: By default, the frame<br />

grabber interface commands the frame grabber board to grab the next image automatically after it received<br />

the current image — but before the next call of grab_image_async! If you switched to another<br />

camera before this call, the frame grabber might already be busy grabbing an image from the first camera.<br />

Some frame grabber interfaces solve this problem by providing the parameter<br />

’start_async_after_grab_async’ for the operator set_framegrabber_param which allows<br />

to disable the automatic grab command to the frame grabber board.<br />

5.3.2 Simultaneous Grabbing<br />

Some frame grabber interfaces provide special functionality to grab images simultaneously from multiple<br />

(synchronized) cameras. Typically, the cameras are connected to a single frame grabber board;<br />

the Leutron interface also allows to grab simultaneously from cameras connected to multiple boards.<br />

As described in section 3.2.5 on page 11, the images are grabbed by a single call to grab_image<br />

or grab_image_async, which return them in form of a multi-channel image. Depending on the<br />

frame grabber interface, it may be necessary to switch on the simultaneous grabbing via the operator<br />

set_framegrabber_param.<br />

Please keep in mind that even if a <strong>HALCON</strong> frame grabber interface supports simultaneous grabbing,<br />

this might not be true for every frame grabber board the interface supports! In order to grab multiple<br />

images simultaneously, a frame grabber board must be equipped with multiple “grabbing units”; for<br />

example, an analog frame grabber board must be equipped with multiple A/D converters. Please check<br />

this in the documentation of your frame grabber board.<br />

Even if a <strong>HALCON</strong> frame grabber interface does not provide the special simultaneous grabbing mode,<br />

you can realize a similar behavior “manually”, e.g., by connecting each (asynchronously resettable)<br />

camera to a single frame grabber board and then using a common external trigger signal to synchronize<br />

the grabbing.


6 Miscellaneous<br />

6.1 Acquiring Images From Unsupported Frame Grabbers<br />

6 Miscellaneous 29<br />

If you want to use a frame grabber that is currently not supported by <strong>HALCON</strong>, i.e., for which no HAL-<br />

CON interface exists, there exist two principal ways: First, you can create your own <strong>HALCON</strong> frame<br />

grabber interface; how to do this is described in detail in the Frame Grabber Integration Programmer’s<br />

Manual.<br />

As an alternative, you can pass externally created images, i.e., the raw image matrix, to <strong>HALCON</strong><br />

using the operators gen_image1, gen_image3, or gen_image1_extern, which create a corresponding<br />

<strong>HALCON</strong> image. The main difference between the operators gen_image1 and gen_image1_extern is<br />

that the former copies the image matrix when creating the <strong>HALCON</strong> image, whereas the latter doesn’t,<br />

which is useful if you want to realize volatile grabbing as described in section 5.1.3 on page 18.<br />

The C example program c\use_extern_image.c shows how to use the operator gen_image1_extern<br />

to pass standard gray value images to <strong>HALCON</strong>. In this case, the image matrix consists of 8 bit pixels<br />

(bytes), which can be represented by the data type unsigned char. At the beginning, the program<br />

calls a procedure which allocates memory for the images to be “grabbed”; in a real application this<br />

corresponds to the image buffer(s) used by the frame grabber SDK.<br />

unsigned char *image_matrix_ptr;<br />

long width, height;<br />

InitializeBuffer(&image_matrix_ptr, &width, &height);<br />

The example program “simulates” the grabbing of images with a procedure which reads images from<br />

an image sequence and copies them into the image buffer. Then, the content of the image buffer is<br />

transformed into a <strong>HALCON</strong> image (type byte) via gen_image1_extern. The parameter ClearProc<br />

is set to 0 to signal that the program itself takes care of freeing the memory. The created <strong>HALCON</strong><br />

image is then displayed. The loop can be exited by clicking into the <strong>HALCON</strong> window with any mouse<br />

button.<br />

Hobject image;<br />

long window_id;<br />

open_window (0, 0, width, height, 0, "visible", "", &window_id);<br />

while (!ButtonPressed(window_id))<br />

{<br />

MyGrabImage((const unsigned char **) &image_matrix_ptr);<br />

gen_image1_extern(&image, "byte", width, height,<br />

(long) image_matrix_ptr, (long) 0);<br />

disp_obj(image, window_id);<br />

}<br />

If your frame grabber supplies images with more than 8 bit pixels, you must adapt both the<br />

data type for the image matrix and the type of the created <strong>HALCON</strong> image (parameter Type of<br />

gen_image1_extern). In case of color images <strong>HALCON</strong> expects the image data in form of three<br />

separate image matrices. You can create a <strong>HALCON</strong> image either by calling the operator gen_image3<br />

with the three pointers to the matrices, or by calling the operator gen_image1_extern three times and<br />

Miscellaneous


30 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Figure 15: Popup dialog in HDevelop signaling a timeout.<br />

then using the operator channels_to_image to combine the three images into a multi-channel image.<br />

Please refer to appendix A on page 37 for more information about <strong>HALCON</strong> images in general.<br />

6.2 Error Handling<br />

Just as the <strong>HALCON</strong> frame grabber interfaces encapsulate the communication with a frame grabber<br />

board, they also encapsulate occurring errors within the <strong>HALCON</strong> error handling mechanism. How to<br />

catch and react to these errors is described below for HDevelop programs and also for programs using<br />

<strong>HALCON</strong>’s programming language interfaces.<br />

Some <strong>HALCON</strong> frame grabber interfaces provide special parameters for set_framegrabber_param<br />

which are related to error handling. The most commonly used one is the parameter ’grab_timeout’<br />

which specifies when the frame grabber should quit waiting for an image. The examples described in the<br />

following sections show how to handle the corresponding <strong>HALCON</strong> error.<br />

<strong>Note</strong> that all example programs enable the signaling of low level errors via the operator set_system,<br />

e.g., in HDevelop syntax via<br />

set_system (’do_low_error’, ’true’)<br />

In this mode, low level errors occurring in the frame grabber SDK (or in the <strong>HALCON</strong> interface) are<br />

signaled by a message box.<br />

6.2.1 Error Handling in HDevelop<br />

The HDevelop example hdevelop\error_handling_timeout_picport.dev shows how to handle<br />

<strong>HALCON</strong> errors in a HDevelop program. To “provoke” an error, open_framegrabber is called with<br />

ExternalTrigger = ’true’. If there is no trigger, a call to grab_image results in a timeout; HDevelop<br />

reacts to this error with the popup dialog shown in figure 15 and stops the program.<br />

open_framegrabber (FGName, 1, 1, 0, 0, 0, 0, ’default’, -1, ’default’, -1,<br />

’true’, CameraType, Device, -1, -1, FGHandle)<br />

set_framegrabber_param (FGHandle, ’grab_timeout’, 2000)<br />

grab_image (Image, FGHandle)<br />

<strong>HALCON</strong> lets you modify the reaction to an error with the operator set_check (in HDevelop:<br />

dev_set_check). If you set it to ’˜give_error’, the program does not stop in case of an error but<br />

only stores its cause in form of an error code. To access this error code in HDevelop, you must define


6.2.2 Error Handling Using <strong>HALCON</strong>/C 31<br />

a corresponding variable using the operator dev_error_var. <strong>Note</strong> that this variable is updated after<br />

each operator call; to check the result of a single operator we therefore recommend to switch back to the<br />

standard error handling mode directly after the operator call as in the following lines:<br />

dev_error_var (ErrorNum, 1)<br />

dev_set_check (’~give_error’)<br />

grab_image (Image, FGHandle)<br />

dev_error_var (ErrorNum, 0)<br />

dev_set_check (’give_error’)<br />

To check whether a timeout occurred, you compare the error variable with the code signaling a timeout<br />

(5322); a list of error codes relating to image acquisition can be found in the Frame Grabber Integration<br />

Programmer’s Manual, appendix B on page 69. In the example, the timeout is handled by disabling the<br />

external trigger mode via the operator set_framegrabber_param (parameter ’external_trigger’).<br />

Then, the call to grab_image is tested again.<br />

if (ErrorNum = 5322)<br />

set_framegrabber_param (FGHandle, ’external_trigger’, ’false’)<br />

dev_error_var (ErrorNum, 1)<br />

dev_set_check (’~give_error’)<br />

grab_image (Image, FGHandle)<br />

dev_error_var (ErrorNum, 0)<br />

dev_set_check (’give_error’)<br />

endif<br />

Now, the error variable should contain the value 2 signaling that the operator call succeeded; for this<br />

value, HDevelop provides the constant H_MSG_TRUE. If you get another error code, the program accesses<br />

the corresponding error text using the operator get_error_text.<br />

if (ErrorNum # H_MSG_TRUE)<br />

get_error_text (ErrorNum, ErrorText)<br />

endif<br />

If your frame grabber interface does not provide the parameter ’external_trigger’, you can realize<br />

a similar behavior by closing the connection and then opening it again with ExternalTrigger set to<br />

’false’.<br />

6.2.2 Error Handling Using <strong>HALCON</strong>/C<br />

The mechanism for error handling in a program based on <strong>HALCON</strong>/C is similar to the one in HDevelop;<br />

in fact, it is even simpler, because each operator automatically returns its error code. However, if a<br />

<strong>HALCON</strong> error occurs in a C program, the default error handling mode causes the program to abort.<br />

The C example program c\error_handling_timeout_picport.c performs the same task as the<br />

HDevelop program in the previous section; if the call to grab_image succeeds, the program grabs and<br />

displays images in a loop, which can be exited by clicking into the window. The following lines show<br />

how to test whether a timeout occurred:<br />

Miscellaneous


32 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

set_check ("~give_error");<br />

error_num = grab_image (&image, fghandle);<br />

set_check ("give_error");<br />

switch (error_num)<br />

{<br />

case H_ERR_FGTIMEOUT:<br />

As you see, in a C program you can use predefined constants for the error codes (see the Frame Grabber<br />

Integration Programmer’s Manual, appendix B on page 69, for a list of image acquisition error codes and<br />

their corresponding constants).<br />

6.2.3 Error Handling Using <strong>HALCON</strong>/C++<br />

If your application is based on <strong>HALCON</strong>/C++, there are two methods for error handling: If you use<br />

operators in their C-like form, e.g., grab_image, you can apply the same procedure as described for<br />

<strong>HALCON</strong>/C in the previous section.<br />

In addition, <strong>HALCON</strong>/C++ provides an exception handling mechanism based on the class HException,<br />

which is described in the Programmer’s Guide, section 4.3 on page 26. Whenever a <strong>HALCON</strong> error<br />

occurs, an instance of this class is created. The main idea is that you can specify a procedure which<br />

is then called automatically with the created instance of HException as a parameter. How to use this<br />

mechanism is explained in the C++ example program cpp\error_handling_timeout_picport.cpp,<br />

which performs the same task as the examples in the previous sections.<br />

In the example program cpp\error_handling_timeout_picport.cpp (preconfigured for the HAL-<br />

CON Leutron interface), the procedure which is to be called upon error is very simple: It just raises a<br />

standard C++ exception with the instance of HException as a parameter.<br />

void MyHalconExceptionHandler(const Halcon::HException& except)<br />

{<br />

throw except;<br />

}<br />

In the program, you “install” this procedure via a class method of HException:<br />

int main(int argc, char *argv[])<br />

{<br />

using namespace Halcon;<br />

HException::InstallHHandler(&MyHalconExceptionHandler);<br />

Now, you react to a timeout with the following lines:<br />

try<br />

{<br />

image = framegrabber.GrabImage();<br />

}<br />

catch (HException except)<br />

{<br />

if (except.err == H_ERR_FGTIMEOUT)<br />

{<br />

framegrabber.SetFramegrabberParam("external_trigger", "false");


6.2.4 Error Handling Using <strong>HALCON</strong>/COM 33<br />

As already noted, if your frame grabber interface does not provide the parameter ’external_trigger’,<br />

you can realize a similar behavior by closing the connection and then opening it again with External-<br />

Trigger set to ’false’:<br />

if (except.err == H_ERR_FGTIMEOUT)<br />

{<br />

framegrabber.OpenFramegrabber(fgname, 1, 1, 0, 0, 0, 0, "default",<br />

-1, "gray", -1, "false", camtype,<br />

"default", -1, -1);<br />

<strong>Note</strong> that when calling OpenFramegrabber via the class HFramegrabber as above, the operator checks<br />

whether it is called with an already opened connection and automatically closes it before opening it with<br />

the new parameters.<br />

6.2.4 Error Handling Using <strong>HALCON</strong>/COM<br />

The <strong>HALCON</strong>/COM interface uses the standard COM error handling technique where every<br />

method call passes both a numerical and a textual representation of the error to the calling<br />

framework. How to use this mechanism is explained in the Visual Basic example program<br />

vb\error_handling_timeout_picport\error_handling_timeout_picport.vbp, which<br />

performs the same task as the examples in the previous sections.<br />

For each method, you can specify an error handler by inserting the following line at the beginning of the<br />

method:<br />

On Error GoTo ErrorHandler<br />

At the end of the method, you insert the code for the error handler. If a runtime error occurs, Visual<br />

Basic automatically jumps to this code, with the error being described in the variable Err. However, the<br />

returned error number does not correspond directly to the <strong>HALCON</strong> error as in the other programming<br />

languages, because low error numbers are reserved for COM. To solve this problem <strong>HALCON</strong>/COM<br />

uses an offset which must be subtracted to get the <strong>HALCON</strong> error code. This offset is accessible as a<br />

property of the class HSystemX:<br />

ErrorHandler:<br />

Dim sys As New HSystemX<br />

ErrorNum = Err.Number - sys.ErrorBaseHalcon<br />

The following code fragment checks whether the error is due to a timeout. If yes, the program disables<br />

the external trigger mode and tries again to grab an image. If the grab is successful the program continues<br />

at the point the error occurred; otherwise, the Visual Basic default error handler is invoked. <strong>Note</strong> that in<br />

contrast to the other programming languages <strong>HALCON</strong>/COM does not provide constants for the error<br />

codes.<br />

If (ErrorNum = 5322) Then<br />

Call FG.SetFramegrabberParam("external_trigger", "false")<br />

Set Image = FG.GrabImage<br />

Resume Next<br />

If the error is not caused by a timeout, the error handler raises it anew, whereupon the Visual Basic<br />

default error handler is invoked.<br />

Miscellaneous


34 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Else<br />

Err.Raise (Err.Number)<br />

End If<br />

If your frame grabber interface does not provide the parameter ’external_trigger’, you can realize<br />

a similar behavior by closing the connection and then opening it again with ExternalTrigger set to<br />

’false’. <strong>Note</strong> that the class HFramegrabberX does not provide a method to close the connection;<br />

instead you must destroy the variable with the following line:<br />

Set FG = Nothing<br />

6.3 Line Scan Cameras<br />

From the point of view of <strong>HALCON</strong> there is no difference between area and line scan cameras: Both<br />

acquire images of a certain width and height; whether the height is 1, i.e., a single line, or larger does<br />

not matter. In fact, in many line scan applications the frame grabber combines multiple acquired lines to<br />

form a so-called page which further lessens the difference between the two camera types.<br />

The main problem is therefore whether your frame grabber supports line scan cameras. If yes, you can<br />

acquire images from it via <strong>HALCON</strong> exactly as from an area scan camera. With the parameter ImageHeight<br />

of the operator open_framegrabber you can sometimes specify the height of the page;<br />

typically, this information is set in the camera configuration file. Some <strong>HALCON</strong> frame grabber interfaces<br />

allow to further configure the acquisition mode via the operator set_framegrabber_param.<br />

The images acquired from a line scan camera can then be processed just like images from area scan<br />

cameras. However, line scan images often pose an additional problem: The objects to inspect may<br />

be spread over multiple images (pages). To solve this problem, <strong>HALCON</strong> provides special operators:<br />

tile_images allows to merge images into a larger image, merge_regions_line_scan and<br />

merge_cont_line_scan_xld allow to merge the (intermediate) processing results of subsequent images.<br />

How to use these operators is explained in the HDevelop example program hdevelop\line_scan.dev.<br />

The program is based on an image file sequence which is read using the <strong>HALCON</strong> virtual frame grabber<br />

interface File; the task is to extract paper clips and calculate their orientation. Furthermore, the gray<br />

values in a rectangle surrounding each clip are determined.<br />

An important parameter for the merging is over how many images an object can be spread. In the<br />

example, a clip can be spread over 4 images:<br />

MaxImagesRegions := 4<br />

The continuous processing is realized by a simple loop: At each iteration, a new image is grabbed, and<br />

the regions forming candidates for the clips are extracted using thresholding.<br />

while (1)<br />

grab_image (Image, FGHandle)<br />

threshold (Image, CurrRegions, 0, 80)<br />

The current regions are then merged with ones extracted in the previous image using the operator<br />

merge_regions_line_scan. As a result, two sets of regions are returned: The parameter CurrMergedRegions<br />

contains the current regions, possibly extended by fitting parts of the previously extracted<br />

regions, whereas the parameter PrevMergedRegions contains the rest of the previous regions.


a)<br />

b)<br />

c)<br />

1<br />

4<br />

6.3 Line Scan Cameras 35<br />

2<br />

5 6<br />

Figure 16: Merging regions extracted from subsequent line scan images: state after a) 2, b) 3, c) 4 images<br />

(large coordinate system: tiled image; small coordinate systems: current image or most recent<br />

image).<br />

merge_regions_line_scan (CurrRegions, PrevRegions, CurrMergedRegions,<br />

PrevMergedRegions, ImageHeight, ’top’,<br />

MaxImagesRegions)<br />

connection (PrevMergedRegions, ClipCandidates)<br />

select_shape (ClipCandidates, FinishedClips, ’area’, ’and’, 4500, 7000)<br />

The regions in PrevMergedRegions are “finished”; from them, the program selects the clips via their<br />

area and further processes them later, e.g., determines their position and orientation. The regions in<br />

CurrMergedRegions are renamed and now form the previous regions for the next iteration.<br />

copy_obj (CurrMergedRegions, PrevRegions, 1, -1)<br />

endwhile<br />

<strong>Note</strong> that the operator copy_obj does not copy the regions themselves but only the corresponding HAL-<br />

CON objects, which can be thought of as references to the actual region data.<br />

1<br />

1<br />

4<br />

2<br />

2<br />

3<br />

3<br />

3<br />

Miscellaneous


36 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

Before we show how to merge the images let’s take a look at figure 16, which visualizes the whole<br />

process: After the first two images CurrMergedRegions contains three clip parts; for the first one a<br />

previously extracted region was merged. <strong>Note</strong> that the regions are described in the coordinate frame of<br />

the current image; this means that the merged part of clip no. 1 has negative coordinates.<br />

In the next iteration (figure 16b), further clip parts are merged, but no clip is finished yet. <strong>Note</strong> that the<br />

coordinate frame is again fixed to the current image; as a consequence the currently merged regions seem<br />

to move into negative coordinates.<br />

After the fourth image (figure 16c), clips no. 1 and 2 are completed; they are returned in the parameter<br />

PrevMergedRegions. <strong>Note</strong> that they are still described in the coordinate frame of the previous image<br />

(depicted with dashed arrow); to visualize them together with CurrMergedRegions they must be moved<br />

to the coordinate system of the current image using the operator move_region:<br />

move_region (FinishedClips, ClipsInCurrentImageCoordinates,<br />

-ImageHeight, 0)<br />

Let’s get back to the task of merging images: To access the gray values around a clip, one must merge<br />

those images over which the PrevMergedRegions can be spread. At the beginning, an empty image is<br />

created which can hold 4 images:<br />

gen_image_const (TiledImage, ’byte’, ImageWidth,<br />

ImageHeight * MaxImagesRegions)<br />

At the end of each iteration, the “oldest” image, i.e., the image at the top, is cut off the tiled image using<br />

crop_part, and the current image is merged at the bottom using tile_images_offset:<br />

crop_part (TiledImage, TiledImageMinusOldest, ImageHeight, 0,<br />

ImageWidth, (MaxImagesRegions - 1) * ImageHeight)<br />

ImagesToTile := [TiledImageMinusOldest,Image]<br />

tile_images_offset (ImagesToTile, TiledImage, [0,<br />

(MaxImagesRegions-1)*ImageHeight], [0, 0], [-1,<br />

-1], [-1, -1], [-1, -1], [-1, -1], ImageWidth,<br />

MaxImagesRegions * ImageHeight)<br />

As noted above, the regions returned in PrevMergedRegions are described in the coordinate frame of<br />

the most recent image (depicted with dashed arrows in figure 16c); to extract the corresponding gray values<br />

from the tiled image, they must first be moved to its coordinate system (depicted with longer arrows)<br />

using the operator move_region. Then, the surrounding rectangles are created using shape_trans, and<br />

finally the corresponding gray values are extracted using add_channels:<br />

move_region (FinishedClips, ClipsInTiledImageCoordinates,<br />

(MaxImagesRegions-1) * ImageHeight, 0)<br />

shape_trans (ClipsInTiledImageCoordinates, AroundClips, ’rectangle1’)<br />

add_channels (AroundClips, TiledImage, GrayValuesAroundClips)


Appendix<br />

A <strong>HALCON</strong> Images<br />

A <strong>HALCON</strong> Images 37<br />

In the following, we take a closer look at the way <strong>HALCON</strong> represents and handles images. Of course,<br />

we won’t bother you with details about the low-level representation and the memory management; HAL-<br />

CON takes care of it in a way to guarantee optimal performance.<br />

A.1 The Philosophy of <strong>HALCON</strong> Images<br />

There are three important concepts behind <strong>HALCON</strong>’s image objects:<br />

1. Multiple channels<br />

Typically, one thinks of an image as a matrix of pixels. In <strong>HALCON</strong>, this matrix is called a<br />

channel, and images may consist of one or more such channels. For example, gray value images<br />

consist of a single channel, color images of three channels.<br />

The advantage of this representation is that many <strong>HALCON</strong> operators automatically process all<br />

channels at once; for example, if you want to subtract gray level or color images from another,<br />

you can apply sub_image without worrying about the image type. Whether an operator processes<br />

all channels at once can be seen in the parameter description in the reference manual:<br />

If an image parameter is described as (multichannel-)image or (multichannel-)image(array)<br />

(e.g., the parameter ImageMinuend of sub_image), all channels are processed; if it is<br />

described as image or image(-array) (e.g., the parameter Image of threshold), only the first<br />

channel is processed.<br />

For more information about channels please refer to appendix A.3.2.<br />

2. Various pixel types<br />

Besides the standard 8 bit (type byte) used to represent gray value image, <strong>HALCON</strong> allows<br />

images to contain various other data, e.g. 16 bit integers (type int2 or uint2) or 32 bit floating<br />

point numbers (type real) to represent derivatives.<br />

Most of the time you need not worry about pixel types, because <strong>HALCON</strong> operators that output<br />

images automatically use a suitable pixel type. For example, the operator derivate_gauss<br />

creates a real image to store the result of the derivation. As another example, if you connect<br />

to a frame grabber selecting a value > 8 for the parameter BitsPerChannel, a subsequent<br />

grab_image returns an uint2 image.<br />

3. Arbitrarily-shaped region of interest<br />

Besides the pixel information, each <strong>HALCON</strong> image also stores its so-called domain in form of a<br />

<strong>HALCON</strong> region. The domain can be interpreted as a region of interest, i.e., <strong>HALCON</strong> operators<br />

(with some exceptions) restrict their processing to this region.<br />

The image domain inherits the full flexibility of a <strong>HALCON</strong> region, i.e., it can be of arbitrary<br />

shape and size, can have holes, or even consist of unconnected points. For more information<br />

about domains please refer to appendix A.3.3 on page 39.<br />

<strong>HALCON</strong> Images


38 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

The power of <strong>HALCON</strong>’s approach lies in the fact that it offers full flexibility but does not require you<br />

to worry about options you don’t need at the moment. For example, if all you do is grab and process<br />

standard 8 bit gray value images, you can ignore channels and pixel types. At the moment you decide<br />

to use color images instead, all you need to do is to add some lines to decompose the image into its<br />

channels. And if your camera / frame grabber provides images with more than 8 bit pixel information,<br />

<strong>HALCON</strong> is ready for this as well.<br />

A.2 Image Tuples (Arrays)<br />

Another powerful mechanism of <strong>HALCON</strong> is the so-called tuple processing: If you want to process<br />

multiple images in the same way, e.g., to smooth them, you can call the operator (e.g., mean_image) once<br />

passing all images as a tuple (array), instead of calling it multiple times. Furthermore, some operators<br />

always return image tuples, e.g., gen_gauss_pyramid or inspect_shape_model.<br />

Whether an operator supports tuple processing can be seen in the parameter description in the reference<br />

manual: If an input image parameter is described as image(-array) or (multichannel-)image(array)<br />

(e.g., the parameter Image of mean_image), it supports tuple processing; if it is described as<br />

image or (multichannel-)image (e.g., the parameter Image of find_1d_bar_code), only one image<br />

is processed.<br />

For information about creating or accessing image tuples please refer to appendix A.3.6.<br />

A.3 <strong>HALCON</strong> Operators for Handling Images<br />

Below you find a brief overview of operators that allow to create <strong>HALCON</strong> images or to modify “technical<br />

aspects” like the image size or the number of channels.<br />

A.3.1 Creation<br />

<strong>HALCON</strong> images are created automatically when you use operators like grab_image or read_image.<br />

You can also create images from scratch using the operators listed in the HDevelop menu Operators<br />

⊲ Image ⊲ Creation, e.g., gen_image_const or gen_image1_extern (see also section 6.1 on page<br />

29).<br />

A.3.2 Channels<br />

Operators for manipulating channels can be found in the HDevelop menu Operators ⊲ Image ⊲ Channel.<br />

You can query the number of channels of an image with the operator count_channels. Channels<br />

can be accessed using access_channel (which extracts a specified channel without copying), image_to_channels<br />

(which converts a multi-channel image into an image tuple), or decompose2 etc.<br />

(which converts a multi-channel image into 2 or more single-channel images). Vice versa, you can create<br />

a multi-channel image using channels_to_image or compose2 etc., and add channels to an image<br />

using append_channel.


A.3.3 Domain<br />

A.3.3 Domain 39<br />

Operators for manipulating the domain of an image can be found in the HDevelop menu Operators ⊲<br />

Image ⊲ Domain. Upon creation of an image, its domain is set to the full image size. You can set it to<br />

a specified region using change_domain. In contrast, the operator reduce_domain takes the original<br />

domain into account; the new domain is equal to the intersection of the original domain with the specified<br />

region. Please also take a look at the operator add_channels, which can be seen as complementary to<br />

reduce_domain.<br />

A.3.4 Access<br />

Operators for accessing information about a <strong>HALCON</strong> image can be found in the HDevelop menu Operators<br />

⊲ Image ⊲ Access. For example, get_image_pointer1 returns the size of an image and a<br />

pointer to the image matrix of its first channel.<br />

A.3.5 Manipulation<br />

You can change the size of an image using the operators change_format or crop_part, or other operators<br />

from the HDevelop menu Operators ⊲ Image ⊲ Format. The menu Operators ⊲ Image ⊲<br />

Type-Conversion lists operators which change the pixel type, e.g., convert_image_type. Operators<br />

to modify the pixel values, can be found in the menu Operators ⊲ Image ⊲ Manipulation, e.g.,<br />

paint_gray, which copies pixels from one image into another.<br />

A.3.6 Image Tuples<br />

Operators for creating and accessing image tuples can be found in the HDevelop menu Operators<br />

⊲ Object ⊲ Manipulation. Image tuples can be created using the operators gen_empty_obj and<br />

concat_obj, while the operator select_obj allows to access an individual image that is part of a<br />

tuple.<br />

<strong>HALCON</strong> Images


40 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

B Parameters Describing the Image<br />

When opening a connection with open_framegrabber, you can specify the desired image format, e.g.,<br />

its size or the number of bits per pixel, using its nine parameters, which are described in the following.<br />

B.1 Image Size<br />

The following 6 parameters influence the size of the grabbed images: HorizontalResolution and<br />

VerticalResolution specify the spatial resolution of the image in relation to the original size. For<br />

example, if you choose VerticalResolution = 2, you get an image with half the height of the original<br />

as depicted in figure 17b. Another name for this process is (vertical and horizontal) subsampling.<br />

With the parameters ImageWidth, ImageHeight, StartRow, and StartColumn you can grab only a<br />

part of the (possibly subsampled) image; this is called image cropping. In figure 17, the image part to<br />

be grabbed is marked with a rectangle in the original (or subsampled) image; to the right, the resulting<br />

image is depicted. <strong>Note</strong> that the resulting <strong>HALCON</strong> image always starts with the coordinates (0,0),<br />

i.e., the information contained in the parameters StartRow and StartColumn cannot be recovered from<br />

the resulting image.<br />

Depending on the involved components, both subsampling and image cropping may be executed at different<br />

points during the transfer of an image from the camera into <strong>HALCON</strong>: in the camera, in the frame<br />

grabber, or in the software. Please note that in most cases you get no direct effect on the performance in<br />

form of a higher frame rate; exceptions are CMOS cameras which adapt their frame rate to the requested<br />

image size. Subsampling or cropping on the software side has no effect on the frame rate; besides, you<br />

can achieve a similar result using reduce_domain. If the frame grabber executes the subsampling or<br />

cropping you may get a positive effect if the PCI bus is the bottleneck of your application and prevents<br />

a)<br />

b)<br />

Figure 17: The effect of image resolution (subsampling) and image cropping (ImageWidth = 200,<br />

ImageHeight = 100, StartRow = 50, StartColumn = 100): a) HorizontalResolution (HR)<br />

= VerticalResolution (VR) = 1; b) HR = 1, VR = 2; c) HR = 2, VR = 1; d) HR = VR = 2.<br />

c)<br />

d)


B.2 Frames vs. Fields 41<br />

you from getting the full frame rate. Some frame grabber interfaces allow dynamic image cropping via<br />

the operator set_framegrabber_param.<br />

<strong>Note</strong> that <strong>HALCON</strong> itself does not differentiate between area and line scan cameras as both produce<br />

images – the former in form of frames, the latter in form of so-called pages created from successive<br />

lines (number specified in the parameter ImageHeight). Section 6.3 on page 34 contains additional<br />

information regarding the use of line scan cameras.<br />

B.2 Frames vs. Fields<br />

The parameter Field is relevant only for analog cameras that produce signals following the video standards<br />

originally developed for TV, e.g., NTSC or PAL. In these standards, the camera transmits images<br />

(also called frames) in form of two so-called fields, one containing all odd lines of a frame, the other<br />

all even lines of the next frame. On the frame grabber board, these two fields are then interlaced; the<br />

resulting frame is transferred via the PCI bus into the computer memory using DMA (direct memory<br />

access).<br />

Figure 18 visualizes this process and demonstrates its major drawback: If a moving object is observed<br />

(in the example a dark square with the letter ’T’), the position of the object changes from field to field,<br />

the resulting frame shows a distortion at the vertical object boundaries (also called picket-fence effect).<br />

Such a distortion seriously impairs the accuracy of measurements; industrial vision systems therefore<br />

often use so-called progressive scan cameras which transfer full frames (see figure 19). Some cameras<br />

also “mix” interlacing with progressive scan as depicted in figure 20.<br />

You can also acquire the individual fields by specifying VerticalResolution = 2. Via the parameter<br />

Field you can then select which fields are to be acquired (see also figure 21): If you select ’first’ or<br />

camera<br />

transfer camera<br />

to frame grabber<br />

(analog signal)<br />

frame grabber<br />

transfer frame<br />

grabber to<br />

software (DMA)<br />

software<br />

odd field even field odd field even field odd field<br />

interlacing interlacing<br />

Figure 18: Interlaced grabbing (Field = ’interlaced’).<br />

t<br />

t<br />

Image Parameters


42 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

camera<br />

transfer camera<br />

to frame grabber<br />

(analog signal)<br />

frame grabber<br />

transfer frame<br />

grabber to<br />

software (DMA)<br />

software<br />

camera<br />

transfer camera<br />

to frame grabber<br />

(analog signal)<br />

frame grabber<br />

transfer frame<br />

grabber to<br />

software (DMA)<br />

software<br />

full frame full frame full frame<br />

Figure 19: Progressive scan grabbing (Field = ’progressive’).<br />

odd field even field odd field even field odd field<br />

interlacing interlacing<br />

Figure 20: Special form of interlaced grabbing supported by some cameras.<br />

’second’, you get all odd or all even fields, respectively; if you select ’next’, you get every field. The<br />

latter mode has the advantage of a higher field rate, at the cost, however, of the so-called vertical jitter:<br />

Objects may seem to move up and down (like the square in figure 21), while structures that are one pixel<br />

wide appear and disappear (like the upper part of the ’T’).<br />

t<br />

t<br />

t<br />

t


a)<br />

b)<br />

c)<br />

camera<br />

transfer camera<br />

to frame grabber<br />

(analog signal)<br />

frame grabber<br />

transfer frame<br />

grabber to<br />

software (DMA)<br />

software<br />

frame grabber<br />

transfer frame<br />

grabber to<br />

software (DMA)<br />

software<br />

frame grabber<br />

transfer frame<br />

grabber to<br />

software (DMA)<br />

software<br />

odd field even field odd field even field odd field<br />

Figure 21: Three ways of field grabbing: a) ’first’; b) ’second’; c) ’next’ .<br />

B.2 Frames vs. Fields 43<br />

By specifying Field = ’first’, ’second’, or ’next’ for a full resolution image (VerticalResolution<br />

= 1), you can select with which field the interlacing starts.<br />

Figure 22 shows a timing diagram for using grab_image together with an interlaced-scan camera. Here,<br />

you can in some cases increase the processing frame rate by specifying ’next’ for the parameter Field.<br />

The frame grabber then starts to digitize an image when the next field arrives; in the example therefore<br />

only one field is lost.<br />

t<br />

t<br />

t<br />

t<br />

Image Parameters


44 <strong>Application</strong> <strong>Note</strong> on Image Acquisition<br />

camera<br />

transfer<br />

(analog)<br />

frame<br />

grabber<br />

transfer<br />

(DMA)<br />

IAI & SDK<br />

application<br />

wait for<br />

vsync<br />

Grab<br />

wait for<br />

image<br />

software grab_image<br />

B.3 Image Data<br />

original<br />

frame rate<br />

expose expose expose expose expose expose expose<br />

odd field even field odd field even field odd field even field odd field<br />

digitize digitize<br />

wait for<br />

vsync digitize digitize<br />

create<br />

HImage<br />

Grab<br />

wait for<br />

image<br />

frame rate<br />

processing<br />

create<br />

HImage<br />

grab_image<br />

process process<br />

Figure 22: Grabbing interlaced images starting with the ’next’ field.<br />

The parameters described in the previous sections concentrated on the size of the images. The image<br />

data, i.e., the data contained in a pixel, is described with the parameters BitsPerChannel and ColorSpace.<br />

To understand these parameters, a quick look at <strong>HALCON</strong>’s way to represent images is necessary:<br />

A <strong>HALCON</strong> image consists of one or more matrices of pixels, which are called channels. Gray<br />

value images are represented as single-channel images, while color images consist of three channels,<br />

e.g., for the red, green, and blue part of an RGB image. Each image matrix (channel) consists of pixels,<br />

which may be of different data types, e.g., standard 8 bit (type byte) or 16 bit integers (type int2 or<br />

uint2) or 32 bit floating point numbers (type real). For detailed information about <strong>HALCON</strong> images<br />

please refer to appendix A on page 37.<br />

The two parameters correspond to the two main aspects of <strong>HALCON</strong> images: With the parameter ColorSpace,<br />

you can select whether the resulting <strong>HALCON</strong> image is to be a (single-channel) gray value<br />

image (value ’gray’) or a (multi-channel) color image (e.g., value ’rgb’). The parameter BitsPer-<br />

Channel specifies how many bits are transmitted per pixel per channel from the frame grabber to the<br />

computer; the pixel type of the <strong>HALCON</strong> image is then chosen to accommodate the transmitted number<br />

of pixels.<br />

For example, if a frame grabber is able to transmit 10 bit gray value images, select ColorSpace =<br />

’gray’ and BitsPerChannel = 10 and you will get a single-channel <strong>HALCON</strong> image of the type<br />

t<br />

t<br />

t<br />

t<br />

t<br />

t


B.3 Image Data 45<br />

’uint2’, i.e., 16 bit per channel. Another example concerns RGB images: Some frame grabbers allow<br />

the values 8 and 5 for BitsPerChannel. In the first case, 3 × 8 = 24 bit are transmitted per pixel, while<br />

in the second case only 3 × 5 = 15 (padded to 16) bit are transmitted; in both cases, a three-channel<br />

’byte’ image results.<br />

Image Parameters


46 <strong>Application</strong> <strong>Note</strong> on Image Acquisition


<strong>HALCON</strong> <strong>Application</strong> <strong>Note</strong><br />

How to Use Shape-Based Matching<br />

to Find and Localize Objects<br />

Provided Functionality<br />

⊲ Finding objects starting based on a single model image<br />

⊲ Localizing objects with subpixel accuracy<br />

Typical <strong>Application</strong>s<br />

⊲ Object recognition and localization<br />

⊲ Intermediate machine vision steps, e.g., alignment of ROIs<br />

⊲ Completeness check<br />

⊲ Parts inspection<br />

Involved Operators<br />

create_shape_model, create_scaled_shape_model<br />

inspect_shape_model, get_shape_model_params, determine_shape_model_params<br />

get_shape_model_contours, set_shape_model_origin, get_shape_model_origin<br />

find_shape_model, find_shape_models<br />

find_scaled_shape_model, find_scaled_shape_models<br />

write_shape_model, read_shape_model<br />

clear_shape_model, clear_all_shape_models<br />

Copyright c○ 2002-2008 by <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>, München, Germany <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>


Overview<br />

<strong>HALCON</strong>’s operators for shape-based matching enable you to find and localize objects based on a single<br />

model image, i.e., from a model. This method is robust to noise, clutter, occlusion, and arbitrary nonlinear<br />

illumination changes. Objects are localized with subpixel accuracy in 2D, i.e., found even if they<br />

are rotated or scaled.<br />

The process of shape-based matching (see section 1 on page 4 for a quick overview) is divided into two<br />

distinct phases: In a first phase, you specify and create the model. This model can be stored in a file to be<br />

reused in different applications. Detailed information about this phase can be found in section 2 on page<br />

6. In the second phase, the model is used to find and localize an object. Section 3 on page 20 describes<br />

how to optimize the outcome of this phase by restricting the search space.<br />

Shape-based matching is a powerful tool for various machine vision tasks, ranging from intermediate<br />

image processing, e.g., to place ROIs automatically or to align them to a moving part, to complex tasks,<br />

e.g., recognize and localize a part in a robot vision application. Examples can be found in section 4 on<br />

page 30.<br />

Unless specified otherwise, the example programs can be found in the subdirectory shape_matching<br />

of the directory <strong>HALCON</strong>ROOT \examples\application_guide.<br />

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in<br />

any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written<br />

permission of the publisher.<br />

Edition 1 June 2002 (<strong>HALCON</strong> 6.1)<br />

Edition 1a May 2003 (<strong>HALCON</strong> 6.1.2)<br />

Edition 2 December 2003 (<strong>HALCON</strong> 7.0)<br />

Edition 2a April 2005 (<strong>HALCON</strong> 7.0.2)<br />

Edition 3 July 2005 (<strong>HALCON</strong> 7.1)<br />

Microsoft, Windows, Windows NT, Windows 2000, and Windows XP are either trademarks or registered trademarks<br />

of Microsoft Corporation.<br />

All other nationally and internationally recognized trademarks and tradenames are hereby recognized.<br />

More information about <strong>HALCON</strong> can be found at:<br />

http://www.halcon.com/


Contents<br />

1 A First Example 4<br />

2 Creating a Suitable Model 6<br />

2.1 A Closer Look at the Region of Interest . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

2.2 Which Information is Stored in the Model? . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

2.3 Synthetic Model Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

3 Optimizing the Search Process 20<br />

3.1 Restricting the Search Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

3.2 Searching for Multiple Instances of the Object . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.3 Searching for Multiple Models Simultaneously . . . . . . . . . . . . . . . . . . . . . . 24<br />

3.4 A Closer Look at the Accuracy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

3.5 How to Optimize the Matching Speed . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

4 Using the Results of Matching 30<br />

4.1 Introducing Affine Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

4.2 Creating and Applying Affine Transformations With <strong>HALCON</strong> . . . . . . . . . . . . . . 30<br />

4.3 Using the Estimated Position and Orientation . . . . . . . . . . . . . . . . . . . . . . . 32<br />

4.4 Using the Estimated Scale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

5 Miscellaneous 46<br />

5.1 Adapting to a Changed Camera Orientation . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

5.2 Reusing Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

3


4 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

1 A First Example<br />

In this section we give a quick overview of the matching process. To follow the example actively, start<br />

the HDevelop program hdevelop\first_example_shape_matching.dev, which locates the print on<br />

an IC; the steps described below start after the initialization of the application (press Run once to reach<br />

this point).<br />

Step 1: Select the object in the model image<br />

Row1 := 188<br />

Column1 := 182<br />

Row2 := 298<br />

Column2 := 412<br />

gen_rectangle1 (ROI, Row1, Column1, Row2, Column2)<br />

reduce_domain (ModelImage, ROI, ImageROI)<br />

After grabbing the so-called model image, i.e., a representative image of the object to find, the first<br />

task is to create a region containing the object. In the example program, a rectangular region is created<br />

using the operator gen_rectangle1; alternatively, you can draw the region interactively using, e.g.,<br />

draw_rectangle1 or use a region that results from a previous segmentation process. Then, an image<br />

containing just the selected region is created using the operator reduce_domain. The result is shown in<br />

figure 1.<br />

Step 2: Create the model<br />

inspect_shape_model (ImageROI, ShapeModelImages, ShapeModelRegions, 8, 30)<br />

create_shape_model (ImageROI, NumLevels, 0, rad(360), ’auto’, ’none’,<br />

’use_polarity’, 30, 10, ModelID)<br />

With the operator create_shape_model, the so-called model is created, i.e., the internal data<br />

structure describing the searched object. Before this, we recommend to apply the operator inspect_shape_model,<br />

which helps you to find suitable parameters for the model creation. in-<br />

1○ 2○<br />

Figure 1: 1○ specifying the object; 2○ the internal model (4 pyramid levels).


Figure 2: Finding the object in other images.<br />

1 A First Example 5<br />

spect_shape_model shows the effect of two parameters: the number of pyramid levels on which the<br />

model is created, and the minimum contrast that object points must have to be included in the model. As<br />

a result, the operator inspect_shape_model returns the model points on the selected pyramid levels as<br />

shown in figure 1; thus, you can check whether the model contains the relevant information to describe<br />

the object of interest.<br />

When actually creating the model with the operator create_shape_model, you can specify additional<br />

parameters besides NumLevels and Contrast: First of all, you can restrict the range of angles the<br />

object can assume (parameters AngleStart and AngleExtent) and the angle steps at which the model<br />

is created (AngleStep). With the help of the parameter Optimization you can reduce the number<br />

of model points; this is useful in the case of very large models. Furthermore, you can switch on the<br />

pregeneration of the model for the allowed range of rotation. The parameter Metric lets you specify<br />

whether the polarity of the model points must be observed. Finally, you can specify the minimum<br />

contrast object points must have in the search images to be compared with the model (MinContrast).<br />

The creation of the model is described in detail in section 2.<br />

As a result, the operator create_shape_model returns a handle for the newly created model (ModelID),<br />

which can then be used to specify the model, e.g., in calls to the operator find_shape_model. <strong>Note</strong><br />

that if you use <strong>HALCON</strong>’s COM or C++ interface and call the operator via the classes HShapeModelX<br />

or HShapeModel, no handle is returned because the instance of the class itself acts as your handle.<br />

If not only the orientation but also the scale of the searched object is allowed to vary, you must use the<br />

operator create_scaled_shape_model to create the model; then, you can describe the allowed range<br />

of scaling with three parameters similar to the range of angles.<br />

Step 3: Find the object again<br />

for i := 1 to 20 by 1<br />

grab_image (SearchImage, FGHandle)<br />

find_shape_model (SearchImage, ModelID, 0, rad(360), 0.7, 1, 0.5,<br />

’least_squares’, 0, 0.9, RowCheck, ColumnCheck,<br />

AngleCheck, Score)<br />

endfor<br />

To find the object again in a search image, all you need to do is call the operator find_shape_model;<br />

figure 2 shows the result for one of the example images. Besides the already mentioned ModelID,<br />

First Example


6 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

find_shape_model provides further parameters to optimize the search process: The parameters AngleStart,<br />

AngleExtent, and NumLevels, which you already specified when creating the model, allow<br />

you to use more restrictive values in the search process; by using the value 0 for NumLevels, the value<br />

specified when creating the model is used. With the parameter MinScore you can specify how many of<br />

the model points must be found; a value of 0.5 means that half of the model must be found. Furthermore,<br />

you can specify how many instances of the object are expected in the image (NumMatches) and<br />

how much two instances of the object may overlap in the image (MaxOverlap). To compute the position<br />

of the found object with subpixel accuracy the parameter SubPixel should be set to a value different<br />

from ’none’. Finally, the parameter Greediness describes the used search heuristics, ranging from<br />

“safe but slow” (value 0) to “fast but unsafe” (value 1). How to optimize the search process is described<br />

in detail in section 3 on page 20.<br />

The operator find_shape_model returns the position and orientation of the found object instances in<br />

the parameters Row, Column, and Angle, and their corresponding Score, i.e., how much of the model<br />

was found.<br />

If you use the operator find_scaled_shape_model (after creating the model using create_scaled_shape_model),<br />

the scale of the found object is returned Scale.<br />

2 Creating a Suitable Model<br />

A prerequisite for a successful matching process is, of course, a suitable model for the object you want to<br />

find. A model is suitable if it describes the significant parts of the object, i.e., those parts that characterize<br />

it and allow to discriminate it clearly from other objects or from the background. On the other hand, the<br />

model should not contain clutter, i.e., points not belonging to the object (see, e.g., figure 4).<br />

2.1 A Closer Look at the Region of Interest<br />

When creating the model, the first step is to select a region of interest (ROI), i.e., the part of the image<br />

which serves as the model. In <strong>HALCON</strong>, a region defines an area in an image or, more generally, a set<br />

of points. A region can have an arbitrary shape; its points do not even need to be connected. Thus, the<br />

region of the model can have an arbitrary shape as well.<br />

The sections below describe how to create simple and more complex regions. The following code fragment<br />

shows the typical next steps after creating an ROI:<br />

reduce_domain (ModelImage, ROI, ImageROI)<br />

create_shape_model (ImageROI, 0, 0, rad(360), 0, ’none’, ’use_polarity’,<br />

30, 10, ModelID)<br />

<strong>Note</strong> that the region of interest used when creating a shape model influences the matching results: Its<br />

center of gravity is used as the reference point of the model (see section 2.1.4 on page 12 for more<br />

information).


2.1.1 How to Create a Region<br />

Figure 3: Creating an ROI from two regions.<br />

2.1.1 How to Create a Region 7<br />

<strong>HALCON</strong> offers multiple operators to create regions, ranging from standard shapes<br />

like rectangles (gen_rectangle2) or ellipses (gen_ellipse) to free-form shapes (e.g.,<br />

gen_region_polygon_filled). These operators can be found in the HDevelop menu Operators<br />

⊲ Regions ⊲ Creation.<br />

However, to use these operators you need the “parameters” of the shape you want to create, e.g., the<br />

position, size and, orientation of a rectangle or the position and radius of a circle. Therefore, they are<br />

typically combined with the operators in the HDevelop menu Operators ⊲ Graphics ⊲ Drawing, which<br />

let you draw a shape on the displayed image and then return the shape parameters:<br />

draw_rectangle1 (WindowHandle, ROIRow1, ROIColumn1, ROIRow2, ROIColumn2)<br />

gen_rectangle1 (ROI, ROIRow1, ROIColumn1, ROIRow2, ROIColumn2)<br />

2.1.2 How to Combine and Mask Regions<br />

You can create more complex regions by adding or subtracting standard regions using the operators<br />

union2 and difference. For example, to create an ROI containing the square and the cross in figure 3,<br />

the following code fragment was used:<br />

draw_rectangle1 (WindowHandle, ROI1Row1, ROI1Column1, ROI1Row2,<br />

ROI1Column2)<br />

gen_rectangle1 (ROI1, ROI1Row1, ROI1Column1, ROI1Row2, ROI1Column2)<br />

draw_rectangle1 (WindowHandle, ROI2Row1, ROI2Column1, ROI2Row2,<br />

ROI2Column2)<br />

gen_rectangle1 (ROI2, ROI2Row1, ROI2Column1, ROI2Row2, ROI2Column2)<br />

union2 (ROI1, ROI2, ROI)<br />

Similarly, you can subtract regions using the operator difference. This method is useful to “mask”<br />

those parts of a region containing clutter, i.e., high-contrast points that are not part of the object. In<br />

figure 4, e.g., the task is to find the three capacitors. When using a single circular ROI, the created model<br />

Model Creation


8 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

model for full−circle ROI<br />

model for ring−shaped ROI<br />

Figure 4: Masking the part of a region containing clutter.<br />

contains many clutter points, which are caused by reflections on the metallic surface. Thus, the other two<br />

capacitors are not found. The solution to this problem is to use a ring-shaped ROI, which can be created<br />

by the following lines of code:<br />

draw_circle (WindowHandle, ROI1Row, ROI1Column, ROI1Radius)<br />

gen_circle (ROI1, ROI1Row, ROI1Column, ROI1Radius)<br />

gen_circle (ROI2, ROI1Row, ROI1Column, ROI1Radius-8)<br />

difference (ROI1, ROI2, ROI)<br />

<strong>Note</strong> that the ROI should not be too “thin”, otherwise it vanishes at higher pyramid levels! As a rule<br />

of thumb, an ROI should be 2 NumLevels−1 pixels wide; in the example, the width of 8 pixels therefore<br />

allows to use 4 pyramid levels.<br />

For this task even better results can be obtained by using a synthetic model image. This is described in<br />

section 2.3 on page 18.


a)<br />

c)<br />

2.1.3 Using Image Processing to Create and Modify Regions 9<br />

Figure 5: Using image processing to create an ROI: a) extract bright regions; b) select the card; c) the<br />

logo forms the ROI; d) result of the matching.<br />

2.1.3 Using Image Processing to Create and Modify Regions<br />

In the previous sections, regions were created explicitly by specifying their shape parameters. Especially<br />

for complex ROIs this method can be inconvenient and time-consuming. In the following, we therefore<br />

show you how to extract and modify regions using image processing operators.<br />

Example 1: Determining the ROI Using Blob Analysis<br />

To follow the example actively, start the HDevelop program hdevelop\create_roi_via_vision.dev,<br />

which locates the <strong>MVTec</strong> logo on a pendulum (see figure 5);<br />

we start after the initialization of the application (press Run once). The main idea is to “zoom in” on the<br />

desired region in multiple steps: First, find the bright region corresponding to the card, then extract the<br />

dark characters on it.<br />

Step 1: Extract the bright regions<br />

threshold (ModelImage, BrightRegions, 200, 255)<br />

connection (BrightRegions, ConnectedRegions)<br />

fill_up (ConnectedRegions, FilledRegions)<br />

First, all bright regions are extracted using a simple thresholding operation (threshold); the operator<br />

b)<br />

d)<br />

Model Creation


10 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

connection forms connected components. The extracted regions are then filled up via fill_up; thus,<br />

the region corresponding to the card also encompasses the dark characters (see figure 5a).<br />

Step 2: Select the region of the card<br />

select_shape (FilledRegions, Card, ’area’, ’and’, 1800, 1900)<br />

The region corresponding to the card can be selected from the list of regions with the operator select_shape.<br />

In HDevelop, you can determine suitable features and values using the dialog Visualization<br />

⊲ Region Features; just click into a region, and the dialog immediately displays its feature<br />

values. Figure 5b shows the result of the operator.<br />

Step 3: Use the card as an ROI for the next steps<br />

reduce_domain (ModelImage, Card, ImageCard)<br />

Now, we can restrict the next image processing steps to the region of the card using the operator reduce_domain.<br />

This iterative focusing has an important advantage: In the restricted region of the card,<br />

the logo characters are much easier to extract than in the full image.<br />

Step 4: Extract the logo<br />

threshold (ImageCard, DarkRegions, 0, 230)<br />

connection (DarkRegions, ConnectedRegions)<br />

select_shape (ConnectedRegions, Characters, ’area’, ’and’, 150, 450)<br />

union1 (Characters, CharacterRegion)<br />

The logo characters are extracted similarly to the card itself; as a last step, the separate character regions<br />

are combined using the operator union1.<br />

Step 5: Enlarge the region using morphology<br />

dilation_circle (CharacterRegion, ROI, 1.5)<br />

reduce_domain (ModelImage, ROI, ImageROI)<br />

create_shape_model (ImageROI, ’auto’, 0, rad(360), ’auto’, ’none’,<br />

’use_polarity’, 30, 10, ModelID)<br />

Finally, the region corresponding to the logo is enlarged slightly using the operator dilation_circle.<br />

Figure 5c shows the resulting ROI, which is then used to create the shape model.<br />

Example 2: Further Processing the Result of inspect_shape_model<br />

You can also combine the interactive ROI specification with image processing. A useful method in the<br />

presence of clutter in the model image is to create a first model region interactively and then process<br />

this region to obtain an improved ROI. Figure 6 shows an example; the task is to locate the arrows. To<br />

follow the example actively, start the HDevelop program hdevelop\process_shape_model.dev; we<br />

start after the initialization of the application (press Run once).<br />

Step 1: Select the arrow<br />

gen_rectangle1 (ROI, 361, 131, 406, 171)<br />

First, an initial ROI is created around the arrow, without trying to exclude clutter (see figure 6a).


a)<br />

b)<br />

c)<br />

d)<br />

model for<br />

Contrast = 30<br />

processed region<br />

2.1.3 Using Image Processing to Create and Modify Regions 11<br />

model for<br />

Contrast = 90<br />

model for<br />

Contrast = 134<br />

final ROI final model<br />

Figure 6: Processing the result of inspect_shape_model: a) interactive ROI; b) models for different values<br />

of Contrast; c) processed model region and corresponding ROI and model; d) result of the<br />

search.<br />

Step 2: Create a first model region<br />

reduce_domain (ModelImage, ROI, ImageROI)<br />

inspect_shape_model (ImageROI, ShapeModelImage, ShapeModelRegion, 1, 30)<br />

Figure 6b shows the shape model regions that would be created for different values of the parameter<br />

Contrast. As you can see, you cannot remove the clutter without losing characteristic points of the<br />

arrow itself.<br />

Step 3: Process the model region<br />

fill_up (ShapeModelRegion, FilledModelRegion)<br />

opening_circle (FilledModelRegion, ROI, 3.5)<br />

You can solve this problem by exploiting the fact that the operator inspect_shape_model returns the<br />

shape model region; thus, you can process it like any other region. The main idea to get rid of the clutter<br />

is to use morphological operator opening_circle, which eliminates small regions. Before this, the<br />

Model Creation


12 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

operator fill_up must be called to fill the inner part of the arrow, because only the boundary points are<br />

part of the (original) model region. Figure 6c shows the resulting region.<br />

Step 4: Create the final model<br />

reduce_domain (ModelImage, ROI, ImageROI)<br />

create_shape_model (ImageROI, 3, 0, rad(360), ’auto’, ’none’,<br />

’use_polarity’, 30, 10, ModelID)<br />

The processed region is then used to create the model; figure 6c shows the corresponding ROI and the<br />

final model region. Now, all arrows are located successfully.<br />

2.1.4 How the ROI Influences the Search<br />

<strong>Note</strong> that the ROI used when creating the model also influences the results of the subsequent matching:<br />

By default, the center point of the ROI acts as the so-called point of reference of the model for the<br />

estimated position, rotation, and scale. After creating a model, you can change its point of reference<br />

with the operator set_shape_model_origin. <strong>Note</strong> that this operator expects not the absolute position<br />

of the new reference point as parameters, but its distance to the default reference point. Please note that<br />

by modifying the point of reference, the accuracy of the estimated position may decrease (see section 3.4<br />

on page 26). You can query the reference point using the operator get_shape_model_origin<br />

The point of reference also influences the search itself: An object is only found if the point of reference<br />

lies within the image, or more exactly, within the domain of the image (see also section 3.1.1 on page<br />

20). Please note that this test is always performed for the original point of reference, i.e., the center point<br />

of the ROI, even if you modified the reference point using set_shape_model_origin.<br />

2.2 Which Information is Stored in the Model?<br />

As the name shape-based pattern matching suggests, objects are represented and recognized by their<br />

shape. There exist multiple ways to determine or describe the shape of an object. Here, the shape is<br />

extracted by selecting all those points whose contrast exceeds a certain threshold; typically, the points<br />

correspond to the contours of the object (see, e.g., figure 1 on page 4). Section 2.2.1 takes a closer look<br />

at the corresponding parameters.<br />

To speed up the matching process, a so-called image pyramid is created, consisting of the original, fullsized<br />

image and a set of downsampled images. The model is then created and searched on the different<br />

pyramid levels (see section 2.2.2 on page 14 for details).<br />

In the following, all parameters belong to the operator create_shape_model if not stated otherwise.<br />

2.2.1 Which Pixels are Part of the Model?<br />

For the model those pixels are selected whose contrast, i.e., gray value difference to neighboring pixels,<br />

exceeds a threshold specified by the parameter Contrast when calling create_shape_model. In order<br />

to obtain a suitable model the contrast should be chosen in such a way that the significant pixels of the<br />

object are included, i.e., those pixels that characterize it and allow to discriminate it clearly from other


a)<br />

c)<br />

2.2.1 Which Pixels are Part of the Model? 13<br />

Figure 7: Selecting significant pixels via Contrast: a) complete object but with clutter; b) no clutter but<br />

incomplete object; c) hysteresis threshold; d) minimum contour size.<br />

objects or from the background. Obviously, the model should not contain clutter, i.e., pixels that do not<br />

belong to the object.<br />

In some cases it is impossible to find a single value for Contrast that removes the clutter but not also<br />

parts of the object. Figure 7 shows an example; the task is to create a model for the outer rim of a drillhole:<br />

If the complete rim is selected, the model also contains clutter (figure 7a); if the clutter is removed,<br />

parts of the rim are missing (figure 7b).<br />

To solve such problems, the parameter Contrast provides two additional methods: hysteresis thresholding<br />

and selection of contour parts based on their size. Both methods are used by specifying a tuple of<br />

values for Contrast instead of a single value.<br />

Hysteresis thresholding (see also the operator hysteresis_threshold) uses two thresholds, a lower<br />

and an upper threshold. For the model, first pixels that have a contrast higher than the upper threshold<br />

are selected; then, pixels that have a contrast higher than the lower threshold and that are connected to a<br />

high-contrast pixel, either directly or via another pixel with contrast above the lower threshold, are added.<br />

This method enables you to select contour parts whose contrast varies from pixel to pixel. Returning to<br />

the example of the drill-hole: As you can see in figure 7c, with a hysteresis threshold you can create a<br />

model for the complete rim without clutter. The following line of code shows how to specify the two<br />

thresholds in a tuple:<br />

inspect_shape_model (ImageROI, ModelImages, ModelRegions, 1, [26,52])<br />

The second method to remove clutter is to specify a minimum size, i.e., number of pixels, for the contour<br />

components. Figure 7d shows the result for the example task. The minimum size must be specified in<br />

b)<br />

d)<br />

Model Creation


14 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

the third element of the tuple; if you don’t want to use a hysteresis threshold, set the first two elements<br />

to the same value:<br />

inspect_shape_model (ImageROI, ModelImages, ModelRegions, 1, [26,26,12])<br />

Alternative methods to remove clutter are to modify the ROI as described in section 2.1 on page 6 or<br />

create a synthetic model (see section 2.3 on page 18).<br />

You can let let <strong>HALCON</strong> select suitable values itself by specifying the value ’auto’ for Contrast.<br />

You can query the used values via the operator determine_shape_model_params. If you want to<br />

specify some of the three contrast parameters and let <strong>HALCON</strong> determine the rest, please refer to the<br />

Reference Manual for detailed information.<br />

2.2.2 How Subsampling is Used to Speed Up the Search<br />

To speed up the matching process, a so-called image pyramid is created, both for the model image and<br />

for the search images. The pyramid consists of the original, full-sized image and a set of downsampled<br />

images. For example, if the original image (first pyramid level) is of the size 600x400, the second level<br />

image is of the size 300x200, the third level 150x100, and so on. The object is then searched first on the<br />

highest pyramid level, i.e., in the smallest image. The results of this fast search are then used to limit the<br />

search in the next pyramid image, whose results are used on the next lower level until the lowest level is<br />

reached. Using this iterative method, the search is both fast and accurate. Figure 8 depicts 4 levels of an<br />

example image pyramid together with the corresponding model regions.<br />

You can specify how many pyramid levels are used via the parameter NumLevels. We recommend<br />

to choose the highest pyramid level at which the model contains at least 10-15 pixels and in which<br />

the shape of the model still resembles the shape of the object. You can inspect the model image<br />

pyramid using the operator inspect_shape_model, e.g., as shown in the HDevelop program hdevelop\first_example_shape_matching.dev:<br />

inspect_shape_model (ImageROI, ShapeModelImages, ShapeModelRegions, 8, 30)<br />

area_center (ShapeModelRegions, AreaModelRegions, RowModelRegions,<br />

ColumnModelRegions)<br />

HeightPyramid := |ShapeModelRegions|<br />

for i := 1 to HeightPyramid by 1<br />

if (AreaModelRegions[i-1] >= 15)<br />

NumLevels := i<br />

endif<br />

endfor<br />

create_shape_model (ImageROI, NumLevels, 0, rad(360), ’auto’, ’none’,<br />

’use_polarity’, 30, 10, ModelID)<br />

After the call to the operator, the model regions on the selected pyramid levels are displayed in HDevelop’s<br />

Graphics Window; you can have a closer look at them using the online zooming (menu entry<br />

Visualization ⊲ Online Zooming). The code lines following the operator call loop through the<br />

pyramid and determine the highest level on which the model contains at least 15 points. This value is<br />

then used in the call to the operator create_shape_model.<br />

A much easier method is to let <strong>HALCON</strong> select a suitable value itself by specifying the value ’auto’<br />

for NumLevels. You can then query the used value via the operator get_shape_model_params.


2.2.2 How Subsampling is Used to Speed Up the Search 15<br />

Figure 8: The image and the model region at four pyramid levels (original size and zoomed to equal size).<br />

The operator inspect_shape_model returns the pyramid images in form of an image tuple (array); the<br />

individual images can be accessed like the model regions with the operator select_obj. Please note<br />

that object tuples start with the index 1, whereas control parameter tuples start with the index 0! !<br />

You can enforce a further reduction of model points via the parameter Optimization. This may be<br />

useful to speed up the matching in the case of particularly large models. We recommend to specify<br />

the value ’auto’ to let <strong>HALCON</strong> select a suitable value itself. Please note that regardless of your<br />

selection all points passing the contrast criterion are displayed, i.e., you cannot check which points are<br />

part of the model.<br />

Model Creation


16 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

With an optional second value, you can specify whether the model is pregenerated completely for the<br />

allowed range of rotation and scale (see the following sections) or not. By default, the model is not<br />

pregenerated. You can pregenerate the model and thereby speed up the matching process by passing<br />

’pregeneration’ as the second value of Optimization. Alternatively, you can set this parameter via<br />

the operator set_system. <strong>Note</strong>, however, that if you allow large ranges of rotation and/or scaling, the<br />

memory requirements rise. Another effect is that the process of creating the model takes significantly<br />

more time.<br />

2.2.3 Allowing a Range of Orientation<br />

If the object’s rotation may vary in the search images you can specify the allowed range in the parameter<br />

AngleExtent and the starting angle of this range in the parameter AngleStart (unit: rad). <strong>Note</strong> that<br />

the range of rotation is defined relative to the model image, i.e., a starting angle of 0 corresponds to the<br />

orientation the object has in the model image. Therefore, to allow rotations up to +/-5 ◦ , e.g., you should<br />

set the starting angle to -rad(5) and the angle extent to rad(10).<br />

We recommend to limit the allowed range of rotation as much as possible in order to speed up the<br />

search process. If you pregenerate the model (see page 16), a large range of rotation also leads to high<br />

memory requirements. <strong>Note</strong> that you can further limit the allowed range when calling the operator<br />

find_shape_model (see section 3.1.2 on page 21). If you want to reuse a model for different tasks<br />

requiring a different range of angles, you can therefore use a large range when creating the model and a<br />

smaller range for the search.<br />

If the object is (almost) symmetric you should limit the allowed range. Otherwise, the search process<br />

will find multiple, almost equally good matches on the same object at different angles; which match (at<br />

which angle) is returned as the best can therefore “jump” from image to image. The suitable range of<br />

rotation depends on the symmetry: For a cross-shaped or square object the allowed extent must be less<br />

than 90 ◦ , for a rectangular object less than 180 ◦ , and for a circular object 0 ◦ .<br />

During the matching process, the model is searched for in different angles within the allowed range, at<br />

steps specified with the parameter AngleStep. If you select the value ’auto’, <strong>HALCON</strong> automatically<br />

chooses an optimal step size φopt to obtain the highest possible accuracy by determining the smallest<br />

rotation that is still discernible in the image. The underlying algorithm is explained in figure 9: The<br />

rotated version of the cross-shaped object is clearly discernible from the original if the point that lies<br />

farthest from the center of the object is moved by at least 2 pixels. Therefore, the corresponding angle<br />

Figure 9: Determining the minimum angle step size from the extent of the model.<br />

φ<br />

l<br />

l<br />

d


φopt is calculated as follows:<br />

2.2.4 Allowing a Range of Scale 17<br />

d 2 = l 2 + l 2 �<br />

− 2 · l · l · cos φ ⇒ φopt = arccos 1 − d2<br />

2 · l2 � �<br />

= arccos 1 − 2<br />

l2 �<br />

with l being the maximum distance between the center and the object boundary and d = 2 pixels.<br />

The automatically determined angle step size φopt is suitable for most applications; therefore, we recommend<br />

to select the value ’auto’ . You can query the used value after the creation via the operator<br />

get_shape_model_params. By selecting a higher value you can speed up the search process, however,<br />

at the cost of a decreased accuracy of the estimated orientation. <strong>Note</strong> that for very high values the<br />

matching may fail altogether!<br />

The value chosen for AngleStep should not deviate too much from the optimal value ( 1<br />

3 φopt ≤ φ ≤<br />

3φopt). <strong>Note</strong> that choosing a very small step size does not result in an increased angle accuracy!<br />

2.2.4 Allowing a Range of Scale<br />

Similarly to the range of orientation, you can specify an allowed range of scale with the parameters<br />

ScaleMin, ScaleMax, and ScaleStep of the operator create_scaled_shape_model.<br />

Again, we recommend to limit the allowed range of scale as much as possible in order to speed up<br />

the search process. If you pregenerate the model (see page 16), a large range of scale also leads to<br />

high memory requirements. <strong>Note</strong> that you can further limit the allowed range when calling the operator<br />

find_scaled_shape_model (see section 3.1.2 on page 21).<br />

<strong>Note</strong> that if you are searching for the object on a large range of scales you should create the model based<br />

on a large scale because <strong>HALCON</strong> cannot “guess” model points when precomputing model instances at<br />

scales larger than the original one. On the other hand, NumLevels should be chosen such that the highest<br />

level contains enough model points also for the smallest scale.<br />

If you select the value ’auto’ for the parameter ScaleStep, <strong>HALCON</strong> automatically chooses a suitable<br />

step size to obtain the highest possible accuracy by determining the smallest scale change that is still<br />

discernible in the image. Similarly to the angle step size (see figure 9 on page 16), a scaled object is<br />

clearly discernible from the original if the point that lies farthest from the center of the object is moved<br />

by at least 2 pixels. Therefore, the corresponding scale change ∆sopt is calculated as follows:<br />

∆s = d<br />

l ⇒ ∆sopt = 2<br />

l<br />

with l being the maximum distance between the center and the object boundary and d = 2 pixels.<br />

The automatically determined scale step size is suitable for most applications; therefore, we recommend<br />

to select the value ’auto’ . You can query the used value after the creation via the operator<br />

get_shape_model_params. By selecting a higher value you can speed up the search process, however,<br />

at the cost of a decreased accuracy of the estimated scale. <strong>Note</strong> that for very high values the matching<br />

may fail altogether!<br />

The value chosen for ScaleStep should not deviate too much from the optimal value ( 1<br />

3 ∆sopt ≤ ∆s ≤<br />

3∆sopt). <strong>Note</strong> that choosing a very small step size does not result in an increased scale accuracy!<br />

Model Creation


18 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

2.2.5 Which Pixels are Compared with the Model?<br />

For efficiency reasons the model contains information that influences the search process: With the parameter<br />

MinContrast you can specify which contrast a point in a search image must at least have in<br />

order to be compared with the model. The main use of this parameter is to exclude noise, i.e., gray value<br />

fluctuations, from the matching process. You can determine the noise by examining the gray values with<br />

the HDevelop dialog Visualization ⊲ Pixel Info; then, set the minimum contrast to a value larger<br />

than the noise. Alternatively, you can let <strong>HALCON</strong> select suitable values itself by specifying the value<br />

’auto’ for MinContrast.<br />

The parameter Metric lets you specify whether the polarity, i.e., the direction of the contrast must be<br />

observed. If you choose the value ’use_polarity’ the polarity is observed, i.e., the points in the<br />

search image must show the same direction of the contrast as the corresponding points in the model. If,<br />

for example, the model is a bright object on a dark background, the object is found in the search images<br />

only if it is also brighter than the background.<br />

You can choose to ignore the polarity globally by selecting the value ’ignore_global_polarity’. In<br />

this mode, an object is recognized also if the direction of its contrast reverses, e.g., if your object can<br />

appear both as a dark shape on a light background and vice versa. This flexibility, however, is obtained<br />

at the cost of a slightly lower recognition speed.<br />

If you select the value ’ignore_local_polarity’, the object is found even if the contrast changes<br />

locally. This mode can be useful, e.g., if the object consists of a part with a medium gray value, within<br />

which either darker of brighter sub-objects lie. Please note however, that the recognition speed may<br />

decrease dramatically in this mode, especially if you allowed a large range of rotation (see section 2.2.3<br />

on page 16).<br />

2.3 Synthetic Model Images<br />

Depending on the application it may be difficult to create a suitable model because there is no “good”<br />

model image containing a perfect, easy to extract instance of the object. An example of such a case was<br />

already shown in section 2.1.2 on page 7: The task of locating the capacitors seems to be simple at first,<br />

as they are prominent bright circles on a dark background. But because of the clutter inside and outside<br />

the circle even the model resulting from the ring-shaped ROI is faulty: Besides containing clutter points<br />

also parts of the circle are missing.<br />

In such cases, it may be better to use a synthetic model image. How to create such an image to locate<br />

the capacitors is explained below. To follow the example actively, start the HDevelop program hdevelop\synthetic_circle.dev;<br />

we start after the initialization of the application (press Run once).<br />

Step 1: Create an XLD contour<br />

RadiusCircle := 43<br />

SizeSynthImage := 2*RadiusCircle + 10<br />

gen_ellipse_contour_xld (Circle, SizeSynthImage / 2, SizeSynthImage / 2, 0,<br />

RadiusCircle, RadiusCircle, 0, 6.28318,<br />

’positive’, 1.5)<br />

First, we create a circular region using the operator gen_ellipse_contour_xld (see figure 10a). You<br />

can determine a suitable radius by inspecting the image with the HDevelop dialog Visualization ⊲


a) b)<br />

c)<br />

2.3 Synthetic Model Images 19<br />

Figure 10: Locating the capacitors using a synthetic model: a) paint region into synthetic image; b) corresponding<br />

model; c) result of the search.<br />

Online Zooming. <strong>Note</strong> that the synthetic image should be larger than the region because pixels around<br />

the region are used when creating the image pyramid.<br />

Step 2: Create an image and insert the XLD contour<br />

gen_image_const (EmptyImage, ’byte’, SizeSynthImage, SizeSynthImage)<br />

paint_xld (Circle, EmptyImage, SyntheticModelImage, 128)<br />

Then, we create an empty image using the operator gen_image_const and insert the XLD contour with<br />

the operator paint_xld. In figure 10a the resulting image is depicted.<br />

Step 3: Create the model<br />

create_scaled_shape_model (SyntheticModelImage, ’auto’, 0, 0, 0.01, 0.8,<br />

1.2, ’auto’, ’none’, ’use_polarity’, 30, 10,<br />

Now, the model is created from the synthetic image. Figure 10d shows the corresponding model region,<br />

figure 10e the search results.<br />

<strong>Note</strong> how the image itself, i.e., its domain, acts as the ROI in this example.<br />

Model Creation


20 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

3 Optimizing the Search Process<br />

The actual matching is performed by the operators find_shape_model, find_scaled_shape_model,<br />

find_shape_models, or find_scaled_shape_models. In the following, we show how to select suitable<br />

parameters for these operators to adapt and optimize it for your matching task.<br />

3.1 Restricting the Search Space<br />

An important concept in the context of finding objects is that of the so-called search space. Quite<br />

literally, this term specifies where to search for the object. However, this space encompasses not only the<br />

2 dimensions of the image, but also other parameters like the possible range of scales and orientations or<br />

the question of how much of the object must be visible. The more you can restrict the search space, the<br />

faster the search will be.<br />

3.1.1 Searching in a Region of Interest<br />

The obvious way to restrict the search space is to apply the operator find_shape_model to a region of<br />

interest only instead of the whole image as shown in figure 11. This can be realized in a few lines of<br />

code:<br />

Step 1: Create a region of interest<br />

Row1 := 141<br />

Column1 := 163<br />

Row2 := 360<br />

Column2 := 477<br />

gen_rectangle1 (SearchROI, Row1, Column1, Row2, Column2)<br />

First, you create a region, e.g., with the operator gen_rectangle1 (see section 2.1.1 on page 7 for more<br />

ways to create regions).<br />

Figure 11: Searching in a region of interest.


Step 2: Restrict the search to the region of interest<br />

3.1.2 Restricting the Range of Orientation and Scale 21<br />

for i := 1 to 20 by 1<br />

grab_image (SearchImage, FGHandle)<br />

reduce_domain (SearchImage, SearchROI, SearchImageROI)<br />

find_shape_model (SearchImageROI, ModelID, 0, rad(360), 0.8, 1, 0.5,<br />

’interpolation’, 0, 0.9, RowCheck, ColumnCheck,<br />

AngleCheck, Score)<br />

endfor<br />

The region of interest is then applied to each search image using the operator reduce_domain. In this<br />

example, the searching speed is almost doubled using this method.<br />

<strong>Note</strong> that by restricting the search to a region of interest you actually restrict the position of the point of<br />

reference of the model, i.e., the center of gravity of the model ROI (see section 2.1.4 on page 12). This<br />

means that the size of the search ROI corresponds to the extent of the allowed movement; for example,<br />

if your object can move ± 10 pixels vertically and ± 15 pixels horizontally you can restrict the search<br />

to an ROI of the size 20×30. In order to assure a correct boundary treatment on higher pyramid levels,<br />

we recommend to enlarge the ROI by 2 NumLevels−1 pixels; to continue the example, if you specified<br />

NumLevels = 4, you can restrict the search to an ROI of the size 36×46.<br />

Please note that even if you modify the point of reference using set_shape_model_origin, the original<br />

one, i.e., the center point of the model ROI, is used during the search. Thus, you must always specify the<br />

search ROI relative to the original reference point.<br />

3.1.2 Restricting the Range of Orientation and Scale<br />

When creating the model with the operator create_shape_model (or create_scaled_shape_model),<br />

you already specified the allowed range of orientation and scale (see<br />

section 2.2.3 on page 16 and section 2.2.4 on page 17). When calling the operator find_shape_model<br />

(or find_scaled_shape_model) you can further limit these ranges with the parameters AngleStart,<br />

AngleExtent, ScaleMin, and ScaleMax. This is useful if you can restrict these ranges by other<br />

information, which can, e.g., be obtained by suitable image processing operations.<br />

Another reason for using a larger range when creating the model may be that you want to reuse the model<br />

for other matching tasks.<br />

3.1.3 Visibility<br />

With the parameter MinScore you can specify how much of the object — more precisely: of the model<br />

— must be visible. A typical use of this mechanism is to allow a certain degree of occlusion as demonstrated<br />

in figure 12: The security ring is found if MinScore is set to 0.7.<br />

Let’s take a closer look at the term “visibility”: When comparing a part of a search image with the model,<br />

the matching process calculates the so-called score, which is a measure of how many model points could<br />

be matched to points in the search image (ranging from 0 to 1). A model point may be “invisible” and<br />

thus not matched because of multiple reasons:<br />

Optimal Search


22 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

a)<br />

b) c)<br />

Figure 12: Searching for partly occluded objects: a) model of the security ring; b) search result for<br />

MinScore = 0.8; c) search result for MinScore = 0.7.<br />

• Parts of the object’s contour are occluded, e.g., as in figure 12.<br />

Please note that an object must not be clipped at the image border; this case is not treated as an !<br />

occlusion! More precisely, the smallest rectangle surrounding the model must not be clipped.<br />

• Parts of the contour have a contrast lower than specified in the parameter MinContrast when<br />

creating the model (see section 2.2.5 on page 18).<br />

• The polarity of the contrast changes globally or locally (see section 2.2.5 on page 18).<br />

• If the object is deformed, parts of the contour may be visible but appear at an incorrect position<br />

and therefore do not fit the model anymore. <strong>Note</strong> that this effect also occurs if camera observes the<br />

scene under an oblique angle; section 5.1 on page 46 shows how to handle this case.<br />

Besides these obvious reasons, which have their root in the search image, there are some not so obvious<br />

reasons caused by the matching process itself:<br />

• As described in section 2.2.3 on page 16, <strong>HALCON</strong> precomputes the model for intermediate angles<br />

within the allowed range of orientation. During the search, a candidate match is then compared<br />

to all precomputed model instances. If you select a value for the parameter AngleStep that is<br />

significantly larger than the automatically selected minimum value, the effect depicted in figure 13<br />

can occur: If the object lies between two precomputed angles, points lying far from the center are<br />

not matched to a model point, and therefore the score decreases.<br />

Of course, the same line of reasoning applies to the parameter ScaleStep (see section 2.2.4 on<br />

page 17).<br />

• Another stumbling block lies in the use of an image pyramid which was introduced in section 2.2.2<br />

on page 14: When comparing a candidate match with the model, the specified minimum score<br />

must be reached on each pyramid level. However, on different levels the score may vary, with<br />

only the score on the lowest level being returned in the parameter Score; this sometimes leads to<br />

the apparently paradox situation that MinScore must be set significantly lower than the resulting<br />

Score.<br />

Recommendation: The higher MinScore, the faster the search!


3.1.4 Thoroughness vs. Speed<br />

AngleStep = 20 AngleStep = 30<br />

Figure 13: The effect of a large AngleStep on the matching.<br />

3.1.4 Thoroughness vs. Speed 23<br />

With the parameter Greediness you can influence the search algorithm itself and thereby trade thoroughness<br />

against speed. If you select the value 0, the search is thorough, i.e., if the object is present<br />

(and within the allowed search space and reaching the minimum score), it will be found. In this mode,<br />

however, even very unlikely match candidates are also examined thoroughly, thereby slowing down the<br />

matching process considerably.<br />

The main idea behind the “greedy” search algorithm is to break off the comparison of a candidate with<br />

the model when it seems unlikely that the minimum score will be reached. In other words, the goal is<br />

not to waste time on hopeless candidates. This greediness, however, can have unwelcome consequences:<br />

In some cases a perfectly visible object is not found because the comparison “starts out on a wrong foot”<br />

and is therefore classified as a hopeless candidate and broken off.<br />

You can adjust the Greediness of the search, i.e., how early the comparison is broken off, by selecting<br />

values between 0 (no break off: thorough but slow) and 1 (earliest break off: fast but unsafe). <strong>Note</strong><br />

that the parameters Greediness and MinScore interact, i.e., you may have to specify a lower minimum<br />

score in order to use a greedier search. Generally, you can reach a higher speed with a high greediness<br />

and a sufficiently lowered minimum score.<br />

3.2 Searching for Multiple Instances of the Object<br />

All you have to do to search for more than one instance of the object is to set the parameter Num-<br />

Matches accordingly. The operator find_shape_model (or find_scaled_shape_model) then returns<br />

the matching results as tuples in the parameters Row, Column, Angle, Scale, and Score. If you<br />

select the value 0, all matches are returned.<br />

<strong>Note</strong> that a search for multiple objects is only slightly slower than a search for a single object.<br />

A second parameter, MaxOverlap, lets you specify how much two matches may overlap (as a fraction).<br />

In figure 14b, e.g., the two security rings overlap by a factor of approximately 0.2. In order to speed up<br />

the matching as far as possible, however, the overlap is calculated not for the models themselves but for<br />

their smallest surrounding rectangle. This must be kept in mind when specifying the maximum overlap;<br />

in most cases, therefore a larger value is needed (e.g., compare figure 14b and figure 14d).<br />

Optimal Search


24 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

a) c)<br />

b)<br />

d)<br />

Figure 14: A closer look at overlapping matches: a) model of the security ring; b) model overlap; c)<br />

smallest rectangle surrounding the model; d) rectangle overlap; e) pathological case.<br />

Figure 14e shows a “pathological” case: Even though the rings themselves do not overlap, their surrounding<br />

rectangles do to a large degree. Unfortunately, this effect cannot be prevented.<br />

3.3 Searching for Multiple Models Simultaneously<br />

If you are searching for instances of multiple models in a single image, you can of course call the operator<br />

find_shape_model (or find_scaled_shape_model) multiple times. A much faster alternative is<br />

to use the operators find_shape_models or find_scaled_shape_models instead. These operators<br />

expect similar parameters, with the following differences:<br />

• With the parameter ModelIDs you can specify a tuple of model IDs instead of a single one. As<br />

when searching for multiple instances (see section 3.2 on page 23), the matching result parameters<br />

Row etc. return tuples of values.<br />

• The output parameter Model shows to which model each found instance belongs. <strong>Note</strong> that the<br />

parameter does not return the model IDs themselves but the index of the model ID in the tuple<br />

ModelIDs (starting with 0).<br />

• The search is always performed in a single image. However, you can restrict the search to a certain<br />

region for each model individually by passing an image tuple (see below for an example).<br />

• You can either use the same search parameters for each model by specifying single values for<br />

AngleStart etc., or pass a tuple containing individual values for each model.<br />

e)


a)<br />

b)<br />

3.3 Searching for Multiple Models Simultaneously 25<br />

Figure 15: Searching for multiple models : a) models of ring and nut; b) search ROIs for the two models.<br />

• You can also search for multiple instances of multiple models. If you search for a certain number<br />

of objects independent of their type (model ID), specify this (single) value in the parameter Num-<br />

Matches. By passing a tuple of values, you can specify for each model individually how many<br />

instances are to be found. In this tuple, you can mix concrete values with the value 0; the tuple<br />

[3,0], e.g., specifies to return the best 3 instances of the first model and all instances of the second<br />

model.<br />

Similarly, if you specify a single value for MaxOverlap, the operators check whether a found<br />

instance is overlapped by any of the other instances independent of their type. By specifying a<br />

tuple of values, each instance is only checked against all other instances of the same type.<br />

The example HDevelop program hdevelop\multiple_models.dev uses the operator<br />

find_scaled_shape_models to search simultaneously for the rings and nuts depicted in figure 15.<br />

Step 1: Create the models<br />

create_scaled_shape_model (ImageROIRing, ’auto’, -rad(22.5), rad(45),<br />

’auto’, 0.8, 1.2, ’auto’, ’none’,<br />

’use_polarity’, 60, 10, ModelIDRing)<br />

create_scaled_shape_model (ImageROINut, ’auto’, -rad(30), rad(60), ’auto’,<br />

0.6, 1.4, ’auto’, ’none’, ’use_polarity’, 60,<br />

10, ModelIDNut)<br />

ModelIDs := [ModelIDRing, ModelIDNut]<br />

First, two models are created, one for the rings and one for the nuts. The two model IDs are then<br />

concatenated into a tuple using the operator assign.<br />

Optimal Search


26 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

Step 2: Specify individual search ROIs<br />

gen_rectangle1 (SearchROIRing, 110, 10, 130, Width - 10)<br />

gen_rectangle1 (SearchROINut, 315, 10, 335, Width - 10)<br />

SearchROIs := [SearchROIRing,SearchROINut]<br />

add_channels (SearchROIs, SearchImage, SearchImageReduced)<br />

In the example, the rings and nuts appear in non-overlapping parts of the search image; therefore, it is<br />

possible to restrict the search space for each model individually. As explained in section 3.1.1 on page<br />

20, a search ROI corresponds to the extent of the allowed movement; thus, narrow horizontal ROIs can<br />

be used in the example (see figure 15b).<br />

The two ROIs are concatenated into a region array (tuple) using the operator concat_obj and then<br />

“added” to the search image using the operator add_channels. The result of this operator is an array<br />

of two images, both having the same image matrix; the domain of the first image is restricted to the first<br />

ROI, the domain of the second image to the second ROI.<br />

Step 3: Find all instances of the two models<br />

find_scaled_shape_models (SearchImageReduced, ModelIDs, [-rad(22.5),<br />

-rad(30)], [rad(45), rad(60)], [0.8, 0.6], [1.2,<br />

1.4], 0.7, 0, 0, ’least_squares’, 0, 0.8,<br />

RowCheck, ColumnCheck, AngleCheck, ScaleCheck,<br />

Score, ModelIndex)<br />

Now, the operator find_scaled_shape_models is applied to the created image array. Because the<br />

two models allow different ranges of rotation and scaling, tuples are specified for the corresponding<br />

parameters. In contrast, the other parameters are are valid for both models. Section 4.3.3 on page 35<br />

shows how to access the matching results.<br />

3.4 A Closer Look at the Accuracy<br />

During the matching process, candidate matches are compared with instances of the model at different<br />

positions, angles, and scales; for each instance, the resulting matching score is calculated. If you set<br />

the parameter SubPixel to ’none’, the result parameters Row, Column, Angle, and Scale contain<br />

the corresponding values of the best match. In this case, the accuracy of the position is therefore 1<br />

pixel, while the accuracy of the orientation and scale is equal to the values selected for the parameters<br />

AngleStep and ScaleStep, respectively, when creating the model (see section 2.2.3 on page 16 and<br />

section 2.2.4 on page 17).<br />

If you set the parameter SubPixel to ’interpolation’, <strong>HALCON</strong> examines the matching scores at<br />

the neighboring positions, angles, and scales around the best match and determines the maximum by<br />

interpolation. Using this method, the position is therefore estimated with subpixel accuracy (≈ 1<br />

20 pixel<br />

in typical applications). The accuracy of the estimated orientation and scale depends on the size of the<br />

object, like the optimal values for the parameters AngleStep and ScaleStep (see section 2.2.3 on page<br />

16 and section 2.2.4 on page 17): The larger the size, the more accurately the orientation and scale can<br />

be determined. For example, if the maximum distance between the center and the boundary is 100 pixel,<br />

◦ .<br />

the orientation is typically determined with an accuracy of ≈ 1<br />

10


new<br />

p. of ref.<br />

original<br />

p. of ref.<br />

3.4 A Closer Look at the Accuracy 27<br />

model rotation rotation inaccuracy<br />

Figure 16: Effect of inaccuracy of the estimated orientation on a moved point of reference.<br />

Recommendation: Because the interpolation is very fast, you can set SubPixel to ’interpolation’<br />

in most applications.<br />

When you choose the values ’least_squares’, ’least_squares_high’, or<br />

’least_squares_very_high’, a least-squares adjustment is used instead of an interpolation,<br />

resulting in a higher accuracy. However, this method requires additional computation time.<br />

Please note that the accuracy of the estimated position may decrease if you modify the point of !<br />

reference using set_shape_model_origin! This effect is visualized in figure 16: As you can see<br />

in the right-most column, an inaccuracy in the estimated orientation “moves” the modified point of<br />

reference, while the original point of reference is not affected. The resulting positional error depends<br />

on multiple factors, e.g., the offset of the reference point and the orientation of the found object. The<br />

main point to keep in mind is that the error increases linearly with the distance of the modified point of<br />

reference from the original one (compare the two rows in figure 16).<br />

An inaccuracy in the estimated scale also results in an error in the estimated position, which again<br />

increases linearly with the distance between the modified and the original reference point.<br />

For maximum accuracy in case the reference point is moved, the position should be determined using the<br />

least-squares adjustment. <strong>Note</strong> that the accuracy of the estimated orientation and scale is not influenced<br />

by modifying the reference point.<br />

Optimal Search


28 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

!<br />

3.5 How to Optimize the Matching Speed<br />

If high memory requirements are no problem for your application, a simple way to speed up the matching<br />

is to pregenerate the model for the allowed range of rotation and scale as described on page 16.<br />

In the following, we show how to optimize the matching process in two steps. Please note that in order<br />

to optimize the matching it is very important to have a set of representative test images from your<br />

application in which the object appears in all allowed variations regarding its position, orientation,<br />

occlusion, and illumination.<br />

Step 1: Assure that all objects are found<br />

Before tuning the parameters for speed, we recommend to find settings such that the matching succeeds<br />

in all test images, i.e., that all object instances are found. If this is not the case when using the default<br />

values, check whether one of the following situations applies:<br />

? Is the object clipped at the image border?<br />

Unfortunately, this failure cannot be prevented, i.e., you must assure that the object is not clipped<br />

(see section 3.1.3 on page 21).<br />

? Is the search algorithm “too greedy”?<br />

As described in section 3.1.4 on page 23, in some cases a perfectly visible object is not found if<br />

the Greediness is too high. Select the value 0 to force a thorough search.<br />

? Is the object partly occluded?<br />

If the object should be recognized in this state nevertheless, reduce the parameter MinScore.<br />

? Does the matching fail on the highest pyramid level?<br />

As described in section 3.1.3 on page 21, in some cases the minimum score is not reached on<br />

the highest pyramid level even though the score on the lowest level is much higher. Test this by<br />

reducing NumLevels in the call to find_shape_model. Alternatively, reduce the MinScore.<br />

? Does the object have a low contrast?<br />

If the object should be recognized in this state nevertheless, reduce the parameter MinContrast<br />

(operator create_shape_model!).<br />

? Is the polarity of the contrast inverted globally or locally?<br />

If the object should be recognized in this state nevertheless, use the appropriate value for the parameter<br />

Metric when creating the model (see section 2.2.5 on page 18). If only a small part of the<br />

object is affected, it may be better to reduce the MinScore instead.<br />

? Does the object overlap another instance of the object?<br />

If the object should be recognized in this state nevertheless, increase the parameter MaxOverlap<br />

(see section 3.2 on page 23).<br />

? Are multiple matches found on the same object?<br />

If the object is almost symmetric, restrict the allowed range of rotation as described in section 2.2.3<br />

on page 16 or decrease the parameter MaxOverlap (see section 3.2 on page 23).


Step 2: Tune the parameters regarding speed<br />

3.5 How to Optimize the Matching Speed 29<br />

The speed of the matching process depends both on the model and on the search parameters. To make<br />

matters more difficult, the search parameters depend on the chosen model parameters. We recommend<br />

the following procedure:<br />

• Increase the MinScore as far as possible, i.e., as long as the matching succeeds.<br />

• Now, increase the Greediness until the matching fails. Try reducing the MinScore; if this does<br />

not help restore the previous values.<br />

• If possible, use a larger value for NumLevels when creating the model.<br />

• Restrict the allowed range of rotation and scale as far as possible as described in section 2.2.3 on<br />

page 16 and section 2.2.4 on page 17. Alternatively, adjust the corresponding parameters when<br />

calling find_shape_model or find_scaled_shape_model.<br />

• Restrict the search to a region of interest as described in section 3.1.1 on page 20.<br />

The following methods are more “risky”, i.e., the matching may fail if you choose unsuitable parameter<br />

values.<br />

• Increase the MinContrast as long as the matching succeeds.<br />

• If you a searching for a particularly large object, it sometimes helps to select a higher point reduction<br />

with the parameter Optimization (see section 2.2.2 on page 14).<br />

• Increase the AngleStep (and the ScaleStep) as long as the matching succeeds.<br />

Optimal Search


30 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

4 Using the Results of Matching<br />

As results, the operators find_shape_model, find_scaled_shape_model etc. return<br />

• the position of the match in the parameters Row and Column,<br />

• its orientation in the parameter Angle,<br />

• the scaling factor in the parameter Scale, and<br />

• the matching score in the parameter Score.<br />

The matching score, which is a measure of the similarity between the model and the matched object, can<br />

be used “as it is”, since it is an absolute value.<br />

In contrast, the results regarding the position, orientation, and scale are worth a closer look as they are<br />

determined relative to the created model. Before this, we introduce <strong>HALCON</strong>’s powerful operators for<br />

the so-called affine transformations, which, when used together with the shape-based matching, enable<br />

you to easily realize applications like image rectification or the alignment of ROIs with a few lines of<br />

code.<br />

4.1 Introducing Affine Transformations<br />

“Affine transformation” is a technical term in mathematics describing a certain group of transformations.<br />

Figure 17 shows the types that occur in the context of the shape-based matching: An object can be<br />

translated (moved) along the two axes, rotated, and scaled. In figure 17d, all three transformations were<br />

applied in a sequence.<br />

<strong>Note</strong> that for the rotation and the scaling there exists a special point, called fixed point or point of reference.<br />

The transformation is performed around this point. In figure 17b, e.g., the IC is rotated around<br />

its center, in figure 17e around its upper right corner. The point is called fixed point because it remains<br />

unchanged by the transformation.<br />

The transformation can be thought of as a mathematical instruction that defines how to calculate the<br />

coordinates of object points after the transformation. Fortunately, you need not worry about the mathematical<br />

part; <strong>HALCON</strong> provides a set of operators that let you specify and apply transformations in a<br />

simple way.<br />

4.2 Creating and Applying Affine Transformations With <strong>HALCON</strong><br />

<strong>HALCON</strong> allows to transform not only regions, but also images and XLD contours by providing the<br />

operators affine_trans_region, affine_trans_image, and affine_trans_contour_xld. The<br />

transformation in figure 17d corresponds to the line<br />

affine_trans_region (IC, TransformedIC, ScalingRotationTranslation,<br />

’false’)<br />

The parameter ScalingRotationTranslation is a so-called homogeneous transformation matrix that<br />

describes the desired transformation. You can create this matrix by adding simple transformations step<br />

by step. First, an identity matrix is created:


e)<br />

row / x<br />

column / y<br />

a) b)<br />

c) d)<br />

4.2 Creating and Applying Affine Transformations With <strong>HALCON</strong> 31<br />

Figure 17: Typical affine transformations: a) translation along two axes; b) rotation around the IC center;<br />

c) scaling around the IC center; d) combining a, b, and c; e) rotation around the upper right<br />

corner; f) scaling around the right IC center.<br />

hom_mat2d_identity (EmptyTransformation)<br />

Then, the scaling around the center of the IC is added:<br />

hom_mat2d_scale (EmptyTransformation, 0.5, 0.5, RowCenterIC,<br />

ColumnCenterIC, Scaling)<br />

Similarly, the rotation and the translation are added:<br />

hom_mat2d_rotate (Scaling, rad(90), RowCenterIC, ColumnCenterIC,<br />

ScalingRotation)<br />

hom_mat2d_translate (ScalingRotation, 100, 200, ScalingRotationTranslation)<br />

Please note that in these operators the coordinate axes are labeled with x and y instead of Row and<br />

Column! Figure 17a clarifies the relation.<br />

Transformation matrices can also be constructed by a sort of “reverse engineering”. In other words, if the<br />

result of the transformation is known for some points of the object, you can determine the corresponding<br />

f)<br />

Matching Results


32 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

!<br />

transformation matrix. If, e.g., the position of the IC center and its orientation after the transformation is<br />

known, you can get the corresponding matrix via the operator vector_angle_to_rigid.<br />

vector_angle_to_rigid (RowCenterIC, ColumnCenterIC, 0,<br />

TransformedRowCenterIC, TransformedColumnCenterIC,<br />

rad(90), RotationTranslation)<br />

and then use this matrix to compute the transformed region:<br />

affine_trans_region (IC, TransformedIC, RotationTranslation, ’false’)<br />

4.3 Using the Estimated Position and Orientation<br />

Even if the task is just to check whether an object is present in the image, you will typically use the returned<br />

position and orientation: to display the found instance. This basic use is described in section 4.3.1.<br />

More advanced applications are to align ROIs for other inspection tasks, e.g., measuring (section 4.3.4<br />

on page 36), or to transform the search image so that the object is positioned as in the model image<br />

(section 4.3.5 on page 40). Section 4.4 on page 44 shows how to locate grasping points on nuts, which<br />

could then be passed on to a robot.<br />

There are two things to keep in mind about the position and orientation returned in the parameters Row,<br />

Column, and Angle: Most important, contrary to expectation the estimated position is not exactly<br />

the position of the point of reference but only close to it. Instead, it is optimized for creating the<br />

transformation matrix with which the applications described above can be realized.<br />

Secondly, in the model image the object is taken as not rotated, i.e., its angle is 0, even if it seems to be<br />

rotated, e.g., as in figure 18b.<br />

4.3.1 Displaying the Matches<br />

Especially during the development of a matching application it is useful to display the matching results<br />

overlaid on the search image. This can be realized in a few steps (see, e.g., the HDevelop program<br />

hdevelop\first_example_shape_matching.dev):<br />

Step 1: Access the XLD contour containing the model<br />

create_shape_model (ImageROI, NumLevels, 0, rad(360), ’auto’, ’none’,<br />

’use_polarity’, 30, 10, ModelID)<br />

get_shape_model_contours (ShapeModel, ModelID, 1)<br />

Below, we want to display the model at the extracted position and orientation. As shown in section 1<br />

on page 4, the corresponding region can be accessed via the operator inspect_shape_model. This is<br />

useful to display the model in the model image. However, for the search images we recommend to use<br />

the XLD version of the model, because XLD contours can be transformed more precisely and quickly.<br />

You can access the XLD model by calling the operator get_shape_model_contours after creating the<br />

model. <strong>Note</strong> that the XLD model is located in the origin of the image, not on the position of the model<br />

in the model image.


a)<br />

b)<br />

model image<br />

Row<br />

Row<br />

Column Column<br />

Angle = 0<br />

Row<br />

Column Column<br />

Angle = 0<br />

search image<br />

model image search image<br />

Row<br />

4.3.1 Displaying the Matches 33<br />

Figure 18: The position and orientation of a match: a) The center of the ROI acts as the default point of<br />

reference; b) In the model image, the orientation is always 0.<br />

Step 2: Determine the affine transformation<br />

find_shape_model (SearchImage, ModelID, 0, rad(360), 0.7, 1, 0.5,<br />

’least_squares’, 0, 0.9, RowCheck, ColumnCheck,<br />

AngleCheck, Score)<br />

if (|Score| = 1)<br />

vector_angle_to_rigid (0, 0, 0, RowCheck, ColumnCheck, AngleCheck,<br />

MovementOfObject)<br />

After the call of the operator find_shape_model, the results are checked; if the matching failed, empty<br />

tuples are returned in the parameters Score etc. For a successful match, the corresponding affine transformation<br />

can be constructed with the operator vector_angle_to_rigid from the position and orientation<br />

of the match (see section 4.2 on page 30). In the first 2 parameters, you pass the “relative” position<br />

of the reference point, i.e., its distance to the default reference point (the center of gravity of the ROI, see<br />

section 2.1.4 on page 12). By default, this relative position is (0,0); section 4.3.4 on page 36 shows the<br />

values in the case of a modified reference point.<br />

Step 3: Transform the XLD<br />

affine_trans_contour_xld (ShapeModel, ModelAtNewPosition,<br />

MovementOfObject)<br />

dev_display (ModelAtNewPosition)<br />

Now, you can apply the transformation to the XLD version of the model using the operator<br />

affine_trans_contour_xld and display it; figure 2 on page 5 shows the result.<br />

Angle<br />

Angle<br />

Matching Results


34 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

!<br />

Figure 19: Displaying multiple matches; the used model is depicted in figure 12a on page 22 .<br />

4.3.2 Dealing with Multiple Matches<br />

If multiple instances of the object are searched and found, the parameters Row, Column, Angle, and<br />

Score contain tuples. The HDevelop program hdevelop\multiple_objects.dev shows how to access<br />

these results in a loop:<br />

Step 1: Determine the affine transformation<br />

find_shape_model (SearchImage, ModelID, 0, rad(360), 0.6, 0, 0.55,<br />

’least_squares’, 0, 0.8, RowCheck, ColumnCheck,<br />

AngleCheck, Score)<br />

for j := 0 to |Score| - 1 by 1<br />

vector_angle_to_rigid (0, 0, 0, RowCheck[j], ColumnCheck[j],<br />

AngleCheck[j], MovementOfObject)<br />

affine_trans_contour_xld (ShapeModel, ModelAtNewPosition,<br />

The transformation corresponding to the movement of the match is determined as in the previous section;<br />

the only difference is that the position of the match is extracted from the tuple via the loop variable.<br />

Step 2: Use the transformation<br />

affine_trans_pixel (MovementOfObject, -120, 0, RowArrowHead,<br />

ColumnArrowHead)<br />

disp_arrow (WindowHandle, RowCheck[j], ColumnCheck[j],<br />

RowArrowHead, ColumnArrowHead, 2)<br />

In this example, the transformation is also used to display an arrow that visualizes the orientation (see<br />

figure 19). For this, the position of the arrow head is transformed using affine_trans_pixel with the<br />

same transformation matrix as the XLD model.<br />

<strong>Note</strong> that you must use the operator affine_trans_pixel and not affine_trans_point_2d,<br />

because the latter uses a different image coordinate system than affine_trans_pixel,<br />

affine_trans_contour_xld, affine_trans_region, and affine_trans_image.


4.3.3 Dealing with Multiple Models<br />

4.3.3 Dealing with Multiple Models 35<br />

When searching for multiple models simultaneously as described in section 3.3 on page 24, it is useful<br />

to store the information about the models, i.e., the XLD models, in tuples. The following example code<br />

stems from the already partly described HDevelop program hdevelop\multiple_models.dev, which<br />

uses the operator find_scaled_shape_models to search simultaneously for the rings and nuts depicted<br />

in figure 15 on page 25.<br />

Step 1: Access the XLD models<br />

create_scaled_shape_model (ImageROIRing, ’auto’, -rad(22.5), rad(45),<br />

’auto’, 0.8, 1.2, ’auto’, ’none’,<br />

’use_polarity’, 60, 10, ModelIDRing)<br />

get_shape_model_contours (ShapeModelRing, ModelIDRing, 1)<br />

create_scaled_shape_model (ImageROINut, ’auto’, -rad(30), rad(60), ’auto’,<br />

0.6, 1.4, ’auto’, ’none’, ’use_polarity’, 60,<br />

inspect_shape_model (ImageROINut, PyramidImage, ModelRegionNut, 1, 30)<br />

As in the previous sections, the XLD contours corresponding to the two models are accessed with the<br />

operator get_shape_model_contours.<br />

Step 2: Save the information about the models in tuples<br />

NumContoursRing := |ShapeModelRing|<br />

get_shape_model_contours (ShapeModelNut, ModelIDNut, 1)<br />

ModelIDs := [ModelIDRing, ModelIDNut]<br />

ShapeModels := [ShapeModelRing,ShapeModelNut]<br />

StartContoursInTuple := [1, NumContoursRing+1]<br />

To facilitate the access to the shape models later, the XLD contours are saved in tuples in analogy to the<br />

model IDs (see section 3.3 on page 24). However, when concatenating XLD contours with the operator<br />

concat_obj, one must keep in mind that XLD objects are already tuples as they may consist of multiple<br />

contours! To access the contours belonging to a certain model, you therefore need the number of contours<br />

of a model and the starting index in the concatenated tuple. The former is determined using the operator<br />

count_obj; the contours of the ring start with the index 1, the contours of the nut with the index 1 plus<br />

the number of contours of the ring.<br />

Matching Results


36 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

Step 3: Access the found instances<br />

find_scaled_shape_models (SearchImageReduced, ModelIDs, [-rad(22.5),<br />

-rad(30)], [rad(45), rad(60)], [0.8, 0.6], [1.2,<br />

1.4], 0.7, 0, 0, ’least_squares’, 0, 0.8,<br />

RowCheck, ColumnCheck, AngleCheck, ScaleCheck,<br />

Score, ModelIndex)<br />

for i := 0 to |Score| - 1 by 1<br />

Model := ModelIndex[i]<br />

vector_angle_to_rigid (0, 0, 0, RowCheck[i], ColumnCheck[i],<br />

AngleCheck[i], MovementOfObject)<br />

hom_mat2d_scale (MovementOfObject, ScaleCheck[i], ScaleCheck[i],<br />

RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)<br />

copy_obj (ShapeModels, ShapeModel, StartContoursInTuple[Model],<br />

NumContoursInTuple[Model])<br />

affine_trans_contour_xld (ShapeModel, ModelAtNewPosition,<br />

MoveAndScalingOfObject)<br />

dev_display (ModelAtNewPosition)<br />

endfor<br />

As described in section 4.3.2 on page 34, in case of multiple matches the output parameters Row etc.<br />

contain tuples of values, which are typically accessed in a loop, using the loop variable as the index into<br />

the tuples. When searching for multiple models, a second index is involved: The output parameter Model<br />

indicates to which model a match belongs by storing the index of the corresponding model ID in the<br />

tuple of IDs specified in the parameter ModelIDs. This may sound confusing, but can be realized in an<br />

elegant way in the code: For each found instance, the model ID index is used to select the corresponding<br />

information from the tuples created above.<br />

As already noted, the XLD representing the model can consist of multiple contours; therefore, you cannot<br />

access them directly using the operator select_obj. Instead, the contours belonging to the model are<br />

selected via the operator copy_obj, specifying the start index of the model in the concatenated tuple<br />

and the number of contours as parameters. <strong>Note</strong> that copy_obj does not copy the contours, but only the<br />

corresponding <strong>HALCON</strong> objects, which can be thought of as references to the contours.<br />

4.3.4 Aligning Other ROIs<br />

The results of the matching can be used to align ROIs for other image processing steps. i.e., to position<br />

them relative to the image part acting as the model. This method is very useful, e.g., if the object to be<br />

inspected is allowed to move or if multiple instances of the object are to be inspected at once as in the<br />

example application described below.<br />

In the example application hdevelop\align_measurements.dev, the task is to inspect razor blades<br />

by measuring the width and the distance of their “teeth”. Figure 20a shows the model ROI, figure 20b<br />

the corresponding model region.


a) b)<br />

d)<br />

c)<br />

4.3.4 Aligning Other ROIs 37<br />

Figure 20: Aligning ROIs for inspecting parts of a razor: a) ROIs for the model; b) the model; c) measuring<br />

ROIs; d) inspection results with zoomed faults.<br />

The inspection task is realized with the following steps:<br />

Step 1: Position the measurement ROIs for the model blade<br />

Rect1Row := 244<br />

Rect1Col := 73<br />

DistColRect1Rect2 := 17<br />

Rect2Row := Rect1Row<br />

Rect2Col := Rect1Col + DistColRect1Rect2<br />

RectPhi := rad(90)<br />

RectLength1 := 122<br />

RectLength2 := 2<br />

Matching Results


38 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

!<br />

First, two rectangular measurement ROIs are placed over the teeth of the razor blade acting as the model<br />

as shown in figure 20c. To be able to transform them later along with the XLD model, they are moved<br />

to lie on the XLD model, whose reference point is the origin of the image. <strong>Note</strong> that before moving the<br />

regions the clipping must be switched off.<br />

area_center (ModelROI, Area, CenterROIRow, CenterROIColumn)<br />

get_system (’clip_region’, OriginalClipRegion)<br />

set_system (’clip_region’, ’false’)<br />

move_region (MeasureROI1, MeasureROI1Ref, - CenterROIRow,<br />

- CenterROIColumn)<br />

move_region (MeasureROI2, MeasureROI2Ref, - CenterROIRow,<br />

- CenterROIColumn)<br />

set_system (’clip_region’, OriginalClipRegion)<br />

DistRect1CenterRow := Rect1Row - CenterROIRow<br />

DistRect1CenterCol := Rect1Col - CenterROIColumn<br />

DistRect2CenterRow := Rect2Row - CenterROIRow<br />

DistRect2CenterCol := Rect2Col - CenterROIColumn<br />

Step 2: Find all razor blades<br />

find_shape_model (SearchImage, ModelID, 0, 0, 0.8, 0, 0.5, ’least_squares’,<br />

0, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)<br />

Then, all instances of the model object are searched for in the image.<br />

Step 3: Determine the affine transformation<br />

for i := 0 to |Score|-1 by 1<br />

vector_angle_to_rigid (0, 0, 0, RowCheck[i], ColumnCheck[i],<br />

AngleCheck[i], MovementOfObject)<br />

affine_trans_contour_xld (ShapeModel, ModelAtNewPosition,<br />

MovementOfObject)<br />

For each razor blade, the transformation representing its position and orientation is calculated.<br />

Step 4: Create measurement objects at the corresponding positions<br />

affine_trans_pixel (MovementOfObject, DistRect1CenterRow,<br />

DistRect1CenterCol, Rect1RowCheck,<br />

Rect1ColCheck)<br />

affine_trans_pixel (MovementOfObject, DistRect2CenterRow,<br />

DistRect2CenterCol, Rect2RowCheck,<br />

Rect2ColCheck)<br />

Now, the new positions of the measure ROIs are calculated using the operator affine_trans_pixel<br />

with the moved ROI coordinates. As remarked in section 4.3.2 on page 34, you must use<br />

affine_trans_pixel and not affine_trans_point_2d. Then, the new measure objects are created.


RectPhiCheck := RectPhi + AngleCheck[i]<br />

gen_measure_rectangle2 (Rect1RowCheck, Rect1ColCheck,<br />

RectPhiCheck, RectLength1, RectLength2,<br />

Width, Height, ’bilinear’,<br />

MeasureHandle1)<br />

gen_measure_rectangle2 (Rect2RowCheck, Rect2ColCheck,<br />

RectPhiCheck, RectLength1, RectLength2,<br />

Width, Height, ’bilinear’,<br />

MeasureHandle2)<br />

4.3.4 Aligning Other ROIs 39<br />

In the example application, the individual razor blades are only translated but not rotated relative to the<br />

model position. Instead of applying the full affine transformation to the measure ROIs and then creating<br />

new measure objects, one can therefore use the operator translate_measure to translate the measure<br />

objects themselves. The example program contains the corresponding code; you can switch between the<br />

two methods by modifying a variable at the top of the program.<br />

Step 5: Measure the width and the distance of the “teeth”<br />

measure_pairs (SearchImage, MeasureHandle1, 2, 25, ’negative’,<br />

’all’, RowEdge11, ColEdge11, Amp11, RowEdge21,<br />

ColEdge21, Amp21, Width1, Distance1)<br />

measure_pairs (SearchImage, MeasureHandle2, 2, 25, ’negative’,<br />

’all’, RowEdge12, ColEdge12, Amp12, RowEdge22,<br />

ColEdge22, Amp22, Width2, Distance2)<br />

Now, the actual measurements are performed using the operator measure_pairs.<br />

Step 6: Inspect the measurements<br />

NumberTeeth1 := |Width1|<br />

if (NumberTeeth1 < 37)<br />

for j := 0 to NumberTeeth1 - 2 by 1<br />

if (Distance1[j] > 4.0)<br />

RowFault := round(0.5*(RowEdge11[j+1] + RowEdge21[j]))<br />

ColFault := round(0.5*(ColEdge11[j+1] + ColEdge21[j]))<br />

disp_rectangle2 (WindowHandle, RowFault, ColFault, 0,<br />

4, 4)<br />

Finally, the measurements are inspected. If a “tooth” is too short or missing completely, no edges are<br />

extracted at this point resulting in an incorrect number of extracted edge pairs. In this case, the faulty<br />

position can be determined by checking the distance of the teeth. Figure 20d shows the inspection results<br />

for the example.<br />

Please note that the example program is not able to display the fault if it occurs at the first or the last<br />

tooth.<br />

Matching Results


40 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

4.3.5 Rectifying the Search Results<br />

In the previous section, the matching results were used to determine the so-called forward transformation,<br />

i.e., how objects are transformed from the model into the search image. Using this transformation,<br />

ROIs specified in the model image can be positioned correctly in the search image.<br />

You can also determine the inverse transformation which transforms objects from the search image back<br />

into the model image. With this transformation, you can rectify the search image (or parts of it), i.e.,<br />

transform it such that the matched object is positioned as it was in the model image. This method is<br />

useful if the following image processing step is not invariant against rotation, e.g., OCR or the variation<br />

model. <strong>Note</strong> that image rectification can also be useful before applying shape-based matching, e.g., if<br />

the camera observes the scene under an oblique angle; see section 5.1 on page 46 for more information.<br />

The inverse transformation can be determined and applied in a few steps, which are described below; in<br />

the corresponding example application of the HDevelop program hdevelop\rectify_results.dev<br />

the task is to extract the serial number on CD covers (see figure 21).<br />

Step 1: Calculate the inverse transformation<br />

vector_angle_to_rigid (CenterROIRow, CenterROIColumn, 0, RowCheck,<br />

ColumnCheck, AngleCheck, MovementOfObject)<br />

hom_mat2d_invert (MovementOfObject, InverseMovementOfObject)<br />

You can invert a transformation easily using the operator hom_mat2d_invert. <strong>Note</strong> that in contrast to<br />

the previous sections, the transformation is calculated based on the absolute coordinates of the reference<br />

point, because here we want to transform the results such that they appear as in the model image.<br />

Step 2: Rectify the search image<br />

affine_trans_image (SearchImage, RectifiedSearchImage,<br />

InverseMovementOfObject, ’constant’, ’false’)<br />

Now, you can apply the inverse transformation to the search image using the operator<br />

affine_trans_image. Figure 21d shows the resulting rectified image of a different CD; undefined<br />

pixels are marked in grey.<br />

Step 3: Extract the numbers<br />

reduce_domain (RectifiedSearchImage, NumberROI,<br />

RectifiedNumberROIImage)<br />

threshold (RectifiedNumberROIImage, Numbers, 0, 128)<br />

connection (Numbers, IndividualNumbers)<br />

Now, the serial number is positioned correctly within the original ROI and can be extracted without<br />

problems. Figure 21e shows the result, which could then, e.g., be used as the input for OCR.


a)<br />

c) d)<br />

4.3.5 Rectifying the Search Results 41<br />

Figure 21: Rectifying the search results: a) ROIs for the model and for the number extraction; b) the model;<br />

c) number ROI at matched position; d) rectified search image (only relevant part shown); e)<br />

extracted numbers.<br />

e)<br />

b)<br />

Matching Results


42 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

a)<br />

b)<br />

Row1<br />

translate(−Row1,−Column1)<br />

Column1<br />

c) d)<br />

Figure 22: Rectifying only part of the search image: a) smallest image part containing the ROI; b) cropped<br />

search image; c) result of the rectification; d) rectified image reduced to the original number<br />

ROI.<br />

Unfortunately, the operator affine_trans_image transforms the full image even if you restrict its<br />

domain with the operator reduce_domain. In a time-critical application it may therefore be necessary<br />

to crop the search image before transforming it. The corresponding steps are visualized in figure 22.<br />

Step 1: Crop the search image<br />

affine_trans_region (NumberROI, NumberROIAtNewPosition,<br />

MovementOfObject, ’false’)<br />

smallest_rectangle1 (NumberROIAtNewPosition, Row1, Column1, Row2,<br />

Column2)<br />

crop_rectangle1 (SearchImage, CroppedNumberROIImage, Row1, Column1,<br />

Row2, Column2)<br />

First, the smallest axis-parallel rectangle surrounding the transformed number ROI is computed using<br />

the operator smallest_rectangle1, and the search image is cropped to this part. Figure 22b shows<br />

the resulting image overlaid on a grey rectangle to facilitate the comparison with the subsequent images.


Step 2: Create an extended affine transformation<br />

hom_mat2d_translate (MovementOfObject, - Row1, - Column1,<br />

MoveAndCrop)<br />

hom_mat2d_invert (MoveAndCrop, InverseMoveAndCrop)<br />

4.3.5 Rectifying the Search Results 43<br />

In fact, the cropping can be interpreted as an additional affine transformation: a translation by the<br />

negated coordinates of the upper left corner of the cropping rectangle (see figure 22a). We therefore<br />

“add” this transformation to the transformation describing the movement of the object using<br />

the operator hom_mat2d_translate, and then invert this extended transformation with the operator<br />

hom_mat2d_invert.<br />

Step 3: Transform the cropped image<br />

affine_trans_image (CroppedNumberROIImage, RectifiedROIImage,<br />

InverseMoveAndCrop, ’constant’, ’true’)<br />

reduce_domain (RectifiedROIImage, NumberROI,<br />

RectifiedNumberROIImage)<br />

Using the inverted extended transformation, the cropped image can easily be rectified with the operator<br />

affine_trans_image (figure 22c) and then be reduced to the original number ROI (figure 22d) in order<br />

to extract the numbers.<br />

Matching Results


44 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

Row<br />

Column<br />

model image search image<br />

Scale = 1<br />

Row<br />

Column<br />

Scale = 0.5<br />

Figure 23: The center of the ROI acts as the point of reference for the scaling.<br />

a) b) c)<br />

d)<br />

Figure 24: Determining grasping points on nuts of varying sizes: a) ring-shaped ROI; b) model; c) grasping<br />

points defined on the model nut; d) results of the matching.<br />

4.4 Using the Estimated Scale<br />

Similarly to the rotation (compare section 4.3 on page 32), the scaling is performed around the center<br />

of the ROI – if you didn’t use set_shape_model_origin, that is. This is depicted in figure 23a at the<br />

example of an ROI whose center does not coincide with the center of the IC.<br />

The estimated scale, which is returned in the parameter Scale, can be used similarly to the position<br />

and orientation. However, there is no convenience operator like vector_angle_to_rigid<br />

that creates an affine transformation including the scale; therefore, the scaling must be added separately.<br />

How to achieve this is explained below; in the corresponding example HDevelop program hdevelop\multiple_scales.dev,<br />

the task is to find nuts of varying sizes and to determine suitable points<br />

for grasping them (see figure 24).


Step 1: Specify grasping points<br />

RowUpperPoint := 284<br />

ColUpperPoint := 278<br />

RowLowerPoint := 362<br />

ColLowerPoint := 278<br />

4.4 Using the Estimated Scale 45<br />

In the example program, the grasping points are specified directly in the model image; they are marked<br />

with arrows in figure 24c. To be able to transform them together with the XLD model, their coordinates<br />

must be moved so that they lie on the XLD model:<br />

area_center (ModelROI, Area, CenterROIRow, CenterROIColumn)<br />

RowUpperPointRef := RowUpperPoint - CenterROIRow<br />

ColUpperPointRef := ColUpperPoint - CenterROIColumn<br />

RowLowerPointRef := RowLowerPoint - CenterROIRow<br />

ColLowerPointRef := ColLowerPoint - CenterROIColumn<br />

Step 2: Determine the complete transformation<br />

find_scaled_shape_model (SearchImage, ModelID, -rad(30), rad(60), 0.6, 1.4,<br />

0.9, 0, 0, ’least_squares’, 0, 0.8, RowCheck,<br />

ColumnCheck, AngleCheck, ScaleCheck, Score)<br />

for i := 0 to |Score| - 1 by 1<br />

vector_angle_to_rigid (0, 0, 0, RowCheck[i], ColumnCheck[i],<br />

AngleCheck[i], MovementOfObject)<br />

hom_mat2d_scale (MovementOfObject, ScaleCheck[i], ScaleCheck[i],<br />

RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)<br />

affine_trans_contour_xld (ShapeModel, ModelAtNewPosition,<br />

MoveAndScalingOfObject)<br />

After the matching, first the translational and rotational part of the transformation is determined with the<br />

operator vector_angle_to_rigid as in the previous sections. Then, the scaling is added using the<br />

operator hom_mat2d_scale. <strong>Note</strong> that the position of the match is used as the point of reference; this<br />

becomes necessary because the scaling is performed “after” the translation and rotation. The resulting,<br />

complete transformation can be used as before to display the model at the position of the matches.<br />

Step 3: Calculate the transformed grasping points<br />

affine_trans_pixel (MoveAndScalingOfObject, RowUpperPointRef,<br />

ColUpperPointRef, RowUpperPointCheck,<br />

ColUpperPointCheck)<br />

affine_trans_pixel (MoveAndScalingOfObject, RowLowerPointRef,<br />

ColLowerPointRef, RowLowerPointCheck,<br />

ColLowerPointCheck)<br />

Of course, the affine transformation can also be applied to other points in the model image with the<br />

operator affine_trans_pixel. In the example, this is used to calculate the position of the grasping<br />

points for all nuts; they are marked with arrows in figure 24d.<br />

As noted in section 4.3.2 on page 34, you must use affine_trans_pixel and not !<br />

affine_trans_point_2d.<br />

Matching Results


46 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching<br />

5 Miscellaneous<br />

5.1 Adapting to a Changed Camera Orientation<br />

As shown in the sections above, <strong>HALCON</strong>’s shape-based matching allows to localize objects even if their<br />

position and orientation in the image or their scale changes. However, the shape-based matching fails<br />

if the camera observes the scene under an oblique angle, i.e., if it is not pointed perpendicularly at the<br />

plane in which the objects move, because an object then appears distorted due to perspective projection;<br />

even worse, the distortion changes with the position and orientation of the object.<br />

In such a case we recommend to rectify images before applying the matching. This is a three-step<br />

process: First, you must calibrate the camera, i.e., determine its position and orientation and other<br />

parameters, using the operator camera_calibration. Secondly, the calibration data is used to create a<br />

mapping function via the operator gen_image_to_world_plane_map, which is then applied to images<br />

with the operator map_image. For detailed information please refer to the <strong>Application</strong> <strong>Note</strong> on 3D<br />

Machine Vision, section 3.3 on page 49.<br />

5.2 Reusing Models<br />

If you want to reuse created models in other <strong>HALCON</strong> applications, all you need to do is to store the<br />

relevant information in files and then read it again. The following example code stems from the HDevelop<br />

program hdevelop\reuse_model.dev. First, a model is created:<br />

create_scaled_shape_model (ImageROI, ’auto’, -rad(30), rad(60), ’auto’,<br />

0.6, 1.4, ’auto’, ’none’, ’use_polarity’, 60,<br />

10, ModelID)<br />

Then, the model is stored in a file using the operator write_shape_model. With the model, <strong>HALCON</strong><br />

automatically saves the XLD contour, the reference point, and the parameters that were used in the call<br />

to create_shape_model.<br />

write_shape_model (ModelID, ModelFile)<br />

In the example program, all shape models are cleared to represent the start of another application.<br />

The model, the XLD contour, and the reference point are now read from the files using the<br />

operator read_shape_model. Then, the XLD contours and the reference are accessed using<br />

get_shape_model_contours and get_shape_model_origin, respectively, Furthermore, the parameters<br />

used to create the model are accessed with the operator get_shape_model_params:<br />

read_shape_model (ModelFile, ReusedModelID)<br />

get_shape_model_contours (ReusedShapeModel, ReusedModelID, 1)<br />

get_shape_model_origin (ReusedModelID, ReusedRefPointRow,<br />

ReusedRefPointCol)<br />

get_shape_model_params (ReusedModelID, NumLevels, AngleStart, AngleExtent,<br />

AngleStep, ScaleMin, ScaleMax, ScaleStep, Metric,<br />

MinContrast)<br />

Now, the model can be used as if it was created in the application itself:


find_scaled_shape_model (SearchImage, ReusedModelID, AngleStart,<br />

AngleExtent, ScaleMin, ScaleMax, 0.9, 0, 0,<br />

’least_squares’, 0, 0.8, RowCheck, ColumnCheck,<br />

AngleCheck, ScaleCheck, Score)<br />

for i := 0 to |Score| - 1 by 1<br />

vector_angle_to_rigid (ReusedRefPointRow, ReusedRefPointCol, 0,<br />

RowCheck[i], ColumnCheck[i], AngleCheck[i],<br />

MovementOfObject)<br />

hom_mat2d_scale (MovementOfObject, ScaleCheck[i], ScaleCheck[i],<br />

RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)<br />

affine_trans_contour_xld (ReusedShapeModel, ModelAtNewPosition,<br />

MoveAndScalingOfObject)<br />

dev_display (ModelAtNewPosition)<br />

endfor<br />

5.2 Reusing Models 47<br />

Miscellaneous


48 <strong>Application</strong> <strong>Note</strong> on Shape-Based Matching


Provided Functionality<br />

<strong>HALCON</strong> <strong>Application</strong> <strong>Note</strong><br />

Finding and Decoding 2D Data<br />

Codes<br />

⊲ Finding and decoding 2D data codes of type Data Matrix ECC 200, QR Code, or PDF417 with one<br />

operator call<br />

Typical <strong>Application</strong>s<br />

⊲ Identification of individuals (Drivers’ licenses, ID cards, etc.)<br />

⊲ Identification and labeling of objects (Medicine, Production, etc.)<br />

⊲ Electronic Data Interchange (EDI)<br />

⊲ Transport and logistics<br />

Involved Operators<br />

create_data_code_2d_model<br />

query_data_code_2d_params<br />

get_data_code_2d_param<br />

set_data_code_2d_param<br />

find_data_code_2d<br />

get_data_code_2d_objects , get_data_code_2d_results<br />

read_data_code_2d_model , write_data_code_2d_model<br />

clear_all_data_code_2d_models , clear_data_code_2d_model<br />

Copyright c○ 2006-2008 by <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>, München, Germany <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>


Overview<br />

2D data codes are used in various application areas and get more and more important. This <strong>Application</strong><br />

<strong>Note</strong> guides you to the handling of 2D data codes using the operators of <strong>HALCON</strong>.<br />

In section 1 on page 4 we introduce you to 2D data codes in general, including a description of the<br />

different symbol types supported by <strong>HALCON</strong>, namely PDF417, Data Matrix ECC 200, and QR Code.<br />

A first example in section 2 on page 5 shows the main steps needed to read a standard 2D data code. To<br />

read non-standard 2D data codes as well or to enhance the run time, section 3 on page 7 describes the<br />

different ways to change the 2D data code model, which is used to guide the search process of the 2D<br />

data code reader.<br />

Although the 2D data code reader of <strong>HALCON</strong> is rather powerful, there are some symbol representations<br />

that cannot be decoded for various reasons. Some problems can be solved by using image preprocessing<br />

methods. Section 4 on page 20 shows a selection of these problems and describes the corresponding<br />

preprocessing steps. A deeper insight into the handling of problems is given in section 5 on page 24.<br />

There, an approach for debugging the search process is provided. This can be used on the one hand to<br />

locate specific defects of symbols that are not decoded, and on the other hand to get information about<br />

successfully decoded symbols, so that the run time can be enhanced by a better model adaptation. Some<br />

problems strictly have to be avoided already during the image acquisition. Besides their introduction, the<br />

requirements and limitations concerning the appearance of the symbols are summarized for the individual<br />

symbol types.<br />

Unless specified otherwise, the HDevelop example programs that are presented in this <strong>Application</strong><br />

<strong>Note</strong> can be found in the subdirectory 2d_data_codes of the directory <strong>HALCON</strong>ROOT<br />

\examples\application_guide.<br />

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in<br />

any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written<br />

permission of the publisher.<br />

Edition 1 April 2006 (<strong>HALCON</strong> 7.1.1)<br />

Edition 1a December 2006 (<strong>HALCON</strong> 7.1.2)<br />

Microsoft, Windows, Windows NT, Windows 2000, and Windows XP are either trademarks or registered trademarks<br />

of Microsoft Corporation.<br />

All other nationally and internationally recognized trademarks and tradenames are hereby recognized.<br />

More information about <strong>HALCON</strong> can be found at:<br />

http://www.halcon.com/


Contents<br />

1 Introduction to 2D Data Codes 4<br />

2 A First Example 5<br />

3 Model Adaptation 7<br />

3.1 Global Parameter Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

3.2 Training . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

3.3 Specific Parameter Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

3.4 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

4 Preprocessing Difficult Images 20<br />

4.1 Slanted Symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

4.2 Small Module Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

4.3 Large Module Gaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

4.4 Noise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

5 Problem Handling 24<br />

5.1 Data Access for Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

5.2 Selected Problems and Tips to Avoid Them . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

5.3 Requirements and Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

3


4 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

1 Introduction to 2D Data Codes<br />

<strong>HALCON</strong> provides means to read 2D data codes of type Portable Data Format 417 (PDF417), Data<br />

Matrix ECC 200, and QR Code. 2D data codes, which are also called 2D bar codes or 2D symbologies,<br />

are used in various areas. Similar to <strong>1D</strong> bar codes, they encode characters and numbers in graphical<br />

symbols that are constructed by dark and light bars or dots that are called modules. <strong>1D</strong> bar codes use<br />

black bars and the spaces in between as modules. As the individual bars or spaces have a constant width<br />

along their height, you can read a <strong>1D</strong> bar code in a single scanning line along the symbol’s width. In<br />

contrast to <strong>1D</strong> bar codes, for the symbols of 2D data codes changes occur along both directions. Thus,<br />

the same information can be encoded in smaller symbols. The actual size of a symbol, i.e., the number<br />

of modules in both directions, mainly depends on the length of the encoded message and the level of the<br />

applied error correction. The latter is needed in order to completely decode a symbol even when it has<br />

small defects, e.g., if some of the modules are not visible. There are different types of 2D data codes.<br />

Two common types are the so-called stacked codes and matrix codes.<br />

Of the stacked codes, <strong>HALCON</strong> supports the PDF417 (see figure 1). Its symbol is built up by several <strong>1D</strong><br />

bar codes, which are arranged in rows and columns. Each <strong>1D</strong> bar code encodes an individual ’codeword’.<br />

According to the name of the symbol type, each codeword consists of four dark as well as four light bars<br />

(spaces) and is built up by 17 modules. It always starts with a dark and ends with a light bar. The number<br />

of rows and columns of a PDF417 symbol is variable in a range of 3 to 90 rows and 1 to 30 columns.<br />

Start and stop patterns frame the symbol on the left and right border. The first and the last columns of<br />

codewords are called left and right row indicators. These codewords provide important information for<br />

the decoding, like the number of rows and columns, the error correction level etc. Around the symbol’s<br />

border, a homogeneous frame is placed, which is called quiet zone. For small symbols, a variant of<br />

PDF417 exists, where no right row indicator exists and the stop pattern is reduced to a one module wide<br />

bar. It is called compact or truncated PDF417. <strong>HALCON</strong> operators can read both conventional and<br />

truncated PDF417.<br />

Start pattern<br />

Data encoded in<br />

2 columns and 8 rows Stop pattern<br />

Left row indicator Right row indicator<br />

Figure 1: Stacked code of type PDF417.<br />

Composition of a PDF417 codeword:<br />

4 dark and 4 light bars,<br />

built up by 17 modules<br />

Matrix codes use graphical patterns. They consist of three components: a so-called finder element or<br />

finder pattern, which is needed to find the symbol and its orientation in an image, the data patterns,<br />

which consist of binary modules grouped relative to the finder pattern, and a quiet zone, similar to the<br />

one needed for PDF417 symbols. Matrix codes supported by <strong>HALCON</strong> are Data Matrix ECC 200 and<br />

QR Code (see figure 2). For both matrix code types, the foreground and background modules typically


2 A First Example 5<br />

are square or rectangular, but also circular foreground modules occur. The modules are ordered in rows<br />

and columns. The number of rows and columns define the size of a symbol, which for a QR Code is<br />

directly linked to its version number (the higher the version number, the bigger the symbol). The finder<br />

element of a Data Matrix ECC 200 consists of an L-shape, and alternating dark and light modules on the<br />

opposite borders. The finder element of a QR Code consists of three squares, which are called ’position<br />

detection patterns’.<br />

Figure 2: Types of matrix codes (finder patterns are marked in gray): (left) Data Matrix ECC 200 and<br />

(right) QR Code.<br />

Whereas stacked codes can also be read row by row by a <strong>1D</strong> bar code reader, matrix codes can only<br />

be decoded by inspecting images, i.e., a camera is needed. The <strong>HALCON</strong> operators for reading 2D<br />

data codes assume images as the source for matrix codes as well as for stacked codes. A basic goal<br />

of <strong>HALCON</strong> is that all 2D data code operators are applied as easily as possible. Every 2D data code<br />

operator can be applied to all supported symbol types; only the assigned parameters vary. Additionally,<br />

finding, reading, and decoding of a symbol can be done with a single operator call. The following<br />

chapters show when and how to apply the different 2D data code operators and give suggestions how to<br />

handle common problems, e.g., when facing irregular symbols or images of bad quality.<br />

2 A First Example<br />

This section shows basic steps for the 2D data code reading. To follow the example actively, start the<br />

HDevelop program hdevelop\2d_data_codes_first_example.dev, which reads symbols of type<br />

’Data Matrix ECC 200’ in different images; the steps described below start after the initialization of<br />

the application (press Run once to reach this point).<br />

Step 1: Specify the 2D data code model<br />

create_data_code_2d_model (’Data Matrix ECC 200’, [], [], DataCodeHandle)<br />

First, the operator create_data_code_2d_model specifies the SymbolType that is to be read. Supported<br />

types are ’PDF417’, ’Data Matrix ECC 200’, and ’QR Code’. Here, ’Data Matrix ECC<br />

200’ is chosen. As a result, the operator returns a handle to access the created 2D data code model.<br />

First Example


6 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Step 2: Find, read, and decode the symbol<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, [], [],<br />

ResultHandles, DecodedDataStrings)<br />

Now, the images are read and for each image the operator find_data_code_2d searches for symbols<br />

of the specified type and, if found, reads and decodes them. The input to the operator is the image<br />

and the data code handle. If you work with images that contain more than one symbol per image you<br />

additionally must add the general parameter ’stop_after_result_num’ with the number of expected<br />

symbols. In this example, the number of symbols per image is 1, which is the default value. Because no<br />

additional parameters are set in this example, two empty tuples [] are passed in the operator call. The<br />

operator find_data_code_2d returns the XLD contour representing the border of the found symbol,<br />

a result handle for further investigations concerning the search process, as well as a string containing<br />

the encoded message(s). In the program, the XLD contour and the string are visualized mainly by the<br />

operators set_tposition, write_string, and dev_display, respectively (see figure 3).<br />

dev_display (Image)<br />

dev_set_color (’white’)<br />

gen_rectangle1 (Rectangle, 10, 10, 40, Width-70)<br />

dev_set_color (’black’)<br />

set_tposition (WindowHandle, 17, 15)<br />

write_string (WindowHandle, DecodedDataStrings)<br />

dev_set_color (’yellow’)<br />

dev_display (SymbolXLDs)<br />

Figure 3: Visualization of the result: surrounding XLD contour of the symbol and decoded string.<br />

If the string exceeds 1024 characters, only 1020 characters followed by ’...’ are displayed. In this case,<br />

the whole encrypted data can be accessed as ASCII code, i.e., as a tuple of numbers representing the<br />

individual characters, by the operator get_data_code_2d_results, which will be discussed in detail<br />

in section 5.1.2 on page 29.


Step 3: Clear the 2D data code model<br />

clear_data_code_2d_model (DataCodeHandle)<br />

3 Model Adaptation 7<br />

The operators create_data_code_2d_model and find_data_code_2d allocate memory. To reset the<br />

2D data code model and explicitly free the model memory, the operator clear_data_code_2d_model<br />

is called.<br />

When running the program, the applied operators assume default values for the parameters used by the<br />

specified 2D data code model. As these default values are choosen according to a certain standard, not<br />

all symbols can be found and decoded. The next chapter describes how the parameters can be adapted to<br />

better suit a specific application.<br />

3 Model Adaptation<br />

To be able to find a symbol in an image, the operator find_data_code_2d needs a set of parameters.<br />

In our first HDevelop program hdevelop\2d_data_codes_first_example.dev we did not explicitly<br />

set any parameters besides the SymbolType we were looking for. Thus, for all parameters needed for the<br />

chosen type, default values were used. These work for symbols fulfilling the following requirements:<br />

• The code must be printed dark on light,<br />

• the contrast value must be bigger than 30,<br />

• the sizes of symbol and modules are in a certain range (which depends on the selected symbol<br />

type),<br />

• there is no or only a small gap between neighboring modules of matrix codes (for PDF417 no gap<br />

is allowed),<br />

• for QR Codes, additionally all three position detection patterns must be visible.<br />

In many cases, you face symbols that do not fulfill all the requirements and therefore are not found.<br />

In this case, and also if you want to enhance the run time of your application, you have to modify the<br />

parameters in order to adapt the 2D data code model to your specific set of images. <strong>HALCON</strong> provides<br />

three different methods to modify the parameters. They are described in detail in the following sections.<br />

Additionally, tips concerning the run time and the storing of the 2D data code model are given. In<br />

particular, the next sections show how to<br />

• adjust the model to read a wider range of symbols (see section 3.1),<br />

• train the model automatically with a set of representative images (see section 3.2),<br />

• optimize the model by setting specific parameters manually (see section 3.3),<br />

• enhance the run time and save the modified model into a file (see section 3.4).<br />

Model Adaptation


8 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

3.1 Global Parameter Settings<br />

There are two predefined sets of parameters for the 2D data code model. The first one is used in the<br />

already mentioned standard mode, which is chosen by default when no other parameter settings are<br />

applied. It uses a restricted range of values for each parameter, is rather fast, and works fine for many,<br />

but not all, 2D data codes. The second one is used in the enhanced mode. There, a large range of values<br />

common for each parameter is checked. Therefore, it is not as fast as the standard mode, but now almost<br />

all readable symbols can be read. In particular, using this mode<br />

• the symbols may also appear light on dark,<br />

• the contrast can be lower (≥10),<br />

• the size of the modules can be smaller,<br />

• a bigger gap between neighboring modules is allowed for matrix codes,<br />

• for Data Matrix ECC 200 the symbol may be slanted up to 0.5235 (30 degrees)<br />

• and the size of the individual modules may vary in a specific range,<br />

• for a QR Code only two position detection patterns must be visible.<br />

Both modes can be set using the operator set_data_code_2d_param, although for the standard mode<br />

this is only necessary to reset a 2D data code model after using another 2D data code model. The HDevelop<br />

program hdevelop\2d_data_codes_global_settings.dev is similar to the first example, but<br />

now you can switch between standard and enhanced mode by (un)commenting the corresponding lines.<br />

enhanced := 1<br />

* enhanced := 0<br />

if (enhanced=1)<br />

set_data_code_2d_param (DataCodeHandle, ’default_parameters’,<br />

’enhanced_recognition’)<br />

else<br />

set_data_code_2d_param (DataCodeHandle, ’default_parameters’,<br />

’standard_recognition’)<br />

endif<br />

Now, when running the program in enhanced mode, the symbols that were not found in standard mode<br />

are correctly decoded. Switching from standard mode to enhanced mode is the easiest way to find symbols<br />

that do not fulfill the requirements of the standard mode. However, because for each parameter<br />

more alternatives have to be checked the time needed for the search process increases, especially when<br />

no code is found at all. The following code lines are used to measure the time needed to run the operator<br />

find_data_code_2d. Thus, you can compare the run time needed for reading with both global parameter<br />

sets. The result is displayed by a procedure called write_message. For example, in figure 4 the<br />

run time needed in enhanced mode is approximately twice the time needed in standard mode.


dev_update_var (’off’)<br />

count_seconds (T1)<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, [], [],<br />

ResultHandles, DecodedDataStrings)<br />

count_seconds (T2)<br />

dev_update_var (’on’)<br />

write_message (WindowHandle, 30, -1,<br />

’Time = ’ + (1000 * (T2-T1))$’.1f’ + ’ms’, true)<br />

3.2 Training 9<br />

Figure 4: Run time required on an Intel Pentium 4 platform (2.4 GHz CPU): 13.6ms in standard mode and<br />

26.5ms in enhanced mode.<br />

To decrease the run time you have to adapt the parameters to your specific images. This can be done either<br />

by an automatic training (see next section) or by setting specific parameters manually (see section 3.3).<br />

<strong>Note</strong> that these methods can mainly be used to reduce the run time. If your symbols cannot be decoded<br />

in enhanced mode, apart from a few exceptions a further adaptation of the model will not work either.<br />

In such a case, you should enhance the quality of your images. This can be done either during the<br />

image acquisition (pay attention, e.g., to the lighting conditions, see section 5.2 on page 37), which is<br />

recommended, or by a preprocessing (see section 4 on page 20).<br />

3.2 Training<br />

If you have a set of symbols you want to find, read, and decode, in most cases the individual symbols have<br />

similar attributes. This similarity can be used to train your 2D data code model, i.e., you use a subset<br />

of your symbols to automatically obtain an individual set of parameters suited best for your specific<br />

application. After the training, you use this parameter set to find the symbols in your remaining images.<br />

By this means, you can find the symbols also if they do not fulfill the requirements of the standard mode.<br />

But opposite to using the enhanced mode, in most cases more restricted parameter values are checked<br />

and therefore the search process becomes faster.<br />

Model Adaptation


10 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

3.2.1 Train the Model<br />

In the HDevelop program hdevelop\2d_data_codes_training.dev, the 2D data code model created<br />

by create_data_code_2d_model is trained with two different images. For training, the operator<br />

find_data_code_2d, i.e., the same operator as for reading a 2D data code, is applied. This time, the<br />

additional parameter ’train’ is assigned. Its value determines the group of parameters that will be<br />

affected by the training. Here, we choose ’all’, i.e., all available model parameters are trained. If<br />

you want to train only specific groups like ’symbol_size’, ’module_size’, or ’contrast’, you can<br />

combine them using tuples. Inside a tuple, you can also choose the value ’all’ and exclude specific<br />

groups from the training by using their name with a preceeding ’~’. A complete list of valid values<br />

for the parameter ’train’ is provided in the description of the operator find_data_code_2d in the<br />

Reference Manual. If you work with images that contain more than one symbol, you can use all symbols<br />

for training by setting the additional parameter ’stop_after_result_num’ to the correct number of<br />

expected symbols. If you want to use only specific symbols, you can reduce the domain to a region of<br />

interest (ROI) containing only the specific symbols. For a short introduction to ROIs see section 3.4.1.<br />

Extensive descriptions can be found in the Quick Guide, section 3.2 on page 27.<br />

The operator find_data_code_2d is applied to each training image individually. The training of the<br />

first image restricts the model to the parameter values needed to find, read, and decode the symbol of<br />

that specific image. All following training images are used to extend the restricted model again, so that<br />

the resulting model suits the whole set of images. If all symbols have the same size, no gaps between the<br />

modules, foreground and background modules of the same size, no distinct texture in the background,<br />

and a similar contrast, one image is sufficient for the training. But for most applications, several training<br />

images are recommended. For a satisfying training result, you should use your most different images.<br />

Here, we choose two images with different contrast values (see figure 5).<br />

create_data_code_2d_model (’ECC200’, [], [], DataCodeHandle)<br />

* -> dark image<br />

read_image (Image, ’datacode/ecc200/ecc200_cpu_007’)<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, ’train’, ’all’,<br />

ResultHandles, DecodedDataStrings)<br />

* -> light image<br />

read_image (Image, ’datacode/ecc200/ecc200_cpu_008’)<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, ’train’, ’all’,<br />

ResultHandles, DecodedDataStrings)<br />

The training leads to a new 2D data code model, which is now used to find, read, and decode the symbols<br />

in the remaining images. To do this, the operator find_data_code_2d is applied again, this time<br />

without the parameter ’train’. At the end of the program the operator clear_data_code_2d_model<br />

is called to reset the model and free the allocated memory.<br />

for i := 7 to 16 by 1<br />

read_image (Image, ’datacode/ecc200/ecc200_cpu_0’ + (round(i)$’.2’))<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, [], [],<br />

ResultHandles, DecodedDataStrings)<br />

endfor<br />

clear_data_code_2d_model (DataCodeHandle)


Figure 5: Images with different contrast values for training the 2D data code model.<br />

3.2.2 Inspect the Changes<br />

3.2.2 Inspect the Changes 11<br />

In the program hdevelop\2d_data_codes_training.dev, the training is framed by additional code<br />

lines, which are not necessary for the training or the following reading of the symbols, but help<br />

to understand how the training changes the 2D data code model. Before the training, the operator<br />

query_data_code_2d_params gets a list of parameters valid for symbols of the type specified in the<br />

2D data code handle. In this case all model parameters that can be set for symbols of type ’Data<br />

Matrix ECC 200’ are queried. The current values of these parameters are obtained by the operator<br />

get_data_code_2d_param.<br />

query_data_code_2d_params (DataCodeHandle, ’get_model_params’,<br />

GenParamNames)<br />

get_data_code_2d_param (DataCodeHandle, GenParamNames, ModelBeforeTraining)<br />

After the training, the parameter values are checked again and the changes between the untrained and the<br />

trained model, stored in the variable ’ModelAdaptation’, are displayed (see figure 6).<br />

get_data_code_2d_param (DataCodeHandle, GenParamNames, ModelAfterTraining)<br />

ModelAdaptation := GenParamNames + ’: ’ + ModelBeforeTraining + ’ -> ’<br />

+ ModelAfterTraining<br />

dev_inspect_ctrl (ModelAdaptation)<br />

In some cases, e.g., when you want to read additional symbols that are not similar to the symbols used<br />

for the training, you have to adapt selected parameters manually. The next section shows how to apply<br />

individual modifications and goes deeper into specific groups of parameters available for the 2D data<br />

code operators provided by <strong>HALCON</strong>.<br />

3.3 Specific Parameter Settings<br />

The third and most complex way to modify a 2D data code model is to change specific parameters<br />

manually. The HDevelop program hdevelop\2d_data_codes_manual_settings.dev shows how<br />

Model Adaptation


12 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 6: Displaying changes of parameter values.<br />

to modify parameters and introduces several operators that provide a deeper insight into a specific 2D<br />

data code model. The operator query_data_code_2d_params, as already mentioned in section 3.2.2,<br />

queries lists of parameters valid for a specific symbol type. Here, again the list of the available<br />

model parameters GenParamNames is queried (for further lists see section 5.1.1 on page 27). Their<br />

current values, in this case the default values of the standard mode, are obtained using the operator<br />

get_data_code_2d_param.<br />

query_data_code_2d_params (DataCodeHandle, ’get_model_params’,<br />

GenParamNames)<br />

get_data_code_2d_param (DataCodeHandle, GenParamNames, GenParamValues)<br />

The modification of a model can be done either within the operator create_data_code_2d_model or<br />

by the operator set_data_code_2d_param, as already introduced in section 3.1. The latter operator<br />

can be called several times and therefore is used if several tuples of parameters that cannot be combined<br />

in the same operator call have to be modified. Instead of setting all parameters at once by specifying a<br />

global parameter set, we now modify the individual parameters separately. The following sections go<br />

deeper into the specific groups of model parameters, particularly concerning<br />

• the shape and size of the symbols (see section 3.3.1),<br />

• the appearance of the modules, e.g., their contrast or size (see section 3.3.2),<br />

• the general behavior of the 2D data code model, i.e., the strictness of the symbol search and the<br />

storing of intermediate results (see section 3.3.3).<br />

For the first two groups a concise overview to the value ranges specific to each individual symbol type is<br />

provided in section 5.3.2 on page 40. The complete list of parameter names is provided in the description<br />

of the operator set_data_code_2d_param in the Reference Manual.


3.3.1 Shape and Size of the Symbols<br />

3.3.1 Shape and Size of the Symbols 13<br />

One group of parameters used for a 2D data code model is related to the size, e.g., the number of rows<br />

and columns, but also the shape or type of a symbol.<br />

Symbol Shape (only Data Matrix ECC 200)<br />

For Data Matrix ECC 200, the parameter ’symbol_shape’ specifies the shape of the symbol. If it is set<br />

to ’rectangle’, the number of rows and columns differs. If it is set to ’square’, the number of rows<br />

and columns is equal. If the value ’any’ is passed, both shapes are searched for. Since <strong>HALCON</strong> 7.1.1,<br />

the parameter ’symbol_shape’ still can be queried but now the search algorithm is the same for both<br />

shapes. Thus, for the symbol search it is of no importance for the parameter settings anymore.<br />

Symbol Size<br />

Parameters related to the symbol size set the minimum and maximum number of rows and columns allowed<br />

for a searched symbol. For matrix codes (Data Matrix ECC 200 and QR Code), rows and columns<br />

correspond to modules, whereas for the stacked code (PDF417), they correspond to codewords (excluding<br />

the codewords of the start and stop patterns as well as those of the left and right row indicators). QR<br />

Codes are always square and therefore have the same number for rows and columns. For them, instead<br />

of setting the number explicitly, it can also be set implicitly by specifying the version number. For Data<br />

Matrix ECC 200 and PDF417 the number of rows and columns may differ.<br />

In the example program, the shape and size of the symbol are the first attributes to be modified. The variable<br />

window shows the default values of the parameters queried by get_data_code_2d_param before<br />

applying the modification. By default, the Data Matrix ECC 200 symbol may have any shape and its size<br />

can lie between 8 to 144 rows and 10 to 144 columns (see figure 7). The parameter ’symbol_size’<br />

assumes a square symbol and therefore expects a single value for the number of rows and columns. So,<br />

by setting it to 18, we speed up the search process by restricting the model to square shaped symbols<br />

with 18 rows and 18 columns.<br />

set_data_code_2d_param (DataCodeHandle, ’symbol_size’, 18)<br />

Available range for the symbol size of Data Matrix ECC 200: 10x10 − 144x144 (square), 8x18 − 16x48 (rectangular)<br />

12x12<br />

18x18<br />

24x24<br />

Figure 7: Examples for symbol sizes of Data Matrix ECC 200.<br />

Model Adaptation


14 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Model Type (only QR Code)<br />

Two types of QR Code are differentiated: the old Model 1 and the new Model 2 (see figure 8). For both<br />

model types the smallest symbol consists of 21 rows and columns and is specified as Version 1. The<br />

largest symbol consists of 73 rows and columns (Version 14) for Model 1 and 177 rows and columns<br />

(Version 40) for Model 2. In addition to the position detection patterns, symbols of Version 2 or larger<br />

contain extension patterns for Model 1 and alignment patterns for Model 2. When working with QR<br />

Codes, the model should be restricted to the correct model by setting ’model_type’ to 1 or 2. If the<br />

parameter is set to ’any’, both types are searched for.<br />

3.3.2 Appearance of the Modules<br />

QR Code: Model 1 QR Code: Model 2<br />

21x21 − 73x73 (Version 1−14) 21x21 − 177x177 (Version 1−40)<br />

Extension Patterns (except Version 1) Alignment Pattern (except Version 1)<br />

Fourth Corner is Fixed<br />

Figure 8: QR Codes: (left) Model 1, (right) Model 2.<br />

The modules of 2D data code symbols can differ significantly in their general appearance. In the program,<br />

the settings for some of the main attributes are modified.<br />

Polarity<br />

The parameter ’polarity’ determines if the foreground modules are darker or brighter than the background<br />

(see figure 9) or if both polarities are checked. By default, the value ’dark_on_light’ is set.<br />

If it is set to ’any’, both polarities are checked. In the program we change it to ’light_on_dark’ to<br />

adapt it to our specific symbols.<br />

set_data_code_2d_param (DataCodeHandle, ’polarity’, ’light_on_dark’)<br />

Mirrored<br />

Especially when reading symbols on transparent surfaces, it may occur that the symbol’s representation<br />

is mirrored (see figure 10). By default, the parameter ’mirrored’ is set to ’any’, i.e., mirrored and<br />

non-mirrored symbols are searched for. If you have only mirrored symbols you can restrict the search by<br />

setting the parameter to ’yes’. Here, all of our symbols are not mirrored, so we restrict the search by<br />

setting the parameter to ’no’.<br />

set_data_code_2d_param (DataCodeHandle, ’mirrored’, ’no’)


Figure 9: Symbols of different polarity: (left) dark on light and (right) light on dark.<br />

3.3.2 Appearance of the Modules 15<br />

Figure 10: Alignment of rows and columns: (left) non-mirrored and (right) mirrored symbol.<br />

Minimum Contrast<br />

The contrast corresponds to the difference between the gray values of the foreground and the background<br />

of a symbol, but also depends on the gradient of the edges. For blurred images, the contrast must be lower<br />

than the gray value difference. In standard mode, the minimum contrast is set to 30. Here, the contrast in<br />

some of our images is rather low. Therefore, we set the parameter ’contrast_min’ to the default value<br />

of the enhanced mode, i.e., a value of 10. See figure 11 for symbols of different contrast.<br />

set_data_code_2d_param (DataCodeHandle, ’contrast_min’, 10)<br />

Module Size<br />

Parameters related to the module size restrict the size of a module in pixels to speed up the search<br />

process. This is useful if the modules of all symbols are of similar size. For both matrix codes, the<br />

size is described by the width and height of a module, whereas for PDF417 codes, it is described by the<br />

module width and the module aspect ratio, which is the module height divided by the module width (see<br />

figure 12). The default values for the different ranges depend on the chosen symbol type. For symbols of<br />

type ’Data Matrix ECC 200’, the default range in standard mode is 6 to 20 pixels. Because we have<br />

rather small modules in our images, we restrict the range to 4 to 7 pixels.<br />

set_data_code_2d_param (DataCodeHandle, [’module_size_min’,<br />

’module_size_max’], [4,7])<br />

Model Adaptation


16 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 11: Symbols of different contrast: (left) 10 and (right) 34 .<br />

Module Aspect =<br />

Module Height<br />

Module Width<br />

Module Gap (only Matrix Codes)<br />

Figure 12: Module aspect ratio for PDF417.<br />

Module Width<br />

Module Height<br />

In contrast to PDF417 codes, the modules of a matrix code are not necessarily connected. If a gap<br />

between the modules exists you can specify the range of its size for both x- and y-direction (’small’ or<br />

’big’). In standard mode no or only a small gap (≤ 10% of the module size) is allowed. In the example<br />

program, we have no gaps in all directions of our symbols, so we restrict the parameter ’module_gap’<br />

to ’no’. Figure 13 illustrates the different gap sizes.<br />

set_data_code_2d_param (DataCodeHandle, ’module_gap’, ’no’)<br />

a) b) c)<br />

Figure 13: Size of module gaps: a) no gaps, b) small gaps, c) big gaps.


Maximum Slant (only Data Matrix ECC 200)<br />

3.3.3 Model Control Parameters 17<br />

For Data Matrix ECC 200, the L-shaped finder pattern is assumed to be right-angled, but a certain slant<br />

of the symbol can be coped with (see figure 14). In standard mode the maximum slant angle is 0.1745<br />

(10 degrees) and in enhanced mode the angle can be up to 0.5235 (30 degrees). Here, we keep the default<br />

value of the standard mode.<br />

Module Grid (only Data Matrix ECC 200)<br />

slant_max<br />

Figure 14: Slant angle.<br />

The parameter ’module_grid’ determines which algorithm is used for the calculation of the module<br />

positions of a Data Matrix ECC 200 symbol. If it is set to ’fixed’, the modules of the symbol have<br />

to be arranged in a regular grid with similar distance between the modules. If it is set to ’variable’,<br />

the grid is aligned to the alternating side of the finder pattern and the size of the modules may vary in<br />

a specific range, in particular they now may deviate up to a modules size from the regular grid. With<br />

’any’, both approaches are tested one after the other.<br />

Number of Position Detection Patterns (only QR Code)<br />

When working with QR Codes, you can set the parameter ’position_pattern_min’ for the number<br />

of position detection patterns that are at least required to be present to 3 or 2. 3 is the default value of the<br />

standard mode and means that all position detection patterns have to be visible. 2 is used in enhanced<br />

mode. There, one of the patterns may be missing.<br />

3.3.3 Model Control Parameters<br />

Besides the shape, size, and appearance of the symbol, you can specify the parameters ’persistence’<br />

and ’strict_model’, which control the general behavior of a 2D data code model.<br />

Persistence<br />

The parameter ’persistence’ determines how intermediate results, obtained while searching for symbols<br />

by the operator find_data_code_2d, are stored in the 2D data code model. By default, they are<br />

stored only temporarily (’persistence’ set to 0) in order to reduce the allocated memory. Setting the<br />

parameter ’persistence’ to 1, the results are stored persistently. Due to the high memory requirements,<br />

we recommend to do this only if some of the intermediate results are to be visualized or used for<br />

Model Adaptation


18 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

debugging purposes, e.g., when a symbol can not be read. Further information about debugging is given<br />

in section 5.1 on page 26.<br />

Strictness<br />

Sometimes, symbols can be read but nevertheless do not fit the model restrictions on the size of the<br />

symbols. The parameter ’strict_model’ controls if the operator find_data_code_2d rejects such<br />

symbols or returns them as a result independent of their size and the size specified in the model. For the<br />

first case, which is the default, the parameter is set to ’yes’. This is reasonable if only symbols of a<br />

certain size are to be found and other symbols, which may be contained in the image as well, should be<br />

ignored. If you set the parameter ’strict_model’ to ’no’, it may occur that also symbols that do not<br />

strictly fulfill the restrictions are found.<br />

3.4 Miscellaneous<br />

3.4.1 Speeding up find_data_code_2d<br />

You can speed up the run time of the operator find_data_code_2d in two ways. One way is to restrict<br />

the search space, the other way is to restrict the value ranges of the parameters used by the 2D data code<br />

model. In the following, both approaches are described in more detail.<br />

Region of Interest<br />

The standard <strong>HALCON</strong> approach to speed up the processing is to restrict the search space. For this, you<br />

define a region of interest (ROI) where the symbol is searched in. If, e.g., all of your images have the<br />

symbol placed in the upper left corner, you define a region that covers the upper left corner in a way<br />

that it contains the symbols in all images. An ROI can be created, e.g., by generating a rectangle with<br />

the operator gen_rectangle1. After reading an image, you reduce the image domain to this specific<br />

rectangular region using the operator reduce_domain. Instead of the original image you then use the<br />

reduced one in the operator find_data_code_2d. Further information about ROIs can be found in the<br />

Quick Guide, section 3.2 on page 27.<br />

Restricted Model<br />

In section 3.1 on page 8 it was already mentioned that adjusting the model parameters significantly<br />

affects the run time of the operator find_data_code_2d. So, the second way to speed it up is to restrict<br />

all parameters to the minimum range of values needed for your specific symbol representations. To<br />

understand the importance of restricting the ranges of values for specific parameters, we have a closer<br />

look at the functionality of the symbol search.<br />

The search takes place in several passes, starting at the highest pyramid level, i.e., the level where symbols<br />

with the maximum module size are still visible. The minimum module size determines the lowest<br />

pyramid level to investigate (see figure 15). Reducing the range of values for the module size, we reduce<br />

the number of passes needed for the symbol search and thus enhance the run time.<br />

In each pyramid level specific parameters are checked. If, e.g., the ’polarity’ is set to ’any’, in a<br />

first pass ’dark_on_light’ symbols are searched for. If none are found, a second pass searches for<br />

’light_on_dark’ symbols. Therefore, restricting the polarity significantly increases the speed.


Figure 15: Pyramid levels.<br />

3.4.2 Store the 2D Data Code Model 19<br />

Each pass consists of two phases, the search phase and the evaluation phase. The search phase is used to<br />

look for finder patterns and generate symbol candidates for every detected finder pattern. The evaluation<br />

phase is used to investigate the candidates in a lower pyramid level and, if possible, to read them. The<br />

operator find_data_code_2d terminates when the required number of symbols was successfully decoded,<br />

or when the last pass was performed. This explains why the symbol search is rather fast when the<br />

right parameter values are checked first and takes much longer when a wide range of parameter values<br />

has to be checked, but the requested number of symbols is not found.<br />

In summary, if run time matters to your application, you should pay special attention to the model<br />

parameters for the following attributes:<br />

• polarity,<br />

• minimum module size,<br />

• number of symbol rows (for PDF417, especially for strongly cluttered or textured images),<br />

• module gaps (for matrix codes with very small modules),<br />

• the minimum number of position detection patterns (for QR codes).<br />

If these parameters are not set correctly or with a range that is unnecessarily wide, the search process<br />

slows down, especially when the requested number of symbols cannot be found. The actual values<br />

of the found symbols can be queried with the operator get_data_code_2d_results as described in<br />

section 5.1.2 on page 29.<br />

3.4.2 Store the 2D Data Code Model<br />

After changing the parameter setting by an automatic training or by a manual parameter setting, the<br />

new model can be stored in a file using the operator write_data_code_2d_model. The HDevelop<br />

Model Adaptation


20 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

program hdevelop\write_2d_data_code_model.dev shows the main steps for storing a trained 2D<br />

data code model. First, like in the previous example programs, a 2D data code handle for symbols of<br />

the type ’Data Matrix ECC 200’ is created. Then, the model is trained by applying the operator<br />

find_data_code_2d to selected images using the parameter ’train’. This step changes the 2D data<br />

code model, which then is stored into the default file ’2d_data_code_model.dcm’ using the operator<br />

write_data_code_2d_model. Finally, the model is deleted to free the allocated memory.<br />

create_data_code_2d_model (’ECC200’, [], [], DataCodeHandle)<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, ’train’, ’all’,<br />

ResultHandles, DecodedDataStrings)<br />

write_data_code_2d_model (DataCodeHandle, ’2d_data_code_model.dcm’)<br />

clear_data_code_2d_model (DataCodeHandle)<br />

Using the saved file, you can restore the saved model in a later session. In the HDevelop<br />

program hdevelop\read_2d_data_code_model.dev, instead of calling the operator create_data_code_2d_model<br />

at the beginning of the program, the operator read_data_code_2d_model<br />

is used to create a 2D data code handle, which loads the parameter settings described in the file<br />

’2d_data_code_model.dcm’.<br />

read_data_code_2d_model (’2d_data_code_model.dcm’, DataCodeHandle)<br />

for i := 7 to 16 by 1<br />

read_image (Image, ’datacode/ecc200/ecc200_cpu_0’ + (round(i)$’.2’))<br />

find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, [], [],<br />

ResultHandles, DecodedDataStrings)<br />

endfor<br />

clear_data_code_2d_model (DataCodeHandle)<br />

4 Preprocessing Difficult Images<br />

The different methods for changing the model parameters follow two complementary goals. The global<br />

parameter settings of the enhanced mode extend the ranges for the parameter values of the 2D data code<br />

model so that almost any symbol can be read. An automatic training or a manual parameter setting on the<br />

other hand restricts the ranges to enhance the run time for the images of a specific application. Therefore,<br />

if a symbol cannot be read in enhanced mode it is most likely not readable with other parameter settings<br />

as well (the few exceptional parameters that may be out of the range specified for the enhanced mode<br />

are listed in section 5.3.2 on page 41). Reasons for a failure of the 2D data code reader comprise various<br />

irreparable distortions of the symbol, which will be introduced in section 5.2 on page 37, and several<br />

problems that occur because of the bad quality of the symbol’s appearance. Both problems should be<br />

avoided already when acquiring the image. But if you nevertheless have to work with images of bad<br />

quality, at least the following problems have a chance to be solved by preprocessing the image before<br />

applying the operator find_data_code_2d:<br />

• The symbol cannot be read because it is slanted beyond the allowed slant angle (for troubleshooting<br />

see section 4.1),<br />

• the size of the modules is smaller than the minimum size allowed for the specific symbol type (for<br />

troubleshooting see section 4.2),


4.1 Slanted Symbol 21<br />

• the gaps between the modules of a matrix code are larger than the biggest allowed module gap (for<br />

troubleshooting see section 4.3),<br />

• there is too much noise in the image so that foreground and background of the symbol cannot be<br />

clearly distinguished anymore (for troubleshooting see section 4.4).<br />

4.1 Slanted Symbol<br />

In section 3.3 on page 16 it was mentioned that small slant angles are allowed for the L-shaped finder<br />

element of a Data Matrix ECC 200 code. Large slant angles may lead to problems for all symbols,<br />

independent of the symbol type. If a symbol is strongly skewed because of radial or perspective distortions,<br />

a PDF417 or a QR Code cannot be decoded and a Data Matrix ECC 200 is not even detected as<br />

a valid symbol. To nevertheless decode those symbols, you have to rectify the image before applying<br />

the operator find_data_code_2d. If you have a set of images with slanted symbols we recommend a<br />

calibrated rectification. Comprehensive information can be found in the <strong>Application</strong> <strong>Note</strong> on 3D Machine<br />

Vision, section 3.3 on page 49. For single symbols or a set of symbols lying in the same plane, the<br />

HDevelop program hdevelop\2d_data_codes_rectify_symbol.dev provides a fast solution for an<br />

uncalibrated rectification of a perspective distortion, which requires a little manual effort.<br />

After reading an image with a slanted symbol, we use the online zooming tool of HDevelop to obtain<br />

the coordinates of all four corners of the symbol. Then, we define the coordinates of the four corners of<br />

the rectified symbol we want to obtain as result of the rectification. The shape of the rectified symbol<br />

depends on the ratio of rows and columns for the specified symbol type. As the symbol in our image<br />

is a Data Matrix ECC 200 with an equal number of rows and columns, we choose a square shape and<br />

define its corner coordinates. The operator hom_vector_to_proj_hom_mat2d uses the coordinates of<br />

the slanted symbol and the coordinates of the rectified symbol to compute a transformation matrix, which<br />

is then used by the operator projective_trans_image to transform the slanted symbol into a square<br />

symbol with the defined extent. If you have a set of symbols lying in the same plane, the transformation<br />

matrix only has to be computed once since it can be used to rectify the other symbols as well.<br />

hom_vector_to_proj_hom_mat2d ([130, 225, 290, 63], [101, 96, 289, 269], [1,<br />

1, 1, 1], [70, 270, 270, 70], [100, 100, 300,<br />

300], [1, 1, 1, 1], ’normalized_dlt’,<br />

HomMat2D)<br />

projective_trans_image (Image_slanted, Image_rectified, HomMat2D,<br />

’bilinear’, ’false’, ’false’)<br />

The rectified symbol can be found, read, and decoded as described in section 2 on page 5 and section 3<br />

on page 7. Figure 16 shows the slanted symbol before and after the rectification and decoding.<br />

4.2 Small Module Size<br />

2D data codes can only be read robustly if the minimum size of a module does not fall below<br />

four pixels for matrix codes and three pixels for PDF417 codes. If you work with images of<br />

lower resolution you can nevertheless read them after zooming them. The HDevelop program hdevelop\2d_data_codes_enlarge_modules.dev<br />

reads an image of low resolution. To increase the<br />

resolution of the symbol, the image is zoomed by a factor of 2 using the operator zoom_image_factor.<br />

Preprocessing


22 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 16: Uncalibrated rectification of an individual image with small manual effort: (left) symbol with<br />

perspective distortion, (right) decoded symbol after rectification.<br />

zoom_image_factor (Image, ImageZoomed, 2, 2, ’constant’)<br />

To study the effect of the zooming, you can use the zooming tool of HDevelop. In contrast to the zooming<br />

operation, the zooming tool has no effect on the resolution of the image, but on the display size. Figure 17<br />

shows a symbol and the modules of its upper right corner before and after the zooming operation.<br />

a) b)<br />

Figure 17: Symbol corner enlarged by the zooming tool of HDevelop: (a) before and (b) after increasing<br />

the resolution of the image.<br />

Now the number of pixels for each individual module is sufficient and the symbol can be read as described<br />

in section 2 on page 5 and section 3 on page 7. Figure 18 shows the successfully decoded


symbol.<br />

Figure 18: After zooming the image, the symbol is found, read, and decoded.<br />

4.3 Large Module Gaps<br />

4.3 Large Module Gaps 23<br />

For matrix codes, gaps between modules are allowed in a certain range. The HDevelop program hdevelop\2d_data_codes_minimize_module_gaps.dev<br />

shows how to read a Data Matrix ECC 200<br />

with very large gaps. First, we try to adapt the parameters for the 2D data code model as described<br />

in section 3 on page 15, i.e., we adapt the parameter ’module_gap_min’ to the biggest allowed<br />

module gap ’big’ before trying to read the code. The adaptation can be done either with the operator<br />

set_data_code_2d_param or as shown in the following code lines within the operator create_data_code_2d_model.<br />

create_data_code_2d_model (’Data Matrix ECC 200’, [’module_gap_min’,<br />

’module_gap_max’], [’no’, ’big’],<br />

DataCodeHandle)<br />

Because the gaps in our image are larger than the biggest allowed module gap, i.e., bigger than 50% of<br />

the module size, the reading of the symbol fails. Getting no result by adapting the parameters of the<br />

model, we have to adapt the image to suit the model. Here, we use gray value morphology, in particular<br />

a gray value erosion with a rectangular structuring element, to enlarge the foreground modules and thus<br />

minimize the size of the gaps. Figure 19 shows the symbol before and after the gray value morphology.<br />

After the preprocessing, the symbol is found, read, and decoded.<br />

gray_erosion_shape (Image, ImageMin, 15, 15, ’rectangle’)<br />

<strong>Note</strong> that this procedure mainly works for matrix codes, i.e., Data Matrix ECC 200 and QR Code. For<br />

them, the distance between the modules only have to become smaller, whereas for PDF417 no gaps are<br />

allowed at all and the exact closing of the gaps is rather challenging, especially with gaps of slightly<br />

different size.<br />

4.4 Noise<br />

For the detection of 2D data code symbols, background and foreground should be clearly distinguishable,<br />

i.e., the modules should consist of homogeneous or at least low-textured regions. If you cannot read<br />

Preprocessing


24 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 19: Preprocessing symbols with large module gaps: (left) original symbol with large gaps between<br />

the modules and (right) decoded symbol after gray value morphology.<br />

a symbol because there is too much texture or noise in the image you can try to preprocess the image<br />

with gray value morphology, a median filter, or a combination of both. The HDevelop program hdevelop\2d_data_codes_minimize_noise.dev<br />

reads a symbol with several parts distorted by noise.<br />

Especially the quiet zone in the lower part of the symbol is distorted by a noisy streak. We apply both<br />

preprocessing steps separately. For the gray value morphology, the operator gray_opening_shape<br />

with a rectangular structuring element is used. It partly closes the gaps and, what is more important here,<br />

reduces noise (see figure 20).<br />

gray_opening_shape (Image, ImageOpening, 7, 7, ’rectangle’)<br />

The median filter smoothes edges and also reduces noise (see figure 21).<br />

median_image (Image, ImageMedian, ’circle’, 3, ’continued’)<br />

For both procedures, because of the noise reduction, the difference between the symbol and the disturbing<br />

streak in the quiet zone becomes more obvious and the reading is successful. So, in this case both<br />

preprocessing steps lead to a successful 2D data code reading.<br />

5 Problem Handling<br />

The previous section proposed a selection of preprocessing steps for common problems when working<br />

with 2D data codes. Now, we will go deeper into the handling of problems.<br />

• In section 5.1 we introduce you to the debugging of the operator find_data_code_2d, which on<br />

the one hand helps to enhance the run time of successfully decoded symbols and on the other hand


5 Problem Handling 25<br />

Figure 20: Preprocessing a noisy image: (left) noise at the symbol’s lower border, (right) decoded after<br />

gray value morphology.<br />

Figure 21: Preprocessing a noisy image: (left) noise at the symbol’s lower border, (right) decoded after<br />

median filtering.<br />

is used for locating problems with symbols that are not decoded. To identify a problem often leads<br />

to ideas how an undecoded symbol can be preprocessed.<br />

• Some situations exist where a preprocessing yields no success. These situations and tips how to<br />

avoid them are presented in section 5.2.<br />

Problem Handling


26 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

• In section 5.3, the requirements and limitations for the 2D data code reader are summarized concisely.<br />

5.1 Data Access for Debugging<br />

During the search process of the operator find_data_code_2d, various results besides the decoded<br />

data string and the XLD contour of the successfully decoded symbol are available. These results provide<br />

hints how the search process can be enhanced with respect to run time, or why a symbol is not found<br />

or decoded. The HDevelop program hdevelop\2d_data_codes_data_access.dev shows how to<br />

access results for various reasons. The following sections describe the single steps of the program in<br />

detail. In particular, they introduce you to<br />

• data access in general, as well as a selection of results useful for all debugging purposes (see<br />

section 5.1.1),<br />

• a selection of results that are useful when facing symbols that are decoded successfully but slowly<br />

(see section 5.1.2),<br />

• a selection of results that may give you a hint why a symbol is not decoded (see section 5.1.3).<br />

The program concentrates on symbols of type Data Matrix ECC 200. Some characteristics of PDF417<br />

and QR Codes that deviate from the presented results are introduced in section 5.1.3 on page 35.<br />

5.1.1 General Information About Data Access<br />

The results obtained from the operator find_data_code_2d are divided into iconic and alphanumeric<br />

results. Iconic results, i.e., objects like images or regions, can be queried with the operator<br />

get_data_code_2d_objects. The input parameters for the operator are the DataCodeHandle,<br />

a CandidateHandle, and the ObjectName. Alphanumeric results are obtained by the operator<br />

get_data_code_2d_results. Here, the input parameters are the DataCodeHandle, the Candidate-<br />

Handle, and the ResultNames. The candidate handle needed for both iconic as well as for alphanumeric<br />

results specifies either an individual candidate for a symbol or a group of several candidates, for which<br />

the results or objects are queried. In a single operator call, you can combine a group of candidates with<br />

an individual result or an individual candidate with a tuple of results. A list of all predefined groups of<br />

candidates as well as all available object and result names for each SymbolType can be found in the<br />

Reference Manual at the descriptions of the individual operators.<br />

In the HDevelop program hdevelop\2d_data_codes_data_access.dev, we first specify the general<br />

settings, i.e., we create a 2D data code model for symbols of type ’Data Matrix ECC 200’ and set the<br />

default parameters to the enhanced mode so that all undamaged symbols can be decoded. By default,<br />

some of the results are stored only temporarily in the 2D data code model. Therefore, we set the model<br />

parameter ’persistence’ to 1 to keep all intermediate results in memory (see section 3.3.3 on page<br />

17).


create_data_code_2d_model (’Data Matrix ECC 200’, ’default_parameters’,<br />

’enhanced_recognition’, DataCodeHandle)<br />

set_data_code_2d_param (DataCodeHandle, ’persistence’, 1)<br />

5.1.1 General Information About Data Access 27<br />

The lists of the available alphanumeric result names and iconic object names are obtained<br />

by the operator query_data_code_2d_params with the parameters ’get_result_params’ and<br />

’get_result_objects’ (see also section 3.2.2 on page 11).<br />

query_data_code_2d_params (DataCodeHandle, ’get_result_params’,<br />

GenParamNames)<br />

dev_inspect_ctrl (GenParamNames)<br />

query_data_code_2d_params (DataCodeHandle, ’get_result_objects’,<br />

GenObjectNames)<br />

dev_inspect_ctrl (GenObjectNames)<br />

After reading an image, we apply the operator find_data_code_2d, which now stores all of its intermediate<br />

results, so that we can investigate them further.<br />

For the group of alphanumeric results, we differentiate between general results and results associated<br />

with a specific symbol candidate or a group of candidates. General results are used, e.g., to get information<br />

about the number of candidates related to each individual group of candidates. In the program,<br />

we set the CandidateHandle to ’general’ and pass a tuple containing all available general Result-<br />

Names. In detail, we want to access the number of all successfully decoded symbols (’result_num’),<br />

the number of all investigated candidates (’candidate_num’), the number of candidates that were identified<br />

as symbols but could not be read (’undecoded_num’), the number of candidates that could not be<br />

identified as valid candidates (’aborted_num’), the lowest and highest pyramid level that is searched<br />

for symbols (’min_search_level’ and ’max_search_level’), and the number of passes that were<br />

completed (’pass_num’). The last three values provide us with information about the performance<br />

of the search process. All result values that are stored in the variable ’GenResult’ are shown in the<br />

variable window of HDevelop. For better inspection, we display them in a new window (see figure 22).<br />

GenResultNames := [’result_num’, ’candidate_num’, ’undecoded_num’,<br />

’aborted_num’, ’min_search_level’,<br />

’max_search_level’, ’pass_num’]<br />

GenResultValues := []<br />

get_data_code_2d_results (DataCodeHandle, ’general’, GenResultNames,<br />

GenResultValues)<br />

GenResult := GenResultNames + ’: ’ + GenResultValues<br />

dev_inspect_ctrl (GenResult)<br />

candidatenum := GenResultValues[1]<br />

undecodednum := GenResultValues[2]<br />

abortednum := GenResultValues[3]<br />

If candidates are found the program queries and displays two iconic results of the search process, the<br />

search image, and the process image. The search image is the pyramid image in which a candidate is<br />

found, whereas the process image is the pyramid image in which it is investigated more closely. A visual<br />

inspection of search image and process image often leads to ideas why a symbol is not found or decoded,<br />

or why the decoding process takes too much time.<br />

Problem Handling


28 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 22: Display of general results.<br />

get_data_code_2d_objects (SearchImage, DataCodeHandle, 0,<br />

’search_image’)<br />

dev_display (SearchImage)<br />

write_message (WindowHandle, -1, -1, ’Search image’, true)<br />

get_data_code_2d_objects (ProcessImage, DataCodeHandle, 0,<br />

’process_image’)<br />

dev_display (ProcessImage)<br />

write_message (WindowHandle, -1, -1, ’Process image’, true)<br />

Figure 23 shows the search image and the process image of the image we already tried to read in section<br />

4.4 on page 23. The reason why the noisy streak in the quiet zone cannot be distinguished from the<br />

symbol becomes more obvious in the low-resolution search image than in the high-resolution original<br />

image.<br />

Figure 23: Pyramid images: (left) search image and (right) process image.<br />

Using the information on the number of candidates in each candidate group, we now discuss two different<br />

situations. On the one hand, we investigate successfully decoded symbols to get information about


5.1.2 Parameters to Access for Successfully Decoded Symbols 29<br />

their current parameter values so we can enhance the run time (see section 5.1.2). On the other hand,<br />

we investigate symbols which are not decoded to find out why they are not decoded and if specific<br />

preprocessing steps are suitable (see section 5.1.3).<br />

5.1.2 Parameters to Access for Successfully Decoded Symbols<br />

The main reason for the debugging of successfully decoded symbols is to enhance the run time of the<br />

search process, i.e., to reduce the number of the needed passes. For that, you have to restrict the ranges<br />

for the parameter values of the 2D data code model to a minimum (see section 3.2 on page 9 and section<br />

3.3 on page 11). To determine a reasonable range for a specific application it is helpful to query<br />

the current parameter values of the symbols using the operator get_data_code_2d_results. The success<br />

of the model adaptation can be controlled by comparing the number of completed passes queried in<br />

section 5.1.1 on page 27 before and after the adaptation.<br />

In the HDevelop program hdevelop\2d_data_codes_data_access.dev, we query a tuple of results<br />

which provide us with information about the symbol’s appearance and additional information concerning<br />

the successful search process (see figure 24). The latter comprises the actual pass in which the<br />

symbol was generated and processed (’pass’), a status message (’status’), and the decoded data<br />

string (’decoded_string’). Status messages provide you with the information whether a symbol was<br />

decoded successfully or why and at which point of the evaluation process the search was aborted for a<br />

specific candidate. Here, we query the results for successfully decoded symbols, so the status message<br />

in the tuple ’VariousResults’ is always ’successfully decoded’.<br />

ResultVariousNames := [’polarity’, ’module_height’,<br />

’module_width’, ’module_gap’,<br />

’mirrored’, ’contrast’, ’slant’,<br />

’pass’, ’status’, ’decoded_string’]<br />

ResultVariousValues := []<br />

get_data_code_2d_results (DataCodeHandle, ResultHandles[j],<br />

ResultVariousNames,<br />

ResultVariousValues)<br />

VariousResults := ResultVariousNames + ’: ’ +<br />

ResultVariousValues<br />

dev_inspect_ctrl (VariousResults)<br />

The ’DecodedDataStrings’ returned by the operator find_data_code_2d and the ’decoded_string’<br />

contained in the tuple ’VariousResults’ are restricted to 1024 characters. When<br />

working with rather large codes, you can query an unrestricted tuple containing all individual numbers<br />

and characters of the decoded data as ASCII code by passing the result name ’decoded_data’ to the<br />

operator get_data_code_2d_results. In the program, the resulting tuple ’ResultASCIICode’ is displayed<br />

in a window (see figure 25).<br />

get_data_code_2d_results (DataCodeHandle, ResultHandles[j],<br />

’decoded_data’, ResultASCIICode)<br />

dev_inspect_ctrl (ResultASCIICode)<br />

To control the classification of the modules that are determined in the search process the program queries<br />

two different arrays of regions, in particular the iconic representations of the foreground and background<br />

Problem Handling


30 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 24: Display of various individual results.<br />

Figure 25: Display of the decoded data (’<strong>MVTec</strong>’) as ASCII code.<br />

modules (’module_1_rois’ and ’module_0_rois’). The returned tuples of regions (’Foreground’<br />

and ’Background’) are displayed in figure 26.<br />

dev_set_color (’red’)<br />

get_data_code_2d_objects (Foreground, DataCodeHandle,<br />

ResultHandles[j], ’module_1_rois’)<br />

dev_display (Foreground)<br />

dev_set_color (’yellow’)<br />

get_data_code_2d_objects (Background, DataCodeHandle,<br />

ResultHandles[j], ’module_0_rois’)<br />

dev_display (Background)<br />

5.1.3 Parameters to Access for Symbols that are not Decoded<br />

For symbols that are not decoded, we differentiate further between symbols that are found but not decoded<br />

and symbols for which no candidate is classified as a valid symbol. If the minimum size of the<br />

modules is not set often the modules themselves are determined as candidates. To reduce the number of<br />

candidates and thus make the investigations more concise, we adapt the model to the minimum module<br />

size before applying the 2D data code reader to the problematic images (of index ’i’).


5.1.3 Parameters to Access for Symbols that are not Decoded 31<br />

Figure 26: Visualization of the individual modules of a successfully decoded symbol.<br />

if (i=3)<br />

set_data_code_2d_param (DataCodeHandle, ’module_size_min’, 24)<br />

endif<br />

if (i=4)<br />

set_data_code_2d_param (DataCodeHandle, ’module_size_min’, 10)<br />

endif<br />

if (i=5)<br />

set_data_code_2d_param (DataCodeHandle, ’module_size_min’, 2)<br />

endif<br />

Another method to reduce the number of the candidates, especially if the image contains other objects<br />

with right angles, is to reduce the domain of the image to an ROI containing the complete symbol<br />

(including its quiet zone). For the creation of ROIs see section 3.4.1 on page 18.<br />

To access all individual symbol candidates that are found but not decoded, we create the handle ’HandlesUndecoded’<br />

by passing the candidate handle ’all_undecoded’ and the result name ’handle’<br />

to the operator get_data_code_2d_results.<br />

get_data_code_2d_results (DataCodeHandle, ’all_undecoded’,<br />

’handle’, HandlesUndecoded)<br />

Then, we query the XLD contour and the corresponding status message for the undecoded symbol<br />

candidates. These provide important information about the reason why a candidate was not found or<br />

decoded. For successfully decoded symbols we received the XLD contour explicitly by the operator<br />

find_data_code_2d. For symbols that are not decoded, we have to query the XLD contours using the<br />

operator get_data_code_2d_objects with the result name ’candidate_xld’.<br />

Problem Handling


32 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

for j := 0 to |HandlesUndecoded|-1 by 1<br />

dev_display (Image)<br />

get_data_code_2d_results (DataCodeHandle,<br />

HandlesUndecoded[j], ’status’,<br />

StatusValue)<br />

write_message (WindowHandle, -1, -1, StatusValue, true)<br />

get_data_code_2d_objects (DataCodeObject, DataCodeHandle,<br />

HandlesUndecoded[j],<br />

’candidate_xld’)<br />

dev_display (DataCodeObject)<br />

Additionally, we visualize the regions of the modules, this time to check, e.g., if a great amount of<br />

modules is missing or if the modules deviate from the regular grid. Perhaps the modules are too small<br />

or the quiet zone is distorted by streaks. In these cases, the obtained grid may be translated relative to<br />

the symbol. These and other problems often can be solved by preprocessing the image as described in<br />

section 4 on page 20.<br />

dev_set_color (’red’)<br />

get_data_code_2d_objects (Foreground, DataCodeHandle,<br />

HandlesUndecoded[j],<br />

’module_1_rois’)<br />

dev_display (Foreground)<br />

dev_set_color (’yellow’)<br />

get_data_code_2d_objects (Background, DataCodeHandle,<br />

HandlesUndecoded[j],<br />

’module_0_rois’)<br />

dev_display (Background)<br />

Besides the iconic results, alphanumeric information about the modules can be obtained. During the<br />

search process, the modules are read row by row. The value 0 defines a certain background module and<br />

the value 100 defines a certain foreground module. Often, modules have a value somewhere in between.<br />

An automatically chosen threshold divides the foreground from the background modules. By inspecting<br />

the values, or more precisely their deviations from 0 or 100, you can evaluate the quality of the module<br />

classification.<br />

get_data_code_2d_results (DataCodeHandle,<br />

HandlesUndecoded[j],<br />

’bin_module_data’,<br />

ResultBinModules)<br />

dev_inspect_ctrl (ResultBinModules)<br />

endfor<br />

Figure 27 shows some of the modules of the symbol that we tried to read in section 4.2 on page 21.<br />

Because the modules are smaller than the specified minimum module size the computed grid cannot<br />

be fitted correctly to the symbol and each computed region contains parts of several modules, i.e., the<br />

individual regions contain dark and light parts at the same time.<br />

The binary values of all regions that are stored in the tuple ’ResultBinModules’ (see figure 28) confirm<br />

the visual impression, since for most of the regions the values strongly deviate from 0 or 100. Hence,<br />

the decision whether a region belongs to foreground or background is not reliable. As described in<br />

section 4.2, the problems caused by a small module size can be solved by increasing the size of the<br />

image.


5.1.3 Parameters to Access for Symbols that are not Decoded 33<br />

Figure 27: Regions of the approximated grid contain parts of multiple modules, which leads to an unreliable<br />

classification.<br />

Figure 28: Display of the binary values for each module.<br />

For candidates that are not detected as valid symbols, no module regions can be obtained. Therefore, after<br />

creating a handle for ’all_aborted’ candidates called ’HandlesAborted’, the debug information is<br />

reduced to the status message and the XLD contour for each candidate.<br />

Problem Handling


34 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

get_data_code_2d_results (DataCodeHandle, ’all_aborted’,<br />

’handle’, HandlesAborted)<br />

for j := 0 to |HandlesAborted|-1 by 1<br />

dev_display (Image)<br />

get_data_code_2d_objects (DataCodeObject,<br />

DataCodeHandle,<br />

HandlesAborted[j],<br />

’candidate_xld’)<br />

dev_set_color (’yellow’)<br />

dev_display (DataCodeObject)<br />

get_data_code_2d_results (DataCodeHandle,<br />

HandlesAborted[j], ’status’,<br />

StatusValue)<br />

write_message (WindowHandle, -1, -1, StatusValue, true)<br />

endfor<br />

For example, in figure 29 the status message tells us that the X-border of the finder element cannot be<br />

adjusted. By looking at the corresponding XLD contour, it becomes obvious that it cannot be adjusted<br />

because of the disturbing streak in the quiet zone near the X-border. To differentiate clearly between<br />

streak and symbol, we have to remove the noise as described in section 4.4 on page 23.<br />

Figure 29: A border of the finder pattern cannot be adjusted because of the streak in the quiet zone.<br />

Sometimes no candidate can be found at all. If this happens check visually if some of the problems<br />

introduced in section 4 on page 20 occur. Perhaps the gaps between the modules are so large that no<br />

connection between the individual modules is recognizable for the 2D data code reader, or the symbol is


5.1.3 Parameters to Access for Symbols that are not Decoded 35<br />

so noisy that the modules cannot be separated from each other. In these cases, you should try to solve<br />

the problems by applying the proposed preprocessing steps. Sometimes the symbols are damaged and<br />

cannot be read at all. Some of these situations and tips how to avoid them already at the image acquisition<br />

are introduced in section 5.2 on page 37.<br />

In the program, we concentrated on a selection of important results common for Data Matrix ECC 200. If<br />

you work with PDF417 or QR Codes, some results will differ. An example for rather different debugging<br />

results concerns slanted symbols. For the Data Matrix ECC 200 symbol that we already presented in<br />

section 4.1 on page 21 the 2D data code reader searches for a rectangular finder pattern. Because the<br />

symbol is slanted the right angles are lost and the status messages state problems related to the border<br />

of the symbol or the finder pattern (see figure 30). Since no valid finder pattern is identified all symbol<br />

candidates are aborted.<br />

Figure 30: The alternating border of a rectangular finder pattern cannot be reconstructed.<br />

For the PDF417 code in figure 31 no rectangular finder pattern is searched for. Therefore, several symbol<br />

candidates are found and adjusted in relation to the start or stop pattern of the symbol. Because these are<br />

degenerated and do not correspond to the outline of the actual symbol no data modules are found and the<br />

symbol is not decoded.<br />

The results for the QR Code in figure 32 are similar. Again, several symbol candidates are found, because<br />

the finder pattern, i.e., at least two of the three position detection patterns, are found. However, as the<br />

candidates are adjusted in relation to those two position detection patterns, the candidate does not fit the<br />

slanted symbol. Here, at least some of the modules are detected and visualize the square of the incorrect<br />

symbol candidate. Since inside the candidate the modules are in the wrong place the error correction<br />

fails.<br />

Problem Handling


36 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 31: The symbol candidate is related to the stop pattern and does not fit the actual symbol outline.<br />

Figure 32: The symbol candidate is related to two position detection patterns and does not fit the actual<br />

symbol outline.<br />

Additionally, further results are available, e.g., the actual error correction level for PDF417 and QR<br />

Codes, queried by get_data_code_2d_results with the parameter ’error_correction_level’.<br />

For PDF417, a value between 0 and 8 can be obtained. 0 means that errors are only detected but not<br />

corrected. The values 1 to 8 describe an increasing error correction capacity. For QR Codes, the increasing<br />

levels ’L’, ’M’, ’Q’, and ’H’ are available. As mentioned before, the complete list of results<br />

specific for each SymbolType can be found in the Reference Manual at the description of the operators<br />

get_data_code_2d_results and get_data_code_2d_objects.


5.2 Selected Problems and Tips to Avoid Them<br />

5.2 Selected Problems and Tips to Avoid Them 37<br />

The 2D data code reader of <strong>HALCON</strong> is a rather powerful tool, which can be used to read also partly<br />

distorted symbols. But sometimes a symbol is distorted so much that it cannot be decoded even after<br />

preprocessing the image. Some distortions are because of damaged symbols, e.g., symbols that are<br />

not printed correctly or for which a great amount of modules is missing for various reasons. Other<br />

distortions occur during the image acquisition. These can be avoided by the right acquisition conditions.<br />

In the following, we introduce you to examples for distortions that result either from<br />

• a bad geometry, i.e., the modules of the symbol are not placed on a regular grid (see section 5.2.1),<br />

• or a bad radiometry, i.e., due to bad lighting conditions the individual modules cannot be classified<br />

correctly (see section 5.2.2).<br />

We recommend to avoid both situations by flattening the symbols to a level surface and using diffuse<br />

light at the image acquisition.<br />

5.2.1 Geometric Distortions<br />

The modules of an ideal symbol are placed on a regular grid. For matrix codes the grid must be regular<br />

along the whole symbol, whereas for PDF417 a regular grid is necessary only within the individual<br />

columns. While searching for a symbol, the operator find_data_code_2d searches for the<br />

finder pattern (or start and stop pattern for PDF417) of the specified symbol. If found, it approximates<br />

a grid for the modules, which is adjusted in relation to the finder pattern. Some errors, i.e.,<br />

small deviations of the modules from the grid (up to a displacement of half a modules size, for Data<br />

Matrix ECC 200 up to a whole modules size when ’module_grid’ is set to ’variable’), can be<br />

coped with. For stronger deviations the 2D data code reading fails. The HDevelop program hdevelop\2d_data_codes_arbitrary_distortions.dev<br />

reads symbols with various distortions. In<br />

Figure 33, e.g., six symbols are printed on paper. The paper is crumpled, so that arbitrary distortions<br />

occur to the symbols and for four of them the modules deviate so much from the regular grid, that they<br />

cannot be decoded.<br />

In contrast to the regular distortion in section 4.1 on page 21, which can be removed by a rectification,<br />

here the distortions are arbitrary and irregular. Therefore, no preprocessing step can be proposed. You<br />

have to prevent such a situation already when acquiring the images by attending that the symbols are<br />

as flat as possible. If your symbols are printed on a flexible surface like paper, you can, e.g., flatten<br />

them with a glass plate. But then, you have to be very careful and consider the right lighting conditions.<br />

Otherwise you may get problems because of reflections as described in the next section.<br />

5.2.2 Radiometric Distortions<br />

Besides the right geometry of the symbol’s grid, the contrast and a uniform appearance of the symbol’s<br />

modules, especially with regard to their polarity, are essential for the decoding of 2D data codes.<br />

The HDevelop program hdevelop\2d_data_codes_arbitrary_distortions.dev searches for the<br />

symbols of two more images. These contain symbols printed on a reflecting surface. Figure 34 shows an<br />

image where the reflections are so strong that for some parts of the symbols the contrast approaches 0,<br />

Problem Handling


38 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

Figure 33: Four symbols cannot be read because of arbitrary geometric distortions.<br />

Figure 34: Two symbols cannot be read because parts of the symbols are not visible because of reflections.<br />

i.e., the information about the modules of these parts is not available anymore. Thus, the symbols cannot<br />

be reconstructed by preprocessing and the 2D data code reading fails.<br />

Figure 35 illustrates another problem that occurs because of bad lighting conditions. Here, because of<br />

reflections the polarity changes within two of the symbols. This leads to problems, since in most cases a<br />

change of the appearance of the modules inside a symbol cannot be coped with.<br />

For both cases, no preprocessing is reasonable to improve the image in a way that makes the symbols<br />

readable again. Therefore, it is especially important to avoid strong reflections by using diffuse light at


5.3 Requirements and Limitations 39<br />

Figure 35: Two symbols cannot be read because of a changed module appearance (polarity).<br />

the image acquisition.<br />

5.3 Requirements and Limitations<br />

For a successful 2D data code reading, a symbol’s representation must fulfill certain requirements. Some<br />

of them were already stated in the preceeding sections. Generally, the value ranges specified for the<br />

individual parameters should not be exceeded. Most of the limits are soft, i.e., sometimes symbols can<br />

be read although their parameter values do not completely lie in the specified ranges. But since this<br />

cannot be ensured you should try to adhere to the rules summarized in section 5.3.1. A concise list of the<br />

value ranges allowed for the parameter groups related to the size and appearance of the symbols is given<br />

in section 5.3.2.<br />

5.3.1 Main Rules to Follow<br />

All symbol types:<br />

• The symbol (including the quiet zone) must be contained completely in the image.<br />

• The modules must fit a regular grid and therefore should have approximately the same size. For<br />

matrix codes, the grid has to be regular along the whole symbol, whereas for PDF417 codes it<br />

has to be regular only within the individual columns. Some errors up to a displacement of half a<br />

modules size (for Data Matrix ECC 200 up to a whole modules size when ’module_grid’ is set<br />

to ’variable’) can be coped with, whereas errors at the finder pattern are worse than errors at<br />

the data modules.<br />

• The appearance of the modules of a symbol should be uniform. Especially the polarity must not<br />

change within a symbol.<br />

Problem Handling


40 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes<br />

• Although a minimum contrast of 1 is allowed, for a stable result the symbols should have a minimum<br />

contrast of 10 between foreground and background.<br />

PDF417:<br />

• For a stable result, the minimum width of the modules should not fall below 3 pixels.<br />

• At the border of the symbol, there should be a quiet zone of at least 2 module’s width in each<br />

direction.<br />

• Gaps between the modules are not allowed.<br />

Data Matrix ECC 200:<br />

• For a stable result, the minimum size of the modules should not fall below 4 pixels.<br />

• At the border of the symbol, there should be a quiet zone of at least 1 module’s width in each<br />

direction.<br />

• Gaps between the modules are allowed, but should not exceed 50% of the module’s size.<br />

• Although theoretically allowed, a slant angle of maximum 0.5235 (30 degrees) should not be<br />

exceeded.<br />

QR Code:<br />

• For a stable result, the minimum size of the modules should not fall below 4 pixels.<br />

• At the border of the symbol, there should be a quiet zone of at least 4 module’s width in each<br />

direction.<br />

• Gaps between the modules are allowed, but should not exceed 50% of the module’s size.<br />

• At least two of three position detection patterns have to be visible.<br />

5.3.2 Valid Parameter Ranges<br />

The following list concisely summarizes the value ranges valid for the parameter groups related to the<br />

size and appearance of the individual symbol types. A complete list of parameter names that belong to<br />

each group can be found at the description of the operator set_data_code_2d_param in the Reference<br />

Manual.


5.3.2 Valid Parameter Ranges 41<br />

Symbol Type PDF417 Data Matrix ECC 200 QR Code<br />

Symbol Size<br />

- Columns 1 - 30 codewords 10 - 144 modules, even 21 - 177 modules<br />

- Rows 3 - 90 modules 8 - 144 modules, even 21 - 177 modules<br />

Symbol Shape — rectangle, square, any —<br />

Model Type — — 1, 2, any<br />

Version — — 1 - 40<br />

Polarity dark_on_light, dark_on_light, dark_on_light,<br />

light_on_dark, light_on_dark, light_on_dark,<br />

any any any<br />

Mirrored yes, no, any yes, no, any yes, no, any<br />

Minimum Contrast 1 - 100 1 - 100 1 - 100<br />

Module Size — 2 - 200 2 - 200<br />

Module Aspect Ratio 0.5 - 20 — —<br />

Module Gaps no gaps no, small, big no, small, big<br />

Maximum Slant — 0 - 0.7 —<br />

Module Grid — fixed, variable, any —<br />

Minimum Position Patterns — — 2, 3<br />

<strong>Note</strong> that for most parameters the range of values valid for a symbol corresponds to the range of values<br />

checked by the 2D data code reader when using the global parameter settings in enhanced mode (see<br />

section 3.1 on page 8). Exceptions to that rule are<br />

• the minimum contrast for all symbol types (allowed range: 1 - 100, default in enhanced mode:<br />

10),<br />

• the maximum module size for matrix codes (allowed range: 2 - 200, default in enhanced mode:<br />

100),<br />

• the module aspect ratio for PFD417 (allowed range: 0.5 - 20, default in enhanced mode for the<br />

minimum module aspect: 1.0, default in enhanced mode for the maximum module aspect: 10),<br />

• the maximum slant for Data Matrix ECC200 (allowed range: 0 - 0.7, default in enhanced mode:<br />

0.5235).<br />

For a stable result, it is recommended to comply with the value ranges specified for the enhanced parameter<br />

set.<br />

In some cases, a measure of the quality of the symbols is asked for. There are various standards available<br />

that are related to the quality verification of 2D data codes, but their focus differs depending, e.g., on<br />

the way the symbol is applied to a surface. A printed symbol with square modules and no gaps between<br />

the modules demands for a different verification standard than a symbol produced by dot peening. An<br />

overlapping quality standard for all kinds of 2D data codes, independent on their appearance, material,<br />

production process etc., is not yet available. Therefore, <strong>HALCON</strong> does not provide a tool to measure<br />

a symbol’s quality. Nevertheless, if necessary you can use <strong>HALCON</strong> operators to implement tools<br />

following the standards suited best for your application.<br />

Problem Handling


42 <strong>Application</strong> <strong>Note</strong> on 2D Data Codes


Provided Functionality<br />

<strong>HALCON</strong> <strong>Application</strong> <strong>Note</strong><br />

<strong>1D</strong> <strong>Metrology</strong><br />

⊲ Detecting edges and measuring their position and distance along lines and arcs<br />

Typical <strong>Application</strong>s<br />

⊲ Inspect object dimensions<br />

Copyright c○ 2005-2008 by <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>, München, Germany <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>


Overview<br />

With <strong>HALCON</strong>, you can perform highly accurate measurements in <strong>1D</strong> (i.e., measure distances and<br />

angles along lines and arcs), 2D (i.e., measure features like the size and orientation of objects), and<br />

3D (i.e., measure in 3D world coordinates). This <strong>Application</strong> <strong>Note</strong> describes <strong>1D</strong> metrology, a fast and<br />

easy-to-use tool that enables you to measure the dimensions of objects with high accuracy.<br />

A first example and a short characterization of the various methods is given in section 1 on page 4. A<br />

description of how to create a measure object as well as the basic concepts of <strong>1D</strong> metrology can be found<br />

in section 2 on page 5. Then, the methods to perform <strong>1D</strong> metrology are described in detail.<br />

For more complex measurement tasks, it might be necessary to control the selection of the edges. To<br />

do this, the measure object can be extended to a fuzzy measure object (section 4 on page 25) where the<br />

selection of the edges is controlled by fuzzy membership functions.<br />

Unless specified otherwise, the HDevelop example programs can be found in the subdirectory<br />

1d_metrology of the directory <strong>HALCON</strong>ROOT \examples\application_guide.<br />

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in<br />

any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written<br />

permission of the publisher.<br />

Edition 1 July 2005 (<strong>HALCON</strong> 7.1)<br />

Edition 1a December 2006 (<strong>HALCON</strong> 7.1.2)<br />

Microsoft, Windows, Windows NT, Windows 2000, and Windows XP are either trademarks or registered trademarks<br />

of Microsoft Corporation.<br />

All other nationally and internationally recognized trademarks and tradenames are hereby recognized.<br />

More information about <strong>HALCON</strong> can be found at:<br />

http://www.halcon.com/


Contents<br />

1 First Example and Overview 4<br />

2 The Basics of Measure Objects 5<br />

2.1 The Process of <strong>1D</strong> Edge Extraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />

2.2 Creating a Measure Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

3 Using the Measure Object 10<br />

3.1 The Position of Edges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

3.2 The Position of Edge Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

3.3 The Position of Points With a Particular Gray Value . . . . . . . . . . . . . . . . . . . . 15<br />

3.4 The Gray Projection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

3.5 Measuring in World Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

3.6 Compensate for Radial Image Distortions . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

3.7 Changing the Position and Orientation of the Measure Object . . . . . . . . . . . . . . . 21<br />

3.8 Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.9 Destroying the Measure Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

4 Advanced Measuring: The Fuzzy Measure Object 25<br />

4.1 A First Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

4.2 Controlling the Selection of Edges and Edge Pairs . . . . . . . . . . . . . . . . . . . . . 27<br />

4.3 Creating the Fuzzy Measure Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

4.4 Using the Standard Measure Object Functionality . . . . . . . . . . . . . . . . . . . . . 36<br />

A Slanted Edges 37<br />

B Examples for Fuzzy Membership Functions 42<br />

B.1 Set Type contrast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />

B.2 Set Type position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

B.3 Set Type position_pair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

B.4 Set Type size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

B.5 Set Type gray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

B.6 Set Type position_pair combined with size . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

C Definition of the Geometric Mean 62<br />

3


4 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

1 First Example and Overview<br />

The example program hdevelop\measure_switch.dev is a simple application where the width of and<br />

the distance between the pins of a switch (see figure 1a) must be measured. This task can easily be solved<br />

by <strong>1D</strong> metrology because positions and distances are measured along a line.<br />

(a) (b)<br />

Figure 1: Image of a switch: (a) The width of the pins and their distance from each other must be measured;<br />

(b) the rectangular ROI within which the edges are determined.<br />

First, a measure object is created by specifying a rectangle that lies over the pins as depicted in figure 1b.<br />

The operator gen_measure_rectangle2 returns a handle to the created measure object.<br />

gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height,<br />

Interpolation, MeasureHandle)<br />

To perform the measurement, you pass this handle to the measuring operators. To inspect the switch,<br />

we use measure_pairs, which extracts the edge pairs corresponding to the pins and returns their width<br />

(distance between the edges of a pair, IntraDistance) and their distance (distance between edges of<br />

subsequent pairs, InterDistance).<br />

measure_pairs (Image, MeasureHandle, Sigma, Threshold, Transition, Select,<br />

RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst,<br />

RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond,<br />

IntraDistance, InterDistance)<br />

The resulting edges are displayed in figure 2 together with the measured width of the pins and the distance<br />

between them.<br />

The following sections take a closer look at these steps and explain how to solve more complex tasks:<br />

Section 2 describes the basics of measuring, i.e., how the edges are determined (section 2.1 on page 6)<br />

and how to create measure objects for rectangular and circular ROIs (section 2.2 on page 9).<br />

Section 3 on page 10 explains how to use the measure object to extract edges (section 3.1 on page 11),<br />

edge pairs (section 3.2 on page 13), points that have a particular gray value (section 3.3 on page 15), and<br />

the gray value profile (section 3.4 on page 16).


2 The Basics of Measure Objects 5<br />

Figure 2: The result of measuring the width of and the distance between the pins of a switch.<br />

Often, it is necessary to determine the dimensions of an object in world coordinates, e.g., in µm. The<br />

transformation of the results of a measure object into world coordinates is described in section 3.5 on<br />

page 20.<br />

Section 3.7 on page 21 describes how to change the position and orientation of measure objects. Some<br />

tips and tricks for the use of measure objects are given in section 3.8 on page 21.<br />

Section 4 on page 25 shows how to solve more complex measurement tasks, e.g., if the object shows<br />

different gray levels or if parts of the image are disturbed by reflections or by shadows that are cast on<br />

the object. For this purpose, it is possible to introduce special weighting functions to suppress unwanted<br />

edges. This extension is called fuzzy measure object.<br />

2 The Basics of Measure Objects<br />

The main idea behind the measure object is to extract edges that run approximately perpendicular to<br />

the line or arc of measurement. This process is described in section 2.1. It is important to understand<br />

this process because you influence it with parameters both when creating the measure object and when<br />

applying it. Section 2.2 on page 9 shows how to specify the shape of the measuring ROI. Please note that<br />

in contrast to other <strong>HALCON</strong> methods, measuring ROIs are not created using reduce_domain, but by<br />

specifying their dimensions when creating a measure object. A measure object can be used to determine<br />

the position of straight edges that run approximately perpendicular to the given ROI.<br />

Basics


6 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

2.1 The Process of <strong>1D</strong> Edge Extraction<br />

<strong>HALCON</strong> determines the position of <strong>1D</strong> edges by the following approach: First, equidistant lines of<br />

projection are constructed perpendicular to the line or arc of measurement (also called profile line) with<br />

a length equal to the width of the ROI (figure 3).<br />

Start<br />

Profile Line<br />

1 Pixel<br />

ROI<br />

End<br />

(a) (b)<br />

End<br />

ROI<br />

Profile Line<br />

Figure 3: Lines of projection for a (a) rectangular ROI and (b) circular ROI.<br />

Then, the mean gray value along each line of projection is calculated. The sequence of these mean values<br />

is called the profile. If the lines of projection are not oriented horizontally or vertically, the pixel<br />

values along them must be interpolated. You can select the interpolation mode with the parameter Interpolation<br />

of the operators for the creation of measure objects (e.g., gen_measure_rectangle2,<br />

see section 1 on page 4). If Interpolation = ’nearest_neighbor’, the gray values in the measurement<br />

are obtained from the gray values of the closest pixel, i.e., by constant interpolation. This is the fastest<br />

method. However, the geometric accuracy is slightly lower in this mode. For Interpolation = ’bilinear’,<br />

bilinear interpolation is used, while for Interpolation = ’bicubic’, bicubic interpolation is used.<br />

The bicubic interpolation yields the most accurate results. However, it is the slowest method.<br />

The length of the lines of projection, i.e., the width of the ROI, defines the degree of averaging in the<br />

direction perpendicular to the profile line. The thick lines in figure 4c and d show the profiles for the two<br />

ROIs displayed in figure 4a and b. It can be seen that the profile that corresponds to the wider ROI is<br />

less noisy. Therefore, as long as the edges run approximately perpendicular to the profile line, the ROI<br />

should be chosen as wide as possible. If the edges do not run perpendicular to the profile line, the width<br />

of the ROI must be chosen smaller to allow the detection of edges. <strong>Note</strong> that in this case, the profile will<br />

contain more noise. Consequently, the edges will be determined less accurate (see appendix A on page<br />

37).<br />

The profile is then smoothed with a Gaussian smoothing filter (see the thick lines in figure 4e and f),<br />

whose standard deviation is specified with the parameter Sigma of the measuring operators (e.g., measure_pairs).<br />

Now, the first derivative of the smoothed profile is calculated (thin lines in figure 4e-f).<br />

<strong>Note</strong> that the amplitude of the derivative is scaled with a factor √ 2π · Sigma. The subpixel precise positions<br />

of all local extrema of the first derivative are edge candidates. In figure 5a on page 8, these edge<br />

candidates are indicated by vectors pointing from the respective position of the derivative (thin line) to<br />

the smoothed gray value profile (thick line). Only those edge candidates that have an absolute value of<br />

1 Pixel<br />

Start


gray value<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

(a) ROI of Width=2 (b) ROI of Width=20<br />

0<br />

0 20 40 60 80 100 120<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

profile line<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

2.1 The Process of <strong>1D</strong> Edge Extraction 7<br />

0<br />

0 20 40 60 80 100 120<br />

profile line<br />

(c) Width=2, no smoothing (d) Width=20, no smoothing<br />

-150<br />

0 20 40 60 80 100 120<br />

profile line<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

-150<br />

0 20 40 60 80 100 120<br />

profile line<br />

(e) Width=2, Sigma=0.9 (f) Width=20, Sigma=0.9<br />

Figure 4: Profiles (thick lines) and derivatives (thin lines) of the profiles for two ROIs with different width<br />

with and without smoothing the profiles (the orientation of the ROIs is from top left down to the<br />

right).<br />

the first derivative larger than a given Threshold (another parameter of the measuring operators) are<br />

considered as edges in the image (see figure 5b on page 8).<br />

For each edge, the position of its intersection with the profile line is returned. Figure 6 shows the detected<br />

edges, displayed by straight lines with a length similar to the width of the ROI.<br />

Basics


8 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

-150<br />

0 20 40 60 80 100 120<br />

profile line<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

-150<br />

0 20 40 60 80 100 120<br />

(a) (b)<br />

profile line<br />

Figure 5: Positions of (a) edge candidates and (b) edges along the profile. The profile was derived from<br />

the 20 pixel wide ROI, it was smoothed with Sigma = 0.9.<br />

Figure 6: Edges detected from the 20 pixel wide ROI. The profile was smoothed with Sigma = 0.9 and<br />

thresholded with a Threshold of 12.<br />

<strong>Note</strong> that the above described approach for the extraction of <strong>1D</strong> edges from a profile differs significantly<br />

from the 2D edge extraction performed, e.g., with the operator edges_sub_pix (compare figure 7 on<br />

page 9). In the case of the <strong>1D</strong> edge extraction, only the positions of the intersections of the edges with<br />

the profile line are determined as described above whereas the 2D edge extraction returns the complete<br />

edges as contours. If the edges are straight and run approximately perpendicular to the profile line, the<br />

results of the <strong>1D</strong> edge extraction are similar to the intersection of the 2D edges with the profile line. The<br />

more the edges are curved or not perpendicular to the profile line, the more different the results of the<br />

two approaches will be. An example where the results of the two approaches are completely different is<br />

given in section 3.1 on page 11.<br />

Keep in mind that measure objects are designed to measure the position of straight edges that run approximately<br />

perpendicular to the profile line. This means that measure objects are not suited to measure the<br />

position of, e.g., curved edges. In those cases, the measure position will typically not coincide with the<br />

intersection of the gray value edge with the profile line. An example for such a case is given in figure 8.<br />

Here, the edges are curved, which leads to wrong measurement results. This effect will be reduced if the


Figure 7: Edges detected in 2D with the operator edges_sub_pix .<br />

2.2 Creating a Measure Object 9<br />

Figure 8: An example for an incorrect use of the measure object. The ROI is oriented from left to right.<br />

width of the ROI is chosen smaller.<br />

2.2 Creating a Measure Object<br />

Measure objects can be created with two different shapes: Rotated rectangles and circular arcs. They are<br />

created with the operators gen_measure_rectangle2 or gen_measure_arc.<br />

To create a rectangular measure object, you use the operator gen_measure_rectangle2:<br />

gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height,<br />

Interpolation, MeasureHandle)<br />

A rotated rectangle is defined by its center (Row, Column), its orientation Phi, and its half edge lengths<br />

Length1 and Length2 (see figure 9). The parameter Phi is given in radians in mathematically positive<br />

sense. All the other parameters are given in pixels.<br />

To create a circular measure object, you use the operator gen_measure_arc:<br />

Basics


10 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

Start<br />

Length2<br />

Profile Line<br />

Length1<br />

ROI<br />

Phi<br />

Center(Row,Column)<br />

Figure 9: Rectangular region of interest (ROI).<br />

gen_measure_arc (CenterRow, CenterCol, Radius, AngleStart,<br />

AngleExtent, AnnulusRadius, Width, Height,<br />

Interpolation, MeasureHandle)<br />

The circular arc is defined by the following parameters (see figure 10 on page 11): The position and<br />

size are defined by the center (CenterRow, CenterColumn) and the radius (Radius). The segment<br />

of the circle is defined by its start angle (AngleStart) and the angular extent (AngleExtent). The<br />

width of the circular ROI is defined by the annulus radius (AnnulusRadius). Again, all parameters are<br />

given in pixels, except for the angles (AngleStart and AngleExtent), which are given in radians in<br />

mathematically positive sense.<br />

The first parameters of both operators for the creation of measure objects define the position, size, and<br />

orientation of the respective ROI. The parameters Width and Height are the size of the images, on which<br />

the measure can be applied. The parameter Interpolation sets the interpolation mode (see section 2.1<br />

on page 6).<br />

As a result, the operators return a handle for the newly created measure object (MeasureHandle), which<br />

can then be used to specify the measure object, e.g., in calls to the operator measure_pos. <strong>Note</strong> that if<br />

you use <strong>HALCON</strong>’s COM or C++ interface and call the operator via the classes HMeasureX or HMeasure,<br />

no handle is returned because the instance of the class itself acts as your handle.<br />

3 Using the Measure Object<br />

For different tasks, depending on your application, you can measure the position of individual edges and<br />

the distance between them (see section 3.1). If the object to inspect has two edges (like the edge pairs in<br />

section 1 on page 4), you can let <strong>HALCON</strong> group the edges to edge pairs (see section 3.2 on page 13).<br />

End


End<br />

Annulus<br />

Radius<br />

ROI<br />

Radius<br />

Profile Line<br />

AngleExtent<br />

AngleStart<br />

Center(CenterRow,CenterColumn)<br />

Figure 10: Circular region of interest (ROI).<br />

3.1 The Position of Edges 11<br />

Furthermore, the position of points on the profile that have a particular gray value can be determined<br />

(section 3.3 on page 15). It is also possible to access the gray value profile itself (section 3.4 on page<br />

16).<br />

Often, it is necessary to determine the dimensions of an object in world coordinates, e.g., in µm. The<br />

transformation of the results of a measure object into world coordinates is described in section 3.5 on<br />

page 20.<br />

Section 3.7 on page 21 describes how to change the position and orientation of measure objects. Some<br />

tips and tricks for the use of measure objects are given in section 3.8 on page 21.<br />

3.1 The Position of Edges<br />

You measure the position of the individual edges with the operator measure_pos. The edges are determined<br />

with the approach described in section 2.1 on page 6. With this approach, it is also possible to<br />

extract edges that appear only if the image is smoothed in a direction perpendicular to the ROI.<br />

In the example program hdevelop\measure_ic_leads.dev, we use this operator to measure the<br />

length of the leads of the IC that is displayed in figure 11a. At a first glance, it is not clear how to<br />

solve this task because the individual leads are not enclosed by two edges. However, we can exploit the<br />

averaging perpendicular to the profile line: If the ROI encloses multiple leads, as depicted in figure 11a,<br />

the averaged gray value of the leads is darker than the background, but lighter than the body of the IC<br />

(see figure 11b and figure 11c).<br />

Let’s take a look at the corresponding code. First, a measure object is created for the ROI at the top of<br />

the image. The ROI must have a width such that it contains several leads.<br />

Start<br />

Measuring


12 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

(a)<br />

gray value<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

-150<br />

0 20 40 60 80 100<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

profile line<br />

(b)<br />

-150<br />

0 20 40 60 80 100<br />

profile line<br />

(c)<br />

Figure 11: (a) Image of an IC with the ROIs that are used for the determination of the lead length; (b) and<br />

(c) show the profile (thick line) and its derivation (thin line) for (b) the ROI at the top and (c) the<br />

ROI at the bottom of the image in (a). The ROIs are oriented from the top to the bottom of the<br />

image.<br />

gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height,<br />

Interpolation, MeasureHandle)<br />

Now, all edges that are perpendicular to the ROI are extracted.<br />

measure_pos (Image, MeasureHandle, Sigma, Threshold, Transition, Select,<br />

RowEdge, ColumnEdge, Amplitude, Distance)<br />

The resulting edges enclose the leads (see figure 12). Their distance is returned in the parameter Distance.<br />

In the example, only two edges are returned. Therefore, the parameter Distance contains only<br />

one element, which is the length of the leads at the top of the image. To determine the length of the leads<br />

at the bottom of the image, the same measurements are carried out within the second ROI.<br />

The parameter Sigma determines the degree of smoothing of the profile along the profile line. The<br />

parameter Threshold defines the threshold that is applied to the derivative of the profile for the selection<br />

of edges. Both parameters are described in section 2.1 on page 6.<br />

The parameter Transition can be used to select edges with a particular transition. If Transition is


Figure 12: The result of the determination of the lead length.<br />

3.2 The Position of Edge Pairs 13<br />

set to ’negative’, only edges at which the gray values change from light to dark will be returned. In<br />

the current example, the two edges in the ROI at the top of the image have a negative transition. If<br />

Transition is set to ’positive’, only edges at which the gray values change from dark to light (e.g., the<br />

two edges in the ROI at the bottom of the image) will be returned. To determine all edges, Transition<br />

must be set to ’all’ in this application.<br />

The parameter Select can be used to restrict the result to the ’first’ or ’last’ edge. In the current example,<br />

Select must be set to ’all’.<br />

Besides the distance of the edges, measure_pos also returns their position in the output parameters<br />

RowEdge and ColumnEdge as well as their amplitude (Amplitude). In the example, the position is used<br />

to visualize the edges:<br />

disp_line (WindowHandle, RowEdge, ColumnEdge-Length2, RowEdge,<br />

ColumnEdge+Length2)<br />

3.2 The Position of Edge Pairs<br />

As already noted in section 1 on page 4, whenever the object to measure is enclosed by two edges, you<br />

can use the operator measure_pairs, which groups edges to edge pairs. In the following example, we<br />

use this operator to determine the width of the leads from the image displayed in figure 11a on page 12.<br />

First, a suitable ROI must be defined. Because we want to determine the edges of the individual leads,<br />

the ROI must be oriented perpendicular to the leads (see figure 13a). Here, it is oriented from the left to<br />

the right. With this ROI, a measure object is created as described in section 2 on page 5.<br />

Now, all edge pairs that enclose dark image regions are extracted<br />

(hdevelop\measure_ic_leads.dev):<br />

Measuring


14 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

(a) (b)<br />

Figure 13: (a) The ROI for and (b) a part of the result of the determination of the lead width.<br />

measure_pairs (Image, MeasureHandle, Sigma, Threshold, Transition, Select,<br />

RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst,<br />

RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond,<br />

IntraDistance, InterDistance)<br />

The resulting edges are displayed in figure 13b, which shows only a part of the image.<br />

The parameters of measure_pairs are partly identical to the ones of measure_pos (see section 3.1 on<br />

page 11): Sigma determines the degree of smoothing of the profile. The parameter Threshold defines<br />

the threshold that is applied to the derivative of the profile for the selection of edges. Both parameters<br />

are described in section 2.1 on page 6.<br />

The parameter Transition can be used to select edge pairs with a particular transition. If Transition<br />

is set to ’negative’, as in the example, only edge pairs where the first edge has a negative transition<br />

and the second edge has a positive transition, i.e., edge pairs that enclose a dark image region will be<br />

returned. If Transition is set to ’positive’, the behavior is exactly opposite, i.e., edge pairs that enclose<br />

a bright image region will be returned. If Transition is set to ’all’, the transition is determined by the<br />

first edge. I.e., dependent on the positioning of the measure object, edge pairs with a light-dark-light<br />

transition or edge pairs with a dark-light-dark transition are returned. This is suited, e.g., to measure<br />

objects with different brightness relative to the background.<br />

If more than one consecutive edge with the same transition is found, only the first one will be used<br />

as a pair element. This behavior may cause problems in applications in which the Threshold cannot<br />

be selected high enough to suppress consecutive edges of the same transition. This problem can be<br />

demonstrated, e.g., by defining the ROI in the example program hdevelop\measure_switch.dev (see<br />

section 1 on page 4) the other way round, i.e., from bottom right to top left. Then, the first edge with a<br />

negative transition corresponds to the shadow of the pin and the edge that corresponds to the pin itself is<br />

not used as a pair element (see figure 14a).


3.3 The Position of Points With a Particular Gray Value 15<br />

For these applications, an advanced pairing mode exists that only selects the strongest edges of a sequence<br />

of consecutive edges of the same transition. This mode is selected by appending ’_strongest’<br />

to any of the above modes for Transition, e.g., ’negative_strongest’. Figure 14b shows the result of<br />

setting Transition to ’negative_strongest’.<br />

(a) (b)<br />

Figure 14: The results of measuring the width of and the distance between the pins of a switch if the<br />

ROI is defined from bottom right to top left: (a) Transition = ’negative’, (b) Transition =<br />

’negative_strongest’.<br />

The parameter Select can be used to restrict the result to the ’first’ or ’last’ edge pair. To determine all<br />

edge pairs, Select must be set to ’all’.<br />

The operator measure_pairs returns the coordinates of the edge positions separately for the first and<br />

the second edge of each edge pair. The output parameters RowEdgeFirst and ColumnEdgeFirst<br />

contain the coordinates of the first edges of the edge pairs and the parameters RowEdgeSecond and<br />

ColumnEdgeSecond contain the coordinates of the second edges. With this, the center of the pairs can<br />

easily be determined by calculating the mean of the respective first and second edge positions:<br />

RowPairCenter := (RowEdgeFirst+RowEdgeSecond)/2.0<br />

ColumnPairCenter := (ColumnEdgeFirst+ColumnEdgeSecond)/2.0<br />

The output parameters IntraDistance and InterDistance contain the distance between the two<br />

edges of the edge pairs and the distance between the edge pairs.<br />

3.3 The Position of Points With a Particular Gray Value<br />

With the operator measure_thresh, it is also possible to determine the subpixel precise positions where<br />

the gray value profile has a given value. This <strong>1D</strong> thresholding works like the 2D subpixel precise thresholding<br />

operator threshold_sub_pix.<br />

This operator can be useful to extract particular edges in applications where the lighting conditions can<br />

be controlled very accurately. <strong>Note</strong> that the measured position depends heavily on the brightness of the<br />

image, i.e., the measured position will vary if the brightness level of the image changes, e.g., due to<br />

illumination changes.<br />

Measuring


16 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

3.4 The Gray Projection<br />

For applications that require the determination of special <strong>1D</strong> features, it is possible to access the gray<br />

value profile directly via the operator measure_projection. It returns the original, i.e., unsmoothed<br />

gray value profile as a tuple in the output parameter GrayValues. On the profile, points that satisfy a<br />

particular condition can be determined. Then, the pixel coordinates of these points can be calculated.<br />

In the example program hdevelop\measure_caliper.dev, the distances between the pitch lines of a<br />

caliper are determined. The used image (figure 15a) shows the pitch lines as approximately one pixel<br />

wide lines (see, e.g., figure 15b). To determine the line positions in the gray value profile, a <strong>1D</strong> line<br />

extraction is implemented based on the gray value profile.<br />

(a) (b)<br />

Figure 15: (a) The image of a caliper; (b) detail of (a).<br />

First, the measure object is created. It is positioned such that only the longest pitch lines, i.e., those<br />

which indicate full centimeters run through the measuring ROI.<br />

gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height,<br />

’bilinear’, MeasureHandle)<br />

Then, the profile is determined with the operator measure_projection, which returns the profile in the<br />

output parameter GrayValues:<br />

measure_projection (Image, MeasureHandle, GrayValues)<br />

To reduce the noise, the profile must be smoothed because the operator measure_projection returns<br />

the original, i.e., unsmoothed profile.


Sigma := 0.3<br />

create_funct_1d_array (GrayValues, Function)<br />

smooth_funct_1d_gauss (Function, Sigma, SmoothedFunction)<br />

The smoothed profile is displayed in figure 16.<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

0 50 100 150 200 250 300 350 400<br />

profile line<br />

Figure 16: The smoothed profile.<br />

3.4 The Gray Projection 17<br />

To detect line points on the profile, it is sufficient to determine the points where the first derivative of the<br />

smoothed profile vanishes. The first derivative of the smoothed profile is determined with the operator<br />

derivate_funct_1d with the control parameter Mode set to ’first’; the points where the first derivative<br />

vanishes are determined with the operator zero_crossings_funct_1d:<br />

derivate_funct_1d (SmoothedFunction, ’first’, FirstDerivative)<br />

zero_crossings_funct_1d (FirstDerivative, ZeroCrossings)<br />

The first derivative of the smoothed profile is displayed in figure 17a.<br />

first derivative<br />

15<br />

10<br />

5<br />

0<br />

-5<br />

-10<br />

-15<br />

0 50 100 150 200 250 300 350 400<br />

profile line<br />

second derivative<br />

30<br />

20<br />

10<br />

0<br />

-10<br />

-20<br />

-30<br />

0 50 100 150 200 250 300 350 400<br />

(a) (b)<br />

profile line<br />

Figure 17: The (a) first and (b) second derivative of the smoothed profile.<br />

Because of noise, the first derivative shows many more zero crossings than just in the middle of each line,<br />

i.e., between the large negative and positive spikes in figure 17a. We can select the desired zero crossings<br />

Measuring


18 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

by looking at the magnitude of the second derivative: Bright lines on a dark background will have a<br />

negative second derivative while dark lines on a bright background will have a positive second derivative.<br />

The second derivative of the smoothed profile is determined with the operator derivate_funct_1d with<br />

the control parameter Mode set to ’second’:<br />

derivate_funct_1d (SmoothedFunction, ’second’, SecondDerivative)<br />

The second derivative of the smoothed profile is displayed in figure 17b on page 17.<br />

In our case, the pitch lines appear as dark lines on a bright background. Therefore, we have to select<br />

those line positions, where the second derivative has a large positive value: For each line position, i.e.,<br />

zero crossing of the first derivative, the value of the second derivative is determined with the operator<br />

get_y_value_funct_1d. If this value is larger than a user defined threshold, the line position will be<br />

stored in a tuple that holds the positions of all salient lines.<br />

MinimumMagnitudeOfSecondDerivative := 8<br />

PositionOfSalientLine := []<br />

for i := 0 to |ZeroCrossings|-1 by 1<br />

get_y_value_funct_1d (SecondDerivative, ZeroCrossings[i], ’constant’,<br />

Y)<br />

if (Y > MinimumMagnitudeOfSecondDerivative)<br />

PositionOfSalientLine := [PositionOfSalientLine,ZeroCrossings[i]]<br />

endif<br />

endfor<br />

Finally, the positions of the lines on the profile must be transformed into pixel coordinates because<br />

measure_projection returns just the gray value profile along the profile line. <strong>Note</strong> that internally, the<br />

coordinates of the center of the measuring ROI are rounded and the length of the measuring ROI is set<br />

to the largest integer value that is smaller or equal to the given value.<br />

The pixel coordinates of the start point of the profile line can be determined as follows (see figure 18):<br />

RowStart = ⌊(Row + 0.5)⌋ + ⌊Length1⌋ · sin(Phi)<br />

ColStart = ⌊(Column + 0.5)⌋ − ⌊Length1⌋ · cos(Phi)<br />

This can be realized by the following lines of code:<br />

RowStart := floor(Row+0.5)+floor(Length1)*sin(Phi)<br />

ColStart := floor(Column+0.5)-floor(Length1)*cos(Phi)<br />

Now, the pixel coordinates of the positions of the salient lines on the profile can be determined as follows:<br />

RowLine = RowStart − PositionOfSalientLine · sin(Phi)<br />

ColLine = ColStart + PositionOfSalientLine · cos(Phi)<br />

In HDevelop, this can be expressed by the following lines of code:<br />

RowLine := RowStart-PositionOfSalientLine*sin(Phi)<br />

ColLine := ColStart+PositionOfSalientLine*cos(Phi)<br />

Figure 19 shows the positions of the determined lines.


Start<br />

Position<br />

of line<br />

Length1<br />

ROI<br />

Profile Line<br />

Phi<br />

Center(Row,Column)<br />

End<br />

Figure 18: The measuring ROI with the position of a point on the profile.<br />

(a) (b)<br />

Figure 19: (a) The determined lines; (b) detail of (a).<br />

3.4 The Gray Projection 19<br />

Measuring


20 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

In the following section, the pixel coordinates of the pitch lines and the distance between them are<br />

transformed into world coordinates.<br />

If you are using a circular measure object, which has been created with the operator gen_measure_arc,<br />

the following formulae must be used to determine the pixel coordinates RowPoint and ColPoint of a<br />

point on the profile:<br />

RowPoint = ⌊(CenterRow + 0.5)⌋ − Radius · sin(AngleStart + Position)<br />

ColPoint = ⌊(CenterColumn + 0.5)⌋ + Radius · cos(AngleStart + Position)<br />

Here, Position is the position of the point on the profile and CenterRow, CenterColumn, Radius,<br />

and AngleStart are the parameters used for the creation of the measure object with the operator<br />

gen_measure_arc.<br />

3.5 Measuring in World Coordinates<br />

In many applications, the dimensions of the measured object must be determined in world coordinates,<br />

e.g., in µm. This can either be achieved by transforming the original measurement results into world<br />

coordinates (see <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision, section 3.2 on page 44) or, by first rectifying<br />

the image and applying the measurement in the transformed image (see <strong>Application</strong> <strong>Note</strong> on 3D Machine<br />

Vision, section 3.3 on page 49). As a prerequisite, the camera must be calibrated (<strong>Application</strong> <strong>Note</strong> on<br />

3D Machine Vision, section 3.1 on page 29).<br />

In the example program hdevelop\measure_caliper.dev, first the positions of the pitch lines of a<br />

caliper are determined (see section 3.4 on page 16). These positions are now transformed into world<br />

coordinates with the operator image_points_to_world_plane:<br />

image_points_to_world_plane (CamParam, WorldPose, RowLine, ColLine, ’mm’,<br />

X, Y)<br />

The parameter CamParam contains the camera parameters and the parameter WorldPose the position and<br />

orientation of the world plane in which the measurement takes place. Both parameters can be determined<br />

during the camera calibration (<strong>Application</strong> <strong>Note</strong> on 3D Machine Vision, section 3.1 on page 29). In the<br />

current example program, they are assumed to be known.<br />

Now, the distance between the pitch lines can be calculated with the operator distance_pp:<br />

Num := |X|<br />

distance_pp (X[0:Num-2], Y[0:Num-2], X[1:Num-1], Y[1:Num-1], Distance)<br />

The resulting distances are displayed in figure 20.<br />

3.6 Compensate for Radial Image Distortions<br />

If the image suffers from heavy radial distortions, a correction of the image coordinates or a rectification<br />

of the image will be necessary.<br />

A detailed description of how to correct the image coordinates can be found in <strong>Application</strong> <strong>Note</strong> on 3D<br />

Machine Vision, section 3.2.6 on page 48. The description of how to rectify images can be found in the<br />

<strong>Application</strong> <strong>Note</strong> on 3D Machine Vision, section 3.3.2 on page 55.


3.7 Changing the Position and Orientation of the Measure Object 21<br />

Figure 20: The distances between the pitch lines in world coordinates.<br />

3.7 Changing the Position and Orientation of the Measure Object<br />

Often, the position of the objects to be measured varies from image to image. In this case, the ROI of the<br />

measure must be adapted accordingly. This process is also called alignment.<br />

The position and orientation of the object to be measured can be determined, e.g., with shape-based<br />

matching. For a detailed description of shape-based matching, please refer to the <strong>Application</strong> <strong>Note</strong><br />

on Shape-Based Matching. This manual also contains an example for aligning a measure ROI (see<br />

<strong>Application</strong> <strong>Note</strong> on Shape-Based Matching, section 4.3.4 on page 36).<br />

If only the position of the measure ROI must be changed, the operator translate_measure can be<br />

used. If also the orientation must be adapted as in the above mentioned example in the <strong>Application</strong> <strong>Note</strong><br />

on Shape-Based Matching, it is necessary to transform the parameters that define the measure ROI and<br />

to create a new measure object with these parameters.<br />

3.8 Tips and Tricks<br />

3.8.1 Distances for Circular ROIs<br />

There are multiple representations for the distance between two edges that are determined with a measure<br />

object that is based on a circular ROI (see figure 21):<br />

Measuring


22 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

• arc length,<br />

• linear distance, and<br />

• angular distance.<br />

End<br />

ROI<br />

Radius<br />

Second edge<br />

Arc length<br />

Linear distance<br />

Angular distance<br />

First edge<br />

Start<br />

Center(CenterRow,CenterColumn)<br />

Figure 21: Distances for circular ROIs.<br />

Measure objects based on a circular ROI return the distances as arc lengths.<br />

The example program hdevelop\measure_ring.dev shows that it is very easy to transform the measurements<br />

into another representation. In this example, the size of the cogs of a cogwheel must be<br />

measured (see figure 22).<br />

First, a measure object is created based on a circular ROI:<br />

gen_measure_arc (CenterRow, CenterCol, Radius, AngleStart,<br />

AngleExtent, AnnulusRadius, Width, Height,<br />

Interpolation, MeasureHandle)<br />

Then, the edges of the cogs are determined with the operator measure_pairs:<br />

measure_pairs (Image, MeasureHandle, Sigma, Threshold, Transition,<br />

Select, RowEdgeFirst, ColumnEdgeFirst,<br />

AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond,<br />

AmplitudeSecond, IntraDistance, InterDistance)<br />

The size of the cogs, i.e., the distance between the edges of the edge pairs is returned in the output<br />

parameter ’IntraDistance’ as arc length.<br />

The linear distance can be calculated from the coordinates of the edges with the operator distance_pp:


3.8.2 ROIs that lie partially outside the image 23<br />

Figure 22: The size of the cogs of the ring in the upper left corner of the image given in different representations.<br />

distance_pp (RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond,<br />

ColumnEdgeSecond, LinearDistance)<br />

The angular distance can be derived from the arc lengths as follows:<br />

AngularDistance =<br />

Arc length<br />

Radius<br />

which is implemented in the HDevelop example program as follows:<br />

AngularDistance := deg(IntraDistance/Radius)<br />

<strong>Note</strong> that here the angular distance is determined in degrees.<br />

3.8.2 ROIs that lie partially outside the image<br />

Gray value information exists only for positions on the profile line where at least a part of the respective<br />

line of projection (see section 2.1 on page 6) lies inside the image. If parts of an ROI lie outside the<br />

image, the edges inside the image and the distances between them will still be determined correctly.<br />

The example presented in figure 23 demonstrates such a case. Here, the edges of a Siemens star must be<br />

determined with a measure object centered at the center of the Siemens star. In figure 23a, the image as<br />

well as the outline of the ROI are shown. The upper part of the ROI lies outside the image. The distances<br />

between the edges as returned by the measure object are displayed in figure 23b.<br />

Measuring


24 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

(a) (b)<br />

Figure 23: Image of a Siemens star: (a) The circular ROI lies partially outside the image; (b) the measured<br />

distances between the edges.<br />

<strong>Note</strong> that at positions where no gray value information is available, the profile contains zeros. Figure 24<br />

shows the gray value profile determined with the operator measure_projection from the measure<br />

object that was created with the above described circular ROI (see figure 23a).<br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

0 100 200 300 400 500 600 700<br />

profile line<br />

Figure 24: The gray value profile from the circular ROI that lies partially outside the image.


3.8.3 Accuracy vs. Speed<br />

3.8.3 Accuracy vs. Speed 25<br />

By default, the averaging of gray values (see section 2.1 on page 6) is performed using fixed point<br />

arithmetic, to achieve maximum speed. You can trade some of the speed against accuracy by setting the<br />

system parameter ’int_zooming’ to ’false’ with the operator set_system. Then the internal calculations<br />

are performed using floating point arithmetic. <strong>Note</strong> that the gain in accuracy is minimal.<br />

See also the description of the parameter Interpolation at section 2.1 on page 6.<br />

3.8.4 Image Type<br />

Measure objects can only be applied to images of type ’byte’ and ’uint2’.<br />

<strong>Note</strong> that if a multi-channel image is passed to the measuring operators (e.g., measure_pos), only the<br />

first channel of the image will be used.<br />

3.9 Destroying the Measure Object<br />

If the measure object is not longer needed in the program, it should be destroyed with the operator<br />

close_measure:<br />

close_measure (MeasureHandle)<br />

This deletes the measure object and frees all of the associated memory.<br />

4 Advanced Measuring: The Fuzzy Measure Object<br />

Some applications require that the selection of the edges or edge pairs can be controlled in more detail.<br />

With the standard measure object (see above), edges or edge pairs can be selected only based on their<br />

contrast and transition. With a fuzzy measure object it is possible to select edges also based on their<br />

contrast and position. The selection of edge pairs can be additionally controlled based on their position<br />

and size, as well as based on the gray value between the two edges of the pair. The name fuzzy measure<br />

object does not mean that the measurements are “fuzzy”; it comes from the so-called “fuzzy membership<br />

functions” that control the selection of edges (see section 4.2.2 on page 30).<br />

In the following section, a first example demonstrates how to create and use a fuzzy measure object. The<br />

features that can be used to control the selection of edges and edge pairs are described in section 4.2 on<br />

page 27 as well as the fuzzy membership functions, which are used to formalize the desired constraints.<br />

Finally, section 4.3 on page 32 shows how to create a fuzzy measure object from a standard measure<br />

object and one or more fuzzy membership functions.<br />

4.1 A First Example<br />

The fuzzy measure object is an extension to the standard measure object. It allows to control the selection<br />

of edges by specifying weighting functions.<br />

Fuzzy Measure


26 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

The example program hdevelop\fuzzy_measure_switch.dev shows a possible usage of the fuzzy<br />

measure object. Again, the width of and the distance between the pins of a switch must be measured. In<br />

this case, there are reflections on the middle pin (see figure 25), which will lead to wrong results if the<br />

standard measure object is used (figure 26a).<br />

Figure 25: Image of a switch with reflections on the middle pin.<br />

(a) (b)<br />

Figure 26: The results of measuring the width of and the distance between the pins of the switch with (a)<br />

a standard measure object and (b) a fuzzy measure object .<br />

The selection of edges can be improved if additional information is available. In the example, the pins<br />

are approximately 9 pixels wide. This information can be translated into a fuzzy membership function.<br />

Figure 27 shows this fuzzy membership function. It returns 1.0 for the desired pair size and 0.0 if the<br />

size of the pairs deviates more than two pixels from the desired pair size. The intermediate values are<br />

interpolated linearly (see figure 27). In <strong>HALCON</strong>, this fuzzy membership function is created with the<br />

operator create_funct_1d_pairs:<br />

create_funct_1d_pairs ([7,9,11], [0.0,1.0,0.0], SizeFunction)


membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

4.2 Controlling the Selection of Edges and Edge Pairs 27<br />

5 6 7 8 9 10 11 12 13<br />

feature value<br />

Figure 27: The fuzzy membership function that is used in the current example to describe the constraint<br />

on the pair width.<br />

The standard measure object is transformed into a fuzzy measure object with the operator<br />

set_fuzzy_measure. As parameters, you pass the handle of the standard measure object, the fuzzy<br />

membership function, and the name of the feature to which the fuzzy membership function applies.<br />

SetType := ’size’<br />

set_fuzzy_measure (MeasureHandle, SetType, SizeFunction)<br />

The resulting fuzzy measure object can be used to extract edge pairs that are approximately 9 pixels wide,<br />

with the term “approximately” being defined by the fuzzy membership function.<br />

Then, the fuzzy measure object is applied to extract the desired edge pairs:<br />

Sigma := 0.9<br />

AmpThresh := 12<br />

FuzzyThresh := 0.5<br />

Transition := ’negative’<br />

Select := ’all’<br />

fuzzy_measure_pairs (Image, MeasureHandle, Sigma, AmpThresh, FuzzyThresh,<br />

Transition, RowEdgeFirst, ColumnEdgeFirst,<br />

AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond,<br />

AmplitudeSecond, RowEdgeCenter, ColumnEdgeCenter,<br />

FuzzyScore, IntraDistance, InterDistance)<br />

Internally, the specified fuzzy membership function is used to weight all the possible edge pairs. The<br />

width of each possible edge pair is determined and transformed into a fuzzy value. If this fuzzy value<br />

lies above the user defined threshold FuzzyThresh, the edge pair is accepted, otherwise it is rejected.<br />

The result is displayed in figure 26b on page 26. With this, the width of all pins is measured correctly.<br />

4.2 Controlling the Selection of Edges and Edge Pairs<br />

The selection of edges and edge pairs can be controlled based on various features. Section 4.2.1 gives<br />

an overview over the possible features. The constraints on the feature values are defined with fuzzy<br />

membership functions. A short introduction into the concept of fuzzy logic and how fuzzy membership<br />

functions are created in <strong>HALCON</strong> is given in section 4.2.2 on page 30.<br />

Fuzzy Measure


28 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

4.2.1 Features that Can Be Used to Control the Selection of Edges and Edge Pairs<br />

In the example program hdevelop\fuzzy_measure_switch.dev described above, the selection of<br />

edge pairs has been controlled by the approximately known pair size. There are further features according<br />

to which the edges or edge pairs can be selected. These features are grouped into so-called set types<br />

(parameter SetType of the operators set_fuzzy_measure set_fuzzy_measure_norm_pair).<br />

The set types that describe positions or sizes can be specified either with fuzzy membership functions<br />

that directly describe the constraint on the feature value like the one displayed in figure 27 on page 27<br />

(see section 4.2.2 on page 30) or with normalized fuzzy membership functions, i.e., fuzzy membership<br />

functions that are defined relative to the desired pair width (section 4.3.2 on page 32). The first method<br />

uses the operator set_fuzzy_measure to specify the fuzzy membership function. The second method<br />

uses the operator set_fuzzy_measure_norm_pair, which enables a generalized usage of the fuzzy<br />

membership function because the pair size is set independently of the fuzzy membership function.<br />

The set types that refer to features of edge pairs will only take effect if edge pairs are determined, i.e., if<br />

the operators fuzzy_measure_pairs or fuzzy_measure_pairing are used.<br />

In the following, a list of the possible set types is given. It is possible to use multiple set types. Details<br />

can be found in section 4.3.3 on page 34. <strong>Note</strong> that the subtypes of each set are mutually exclusive, i.e.,<br />

only one subtype of each set can be specified for a fuzzy measure object.<br />

Set Type Subtype Function Type Short Description<br />

Direct Norm.<br />

contrast ’contrast’ • - Evaluates the amplitude of the<br />

edges.<br />

position ’position’ • • Evaluates the signed distance<br />

of the edges to the reference<br />

point of the fuzzy measure object.<br />

The reference point is located<br />

at the start of the profile<br />

line (see figure 9 on page 10 and<br />

figure 10 on page 11).<br />

’position_center’ • • Like ’position’ with the reference<br />

point located at the center<br />

of the profile line.<br />

’position_end’ • • Like ’position’ with the reference<br />

point located at the end of<br />

the profile line.<br />

’position_first_edge’ • • Like ’position’ with the reference<br />

point located at the first<br />

edge.<br />

’position_last_edge’ • • Like ’position’ with the reference<br />

point located at the last<br />

edge.


4.2.1 Features that Can Be Used to Control the Selection of Edges and Edge Pairs 29<br />

Set Type Subtype Function Type Short Description<br />

Direct Norm.<br />

position_pair ’position_pair’ • • Evaluates the signed distance of<br />

(for edge pairs<br />

the edge pairs to the reference<br />

only)<br />

point of the fuzzy measure object.<br />

The position of an edge<br />

pair is defined as the center of<br />

the two edges. The reference<br />

’position_pair_center’ • •<br />

point is located at the start of the<br />

profile line (see figure 9 on page<br />

10 and figure 10 on page 11).<br />

Like ’position_pair’ with the<br />

reference point located at the<br />

center of the profile line.<br />

’position_pair_end’ • • Like ’position_pair’ with the<br />

reference point located at the<br />

end of the profile line.<br />

’position_first_pair’ • • Like ’position_pair’ with the<br />

reference point located at the<br />

position of the first edge pair.<br />

’position_last_pair’ • • Like ’position_pair’ with the<br />

reference point located at the<br />

position of the last edge pair.<br />

size (for edge ’size’ • • Evaluates the size of the edge<br />

pairs only)<br />

pairs, i.e., the distance between<br />

the two edges.<br />

’size_diff’ - • Evaluates the signed difference<br />

between the desired PairSize<br />

and the actual size of the edge<br />

pairs.<br />

’size_abs_diff’ - • Evaluates the absolute difference<br />

between the desired Pair-<br />

Size and the actual size of the<br />

edge pairs.<br />

gray (for edge ’gray’ • - Evaluates the mean gray value<br />

pairs only)<br />

between the two edges of edge<br />

pairs.<br />

<strong>Note</strong> that for the extraction of edge pairs all possible pairs of edges are internally analyzed according<br />

to the specified fuzzy membership functions. If only partial knowledge about the edge pairs to be determined<br />

is specified with the fuzzy membership functions, this will possibly lead to unintuitive results.<br />

For example, if the position of the edge pairs is specified but not their size, some small edge pairs will<br />

possibly be omitted because of a large edge pair that consists of the first edge of the first small edge pair<br />

and the second edge of the last small edge pair and that has a membership value equal to or higher than<br />

that of the small edge pairs (see appendix B.3.1 on page 50). Therefore, all the available knowledge<br />

Fuzzy Measure


30 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

about the edge pairs to be extracted should be specified with fuzzy membership functions. In the above<br />

example, the definition of the desired edge pairs can be made more clear by also specifying the size of<br />

the edge pairs (see appendix B.6 on page 61).<br />

4.2.2 Defining the Constraints on the Feature Values with Fuzzy Membership Functions<br />

The constraints for the selection of edges and edge pairs are defined with fuzzy membership functions.<br />

These functions transform the feature values into membership values. The decision whether an edge or<br />

an edge pair is accepted is made based on these membership values. For this so-called defuzzyfication,<br />

the membership values are compared with a given threshold.<br />

This section describes the concept of fuzzy membership functions and how they are created in <strong>HALCON</strong><br />

as well as the defuzzyfication.<br />

Fuzzy Membership Functions<br />

Fuzzy logic handles the concept of partial truth, i.e., truth values between “completely true” and “completely<br />

false”. A fuzzy set is a set whose elements have degrees of membership. The degree of membership<br />

is defined by the feature value of the element and by the fuzzy membership function, which<br />

transforms the feature value into a membership value, i.e., the degree of membership.<br />

With this, fuzzy logic provides a framework for the representation of knowledge that is afflicted with<br />

uncertainties or can only be described vaguely. This applies often to knowledge that is expressed in<br />

natural language, e.g., “the distance between the two edges of a pair is approximately 9 pixel,” or “the<br />

edges are strong and they are located at the beginning of the profile line.”<br />

For example, a fuzzy membership function for the requirement that the edges must be strong could look<br />

like the one displayed in figure 28a. Here, any edge that has an amplitude of less than 50 will not be part<br />

of the fuzzy set of strong edges. Edges with an amplitude higher than 100 are full members of the fuzzy<br />

set, i.e, they have a membership value of 1.0. Edges with amplitudes between 50 and 100 are partial<br />

members of the fuzzy set, e.g., an edge with an amplitude of 75 will have a membership value of 0.5.<br />

In general, a fuzzy membership function is a mathematical function that defines the degree of an element’s<br />

membership in a fuzzy set.<br />

In <strong>HALCON</strong>, fuzzy membership functions are defined as piecewise linear functions by at least two<br />

pairs of values, sorted in an ascending order by their x value. They are created with the operator create_funct_1d_pairs:<br />

create_funct_1d_pairs (XValues, YValues, FuzzyMembershipFunction)<br />

The x values represent the feature of the edges or edge pairs and must lie within the parameter space of<br />

the set type, i.e., in case of ’contrast’ and ’gray’ features and, e.g., byte images within the range 0.0 ≤ x<br />

≤ 255.0. For ’size’, x has to satisfy 0.0 ≤ x, whereas for ’position’ and ’position_pair’, x can be any real<br />

number. The y values of the fuzzy membership function represent the resulting membership value for the<br />

corresponding feature value and have to satisfy 0.0 ≤ y ≤ 1.0. Outside of the function’s interval, defined<br />

by the smallest and the largest specified x value, the y values of the interval borders are continued with<br />

constant values equal to the closest defined y value.<br />

Therefore, the fuzzy membership function displayed in figure 28a is defined by the following code,<br />

which specifies the coordinates of the two control points of the fuzzy membership function.


membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

4.2.2 Defining the Constraints on the Feature Values with Fuzzy Membership Functions 31<br />

0 50 100 150 200 250<br />

feature value for ’contrast’<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 10 20 30 40 50 60 70 80<br />

feature value for ’position’<br />

Figure 28: Examples for fuzzy membership functions. They can, e.g., be used to select (a) strong edges<br />

or (b) edges at the beginning of the profile line. The dots indicate the points to pass to<br />

create_funct_1d_pairs .<br />

create_funct_1d_pairs ([50,100], [0,1], FuzzyMembershipFunction1)<br />

A fuzzy membership function describing the condition that the edge must be at the beginning of the<br />

profile line could look like the one displayed in figure 28b (assuming that the profile line has a length of<br />

80 pixels). It can be defined as follows:<br />

Length := 80<br />

create_funct_1d_pairs ([Length/8.0, Length/2.0], [1,0],<br />

FuzzyMembershipFunction2)<br />

Further examples for fuzzy membership functions can be found in the appendix B on page 42.<br />

Defuzzyfication<br />

Finally, to decide wether an edge or an edge pair meets the constraint, the membership value must be<br />

“defuzzyfied”. This is done by comparing it with a user-defined fuzzy threshold. If the membership<br />

value lies below this threshold, the edge (pair) will be rejected. Otherwise, it will be accepted.<br />

If, e.g., a fuzzy threshold of 0.5 is assumed as in figure 29, all edges that have a membership value of at<br />

least 0.5 will be accepted. For the fuzzy membership function displayed in figure 29a, these are all edges<br />

with a feature value of at least 75; for the fuzzy membership function of figure 29b, edges will only be<br />

accepted if their feature value is at most 25.<br />

The specification of the fuzzy membership function and the definition of the fuzzy threshold are separated<br />

for fuzzy measure objects. The fuzzy membership function is specified with the operator<br />

set_fuzzy_measure or set_fuzzy_measure_norm_pair, respectively, i.e., during the creation of<br />

the fuzzy measure object (see section 4.3). In contrast, the fuzzy threshold is defined when the fuzzy<br />

measure object is used with one of the operators fuzzy_measure_pos, fuzzy_measure_pairs, or<br />

fuzzy_measure_pairing. This separation between the specification of the fuzzy membership function<br />

and the definition of the fuzzy threshold allows a flexible use of the fuzzy measure object: Often, it<br />

will be sufficient to adjust only the fuzzy threshold to varying imaging conditions.<br />

Fuzzy Measure


32 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 50 100 150 200 250<br />

feature value for ’contrast’<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 10 20 30 40 50 60 70 80<br />

feature value for ’position’<br />

Figure 29: Examples for fuzzy membership functions (thick lines) together with a fuzzy threshold at 0.5<br />

(thin lines).<br />

4.3 Creating the Fuzzy Measure Object<br />

This section describes how to create a fuzzy measure object from an existing measure object. Fuzzy<br />

measure objects can be created by specifying a fuzzy membership function as described in section 4.3.1.<br />

Fuzzy measure objects can also be created with normalized fuzzy membership functions, i.e., fuzzy<br />

membership functions that are defined relative to the desired pair width (see section 4.3.2). Section 4.3.3<br />

on page 34 shows that it is even possible to specify multiple fuzzy membership functions for different<br />

set types of one fuzzy measure object.<br />

4.3.1 Specifying a Fuzzy Membership Function<br />

To transform a standard measure object into a fuzzy measure object, you specify a fuzzy membership<br />

function with the operator set_fuzzy_measure.<br />

For example, you can create a fuzzy measure object for the extraction of edge pairs that have a size of<br />

approximately 10 pixels with the following lines of code:<br />

create_funct_1d_pairs ([5,10,15], [0,1,0],<br />

FuzzyMembershipFunctionPairSize10)<br />

set_fuzzy_measure (MeasureHandle, ’size’,<br />

FuzzyMembershipFunctionPairSize10)<br />

The fuzzy membership function used in this example is displayed in figure 30.<br />

4.3.2 Specifying a Normalized Fuzzy Membership Function<br />

Fuzzy measure objects can also be created with normalized fuzzy membership functions, i.e., fuzzy<br />

membership functions that are defined relative to the desired pair width. For this, the operator<br />

set_fuzzy_measure_norm_pair must be used.


membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

4.3.2 Specifying a Normalized Fuzzy Membership Function 33<br />

0 5 10 15 20<br />

feature value<br />

Figure 30: Fuzzy membership function, which can be used to extract edge pairs that are approximately<br />

10 pixels wide.<br />

To create a fuzzy measure object that is identical with the one created in the above example (see section<br />

4.3.1), the following code can be used:<br />

create_funct_1d_pairs ([0.5,1,1.5], [0,1,0],<br />

FuzzyMembershipFunctionPairSizeNormalized)<br />

PairSize := 10<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, ’size’,<br />

FuzzyMembershipFunctionPairSizeNormalized)<br />

Here, the normalized fuzzy membership function is used, which is displayed in figure 31. Internally, the<br />

operator set_fuzzy_measure_norm_pair multiplies the x values of the normalized fuzzy membership<br />

function with the given pair size.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 0.5 1 1.5 2<br />

normalized feature value<br />

Figure 31: Normalized fuzzy membership function, which can be used for the extraction of edge pairs of<br />

various sizes, according to the defined pair size.<br />

One major advantage of using the normalized form of fuzzy membership functions is that the application<br />

can very easily be adapted to varying sizes of the object to be measured. If, e.g., larger objects must be<br />

measured or if a camera with a higher resolution is used, it will suffice to adapt the pair size.<br />

Fuzzy Measure


34 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

If, e.g., the above example for the extraction of 10 pixel wide edge pairs must be adapted to the extraction<br />

of 20 pixel wide edge pairs, simply the definition of the pair size must be changed:<br />

PairSize := 20<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, ’size’,<br />

FuzzyMembershipFunctionPairSizeNormalized)<br />

This creates a fuzzy measure object that uses the fuzzy membership function displayed in figure 32,<br />

internally.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 5 10 15 20 25 30 35 40<br />

feature value<br />

Figure 32: Fuzzy membership function, which can be used for the extraction of approximately 20 pixel<br />

wide edge pairs.<br />

To achieve such a fuzzy measure object without normalized fuzzy membership functions, the definition<br />

of the fuzzy membership function itself must be adapted:<br />

create_funct_1d_pairs ([10,20,30], [0,1,0],<br />

FuzzyMembershipFunctionPairSize20)<br />

set_fuzzy_measure (MeasureHandle, ’size’,<br />

FuzzyMembershipFunctionPairSize20)<br />

4.3.3 Specifying Multiple Fuzzy Membership Functions<br />

You can also specify fuzzy membership functions for different set types by repeatedly calling the operator<br />

set_fuzzy_measure or set_fuzzy_measure_norm_pair, respectively:<br />

set_fuzzy_measure (MeasureHandle, ’contrast’, FuzzyMembershipFunction1)<br />

set_fuzzy_measure (MeasureHandle, ’position’, FuzzyMembershipFunction2)<br />

If more than one set is defined in this way, the individual membership values will be aggregated with a<br />

fuzzy and operator: The overall membership value is derived by the geometric mean (see appendix C on<br />

page 62) of the individual membership values of each set.<br />

For example, the two set types ’contrast’ and ’position’ are used to achieve the selection of strong<br />

edges at the beginning of the profile line. For this, the two fuzzy membership functions as displayed in<br />

figure 28a and b on page 31 are used.


4.3.3 Specifying Multiple Fuzzy Membership Functions 35<br />

Assuming an edge at the position 20 along the profile line that has an amplitude of 80, the membership<br />

value is determined as follows. First, the membership values of the individual fuzzy sets are determined:<br />

membership value position=20 = 0.67<br />

membership value contrast=80 = 0.60<br />

Then, the geometric mean is calculated:<br />

�<br />

membership value20/80 = membership valueposition=20 · membership valuecontrast=80 = 0.63<br />

This value is compared to the fuzzy threshold. If it lies above this threshold, the respective edge will be<br />

accepted, otherwise it will be rejected.<br />

Figure 33a shows a plot of the membership value over the two feature values for ’contrast’ and ’position’.<br />

Assuming a fuzzy threshold of 0.5, the thick line in figure 33b marks the boundary of the domain of<br />

the feature values that lead to an acceptance of the respective edge. All edges with position/amplitude<br />

combinations that lie in this domain in the upper left corner will be accepted. The thin line marks the<br />

domain that results if both constraints must be satisfied individually. As can be seen, the domain that<br />

results from the combination of several set types is a bit larger. In particular, if one feature value meets<br />

the requirement very well, the other value may be slightly worse than allowed by the respective individual<br />

constraint.<br />

membership value<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

1<br />

0 10 20 30 40 50<br />

edge position 60 70 80 0<br />

50 100150200250<br />

edge amplitude<br />

edge amplitude<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

0 10 20 30 40 50 60 70 80<br />

edge position<br />

(a) (b)<br />

Figure 33: Membership value as a function of two feature values: (a) The membership value; (b) the<br />

boundary of the domain where edges will be accepted (thick line) compared to the boundary<br />

of the domain if the two constraints must be satisfied individually.<br />

To illustrate this, an edge at the position 10 having an amplitude of 65 is assumed. The individual<br />

membership values are:<br />

membership value position=10 = 1.00<br />

membership value contrast=65 = 0.30<br />

Fuzzy Measure


36 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

With this, the membership value can be calculated:<br />

�<br />

membership value10/65 = membership valueposition=10 · membership valuecontrast=65 = 0.54<br />

The overall membership value lies above 0.5 although the individual membership value for the contrast<br />

of the edge lies well below this value.<br />

<strong>Note</strong> that it is not possible to specify multiple fuzzy membership functions for one and the same set<br />

type. Setting a further fuzzy membership function to a set discards the previously defined function and<br />

replaces it by the new one.<br />

4.3.4 Changing and Resetting a Fuzzy Measure Object<br />

Fuzzy membership functions that have been specified for a particular set type can be changed and reset.<br />

To change a fuzzy membership function for a set type, simply specify the new fuzzy membership function<br />

for this set type with one of the operators set_fuzzy_measure and set_fuzzy_measure_norm_pair,<br />

as described in section 4.3.1 on page 32.<br />

A fuzzy measure object can be reset with the operator reset_fuzzy_measure. This discards the fuzzy<br />

membership function of the specified fuzzy set SetType. For example, the fuzzy membership function<br />

of the set type ’contrast’ is discarded with the following lines of code:<br />

SetType := ’contrast’<br />

reset_fuzzy_measure (MeasureHandle, SetType)<br />

4.4 Using the Standard Measure Object Functionality<br />

All operators that provide functionality for the standard measure object can also be applied to fuzzy measure<br />

objects. This includes especially the operators measure_projection, measure_thresh, translate_measure,<br />

and close_measure. The operators for the standard measure object ignore the specified<br />

fuzzy membership functions and return the same results as if they were applied to a standard measure<br />

object.


Appendix<br />

A Slanted Edges<br />

A Slanted Edges 37<br />

This section shows the effect of the width of the ROI and the angle between the profile line and the edges.<br />

In the figures on the next pages, the images on the left hand show the size and orientation of the ROI and<br />

the diagrams on the right hand show the resulting profile (thick line) and its derivative (thin line, Sigma<br />

= 0.9).<br />

As long as the profile line runs approximately perpendicular to the edges, the ROI should be chosen as<br />

wide as possible because then the profile is less noisy (compare, e.g., figure 35a and figure 35c).<br />

If the profile line does not run perpendicular to the edges (see figure 36 on page 39 and figure 37 on page<br />

40), the width of the ROI must be chosen smaller to allow the detection of edges. <strong>Note</strong> that in this case,<br />

the profile will contain more noise. Consequently, the edges will be determined less accurately. What is<br />

more, the distance between the determined edges does not represent the perpendicular, i.e., the shortest<br />

distance between the respective image edges (see figure 34). If the angle δ between the profile line and<br />

the perpendicular of the edges is known, the perpendicular distance can be determined from the distance<br />

between the determined edges (Distance) as follows:<br />

perpendicular distance = cos(δ) · Distance<br />

Profile Line<br />

ROI<br />

Distance<br />

δ<br />

Perpendicular distance<br />

between the edges<br />

Figure 34: Relationship between the determined Distance and the perpendicular distance between<br />

edges.<br />

If the profile line is heavily slanted with respect to the edges, it may become impossible to determine the<br />

edges reliably, even with a very narrow ROI (see, e.g., figure 38a on page 41).<br />

Appendix


38 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(a) Width of the ROI: 6 pixels.<br />

gray value<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(b) Width of the ROI: 30 pixels.<br />

gray value<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(c) Width of the ROI: 60 pixels.<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

profile line<br />

Figure 35: Angle between the profile line and the perpendicular of the edges: 0 ◦ .


gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(a) Width of the ROI: 6 pixels.<br />

gray value<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(b) Width of the ROI: 30 pixels.<br />

gray value<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(c) Width of the ROI: 60 pixels.<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

profile line<br />

Figure 36: Angle between the profile line and the perpendicular of the edges: 15 ◦ .<br />

A Slanted Edges 39<br />

Appendix


40 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(a) Width of the ROI: 6 pixels.<br />

gray value<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(b) Width of the ROI: 30 pixels.<br />

gray value<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(c) Width of the ROI: 60 pixels.<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

profile line<br />

Figure 37: Angle between the profile line and the perpendicular of the edges: 30 ◦ .


gray value<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(a) Width of the ROI: 6 pixels.<br />

gray value<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(b) Width of the ROI: 30 pixels.<br />

gray value<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

250<br />

200<br />

150<br />

100<br />

50<br />

0<br />

-50<br />

-100<br />

(c) Width of the ROI: 60 pixels.<br />

profile line<br />

-150<br />

0 20 40 60 80 100 120 140<br />

profile line<br />

Figure 38: Angle between the profile line and the perpendicular of the edges: 45 ◦ .<br />

A Slanted Edges 41<br />

Appendix


42 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

B Examples for Fuzzy Membership Functions<br />

In this section, examples for fuzzy membership functions are given. For each set type (see section 4.2.1<br />

on page 28), the typical range of the x values of the fuzzy membership functions as well as one fuzzy<br />

membership function is given. If the set type allows the creation of the fuzzy measure object with fuzzy<br />

membership functions and normalized fuzzy membership functions, both fuzzy membership functions<br />

are displayed. In this case, the normalized fuzzy membership function is defined such that, together with<br />

the stated PairSize, it creates the same fuzzy measure object as the direct fuzzy membership function.<br />

Then, mostly a PairSize of 10.0 is used to make it easy to compare the two fuzzy membership functions.<br />

The effect of the specification of the fuzzy membership function is shown by means of the results of the<br />

fuzzy measure object applied to the test image shown in figure 39.<br />

Figure 39: The test image that is used to show the effect of the different fuzzy membership functions .<br />

The results of the standard measure object applied to this test image are shown in figure 40.<br />

(a) (b)<br />

Figure 40: Result of the standard measure object applied to the test image: (a) Edges determined with<br />

the operator measure_pos, (b) edge pairs determined with the operator measure_pairs .<br />

Figure 40a shows the edges determined with the operator measure_pos and figure 40b shows the edge<br />

pairs determined with the operator measure_pairs. Both operators were applied with the following<br />

parameter settings:<br />

Parameter Value<br />

Sigma 1.0<br />

Threshold 10.0<br />

Transition ’all’<br />

Select ’all’<br />

FuzzyThresh 0.5<br />

The following examples shall give an impression of the effect of different fuzzy membership functions<br />

specified for different set types. They are in no way complete. <strong>Note</strong> that all the edge pairs are extracted<br />

with the operator fuzzy_measure_pairs, not with the operator fuzzy_measure_pairing.


B.1 Set Type contrast<br />

B.1.1 Subtype ’contrast’<br />

Evaluates the amplitude of the edges.<br />

B.1 Set Type contrast 43<br />

The x values of fuzzy membership functions for the sub set type ’contrast’ must lie within the range of<br />

gray values, i.e.,<br />

0.0 ≤ x ≤ 255.0 for ’byte’ images and<br />

0.0 ≤ x ≤ 65535.0 for ’uint2’ images.<br />

Figure 41 shows a fuzzy membership function that can be used to extract strong edges in ’byte’ images.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 50 100 150 200 250<br />

feature value<br />

The sub set type ’contrast’ cannot be specified<br />

with a normalized fuzzy membership function.<br />

(a) (b)<br />

Figure 41: A fuzzy membership function that can be used to extract strong edges in ’byte’ images (SetType<br />

= ’contrast’).<br />

Figure 42 shows the positions of the edges that will be extracted if the the fuzzy measure object is created<br />

with the fuzzy membership function displayed in figure 41. With this fuzzy measure object, only those<br />

edges are extracted that have a contrast between 75 and 125.<br />

Figure 42: The extracted edges.<br />

The fuzzy membership function displayed in figure 41a can be created with the following HDevelop<br />

code:<br />

SetType := ’contrast’<br />

create_funct_1d_pairs ([50,100,150], [0,1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

Appendix


44 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

B.2 Set Type position<br />

B.2.1 Subtype ’position’<br />

Evaluates the signed distance of the edges to the reference point of the fuzzy measure object. The<br />

reference point is located at the start of the profile line (see figure 9 on page 10 and figure 10 on page<br />

11).<br />

The x values of fuzzy membership functions for the sub set type ’position’ must lie within the range<br />

0.0 ≤ x ≤ length of the ROI.<br />

Figure 43 shows fuzzy membership functions that can be used to extract edges at the beginning of the<br />

profile line.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 10 20 30 40 50<br />

normalized feature value<br />

Figure 43: Fuzzy membership functions that can be used to extract edges at the beginning of the profile<br />

line (SetType = ’position’, PairSize = 10).<br />

Figure 44 shows the positions of the edges that will be extracted if the the fuzzy measure object is created<br />

with the fuzzy membership function displayed in figure 43. Only the first four edges are returned.<br />

Figure 44: The extracted edges.<br />

The fuzzy membership function displayed in figure 43a can be created with the following HDevelop<br />

code:<br />

SetType := ’position’<br />

create_funct_1d_pairs ([50,130], [1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 43b can be created<br />

with the following HDevelop code:


SetType := ’position’<br />

PairSize := 10<br />

create_funct_1d_pairs ([5,13], [1,0], NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.2.2 Subtype ’position_center’<br />

B.2.2 Subtype ’position_center’ 45<br />

’position_center’ behaves like ’position’ with the reference point located at the center of the profile line.<br />

The x values of fuzzy membership functions for the sub set type ’position_center’ must lie within the<br />

range<br />

length of the ROI<br />

−<br />

2<br />

≤ x ≤<br />

length of the ROI<br />

2<br />

.<br />

Figure 45 shows fuzzy membership functions that can be used to extract edges in the center of the profile<br />

line.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-200 -100 0 100 200<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-25 -20 -15 -10 -5 0 5 10 15 20 25<br />

normalized feature value<br />

Figure 45: Fuzzy membership functions that can be used to extract edges in the center of the profile line<br />

(SetType = ’position_center’, PairSize = 10).<br />

Figure 46 shows the positions of the edges that will be extracted if the the fuzzy measure object is created<br />

with the fuzzy membership function displayed in figure 45. Only the edges in the center of the profile<br />

line are returned.<br />

Figure 46: The extracted edges.<br />

The fuzzy membership function displayed in figure 45a can be created with the following HDevelop<br />

code:<br />

Appendix


46 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

SetType := ’position_center’<br />

create_funct_1d_pairs ([-70,-20,20,70], [0,1,1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 45b can be created<br />

with the following HDevelop code:<br />

SetType := ’position_center’<br />

PairSize := 10<br />

create_funct_1d_pairs ([-7,-2,2,7], [0,1,1,0],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.2.3 Subtype ’position_end’<br />

’position_end’ behaves like ’position’ with the reference point located at the end of the profile line.<br />

The x values of fuzzy membership functions for the sub set type ’position_end’ must lie within the range<br />

−length of the ROI ≤ x ≤ 0.0.<br />

Figure 47 shows fuzzy membership functions that can be used to extract edges at the end of the profile<br />

line.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-500 -400 -300 -200 -100 0<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-50 -40 -30 -20 -10 0<br />

normalized feature value<br />

Figure 47: Fuzzy membership functions that can be used to extract edges at the end of the profile line<br />

(SetType = ’position_end’, PairSize = 10).<br />

Figure 48 shows the positions of the edges that will be extracted if the the fuzzy measure object is created<br />

with the fuzzy membership function displayed in figure 47. Only the edges at the end of the profile line<br />

are returned.<br />

The fuzzy membership function displayed in figure 47a can be created with the following HDevelop<br />

code:


Figure 48: The extracted edges.<br />

SetType := ’position_end’<br />

create_funct_1d_pairs ([-250,0], [0,1], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

B.2.4 Subtype ’position_first_edge’ 47<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 47b can be created<br />

with the following HDevelop code:<br />

SetType := ’position_end’<br />

PairSize := 10<br />

create_funct_1d_pairs ([-25,0], [0,1], NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.2.4 Subtype ’position_first_edge’<br />

’position_first_edge’ behaves like ’position’ with the reference point located at the first edge.<br />

The x values of fuzzy membership functions for the sub set type ’position_first_edge’ must lie within the<br />

range<br />

0.0 ≤ x ≤ length of the ROI.<br />

Figure 49 shows fuzzy membership functions that can be used to extract edges close to the first edge.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 10 20 30 40 50<br />

normalized feature value<br />

Figure 49: Fuzzy membership functions that can be used to extract edges close to the first edge (SetType<br />

= ’position_first_edge’, PairSize = 10).<br />

Appendix


48 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

Figure 50 shows the positions of the edges that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 49. Only the edges at the beginning of<br />

the profile line are returned. <strong>Note</strong> that even though the same fuzzy membership function has been used<br />

as in figure 43 on page 44, one more edge has been extracted. This is because the reference point is<br />

located at the first edge instead of the start of the profile line.<br />

Figure 50: The extracted edges.<br />

The fuzzy membership function displayed in figure 49a on page 47 can be created with the following<br />

HDevelop code:<br />

SetType := ’position_first_edge’<br />

create_funct_1d_pairs ([50,130], [1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 49b on page 47 can<br />

be created with the following HDevelop code:<br />

SetType := ’position_first_edge’<br />

PairSize := 10<br />

create_funct_1d_pairs ([5,13], [1,0], NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.2.5 Subtype ’position_last_edge’<br />

’position_last_edge’ behaves like ’position’ with the reference point located at the last edge.<br />

The x values of fuzzy membership functions for the sub set type ’position_last_edge’ must lie within the<br />

range<br />

−length of the ROI ≤ x ≤ 0.0.<br />

Figure 51 shows fuzzy membership functions that can be used to extract edges close to the last edge.<br />

Figure 52 shows the positions of the edges that will be extracted if the the fuzzy measure object is created<br />

with the fuzzy membership function displayed in figure 51. Only the edges at the end of the profile line<br />

are returned. <strong>Note</strong> that even though the same fuzzy membership function has been used as in figure 47<br />

on page 46, more edges have been extracted. This is because the reference point is located at the last<br />

edge instead of the end of the profile line.<br />

The fuzzy membership function displayed in figure 51a can be created with the following HDevelop<br />

code:


membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-500 -400 -300 -200 -100 0<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

B.3 Set Type position_pair 49<br />

-50 -40 -30 -20 -10 0<br />

normalized feature value<br />

Figure 51: Fuzzy membership functions that can be used to extract edges close to the last edge (SetType<br />

= ’position_last_edge’, PairSize = 10).<br />

Figure 52: The extracted edges.<br />

SetType := ’position_last_edge’<br />

create_funct_1d_pairs ([-250,0], [0,1], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 51b can be created<br />

with the following HDevelop code:<br />

SetType := ’position_last_edge’<br />

PairSize := 10<br />

create_funct_1d_pairs ([-25,0], [0,1], NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.3 Set Type position_pair<br />

<strong>Note</strong> that for the extraction of edge pairs all possible pairs of edges are internally analyzed according<br />

to the specified fuzzy membership functions. If only partial knowledge about the edge pairs to be determined<br />

is specified with the fuzzy membership functions, this will possibly lead to unintuitive results.<br />

For example, if the position of the edge pairs is specified but not their size, some small edge pairs will<br />

possibly be omitted because of a large edge pair that consists of the first edge of the first small edge pair<br />

and the second edge of the last small edge pair and that has a membership value equal to or higher than<br />

that of the small edge pairs (see appendix B.3.1). Therefore, all the available knowledge about the edge<br />

Appendix


50 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

pairs to be extracted should be specified with fuzzy membership functions. In the above example, the<br />

definition of the desired edge pairs can be made more clear by also specifying the size of the edge pairs<br />

(see appendix B.6 on page 61).<br />

B.3.1 Subtype ’position_pair’<br />

Evaluates the signed distance of the edge pairs to the reference point of the fuzzy measure object. The<br />

position of an edge pair is defined as the center of the two edges. The reference point is located at the<br />

start of the profile line (see figure 9 on page 10 and figure 10 on page 11).<br />

The x values of fuzzy membership functions for the sub set type ’position_pair’ must lie within the range<br />

0.0 ≤ x ≤ length of the ROI.<br />

Figure 53 shows fuzzy membership functions that can be used to extract edge pairs in approximately the<br />

first half of the profile line.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 10 20 30 40 50<br />

normalized feature value<br />

Figure 53: Fuzzy membership functions that can be used to extract edge pairs in approximately the first<br />

half of the profile line (SetType = ’position_pair’, PairSize = 10).<br />

Figure 54 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 53. Only edge pairs in approximately<br />

the first half of the profile line are returned. <strong>Note</strong> that one large edge pair is extracted instead of multiple<br />

small ones. This happens because internally, all possible pairs of edges are analyzed according to the<br />

specified fuzzy membership functions and no condition for the size of the edge pairs was given. See<br />

appendix B.6 on page 61 for an example where in addition a fuzzy membership function for the size of<br />

the edge pairs is specified.<br />

The fuzzy membership function displayed in figure 53a can be created with the following HDevelop<br />

code:<br />

SetType := ’position_pair’<br />

create_funct_1d_pairs ([0,50,250,300], [0,1,1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 53b can be created


with the following HDevelop code:<br />

Figure 54: The extracted edge pairs.<br />

SetType := ’position_pair’<br />

PairSize := 10<br />

create_funct_1d_pairs ([0,5,25,30], [0,1,1,0],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.3.2 Subtype ’position_pair_center’<br />

B.3.2 Subtype ’position_pair_center’ 51<br />

’position_pair_center’ behaves like ’position_pair’ with the reference point located at the center of the<br />

profile line.<br />

The x values of fuzzy membership functions for the sub set type ’position_pair_center’ must lie within<br />

the range<br />

length of the ROI<br />

−<br />

2<br />

≤ x ≤<br />

length of the ROI<br />

2<br />

.<br />

Figure 55 shows fuzzy membership functions that can be used to extract edge pairs in the middle of the<br />

profile line.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-200 -100 0 100 200<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-25 -20 -15 -10 -5 0 5 10 15 20 25<br />

normalized feature value<br />

Figure 55: Fuzzy membership functions that can be used to extract edge pairs in the middle of the profile<br />

line (SetType = ’position_pair_center’, PairSize = 10).<br />

Figure 56 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 55. Only one edge pair in the middle of<br />

Appendix


52 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

the profile line is returned. <strong>Note</strong> that only the position of the edge pair, i.e., the position of the center<br />

between the two edges of the edge pair is used to restrict the extraction of edge pairs. The position of the<br />

individual edges of the edge pair is not restricted. In this case, one large edge pair with its center in the<br />

middle of the profile line is returned.<br />

Figure 56: The extracted edge pairs.<br />

The fuzzy membership function displayed in figure 55a on page 51 can be created with the following<br />

HDevelop code:<br />

SetType := ’position_pair_center’<br />

create_funct_1d_pairs ([-25,0,25], [0,1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 55b on page 51 can<br />

be created with the following HDevelop code:<br />

SetType := ’position_pair_center’<br />

PairSize := 10<br />

create_funct_1d_pairs ([-2.5,0,2.5], [0,1,0],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.3.3 Subtype ’position_pair_end’<br />

’position_pair_end’ behaves like ’position_pair’ with the reference point located at the end of the profile<br />

line.<br />

The x values of fuzzy membership functions for the sub set type ’position_pair_end’ must lie within the<br />

range<br />

−length of the ROI ≤ x ≤ 0.0.<br />

Figure 57 shows fuzzy membership functions that can be used to extract edge pairs at the end of the<br />

profile line.<br />

Figure 58 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 57. Only edge pairs at the end of the<br />

profile line are returned.<br />

The fuzzy membership function displayed in figure 57a can be created with the following HDevelop<br />

code:


membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-500 -400 -300 -200 -100 0<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

B.3.4 Subtype ’position_first_pair’ 53<br />

-50 -40 -30 -20 -10 0<br />

normalized feature value<br />

Figure 57: Fuzzy membership functions that can be used to extract edge pairs at the end of the profile<br />

line (SetType = ’position_pair_end’, PairSize = 10).<br />

Figure 58: The extracted edge pairs.<br />

SetType := ’position_pair_end’<br />

create_funct_1d_pairs ([-300,-200,0], [0,0.9,1], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 57b can be created<br />

with the following HDevelop code:<br />

SetType := ’position_pair_end’<br />

PairSize := 10<br />

create_funct_1d_pairs ([-30,-20,0], [0,0.9,1],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.3.4 Subtype ’position_first_pair’<br />

’position_first_pair’ behaves like ’position_pair’ with the reference point located at the position of the<br />

first edge pair.<br />

The x values of fuzzy membership functions for the sub set type ’position_first_pair’ must lie within the<br />

range<br />

0.0 ≤ x ≤ length of the ROI.<br />

Appendix


54 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

Figure 59 shows fuzzy membership functions that can be used to extract edge pairs in approximately the<br />

first half of the profile line.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 10 20 30 40 50<br />

normalized feature value<br />

Figure 59: Fuzzy membership functions that can be used to extract edge pairs in approximately the first<br />

half of the profile line (SetType = ’position_first_pair’, PairSize = 10).<br />

Figure 60 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 59. Only one edge pair in the first half<br />

of the profile line is returned. <strong>Note</strong> that a large edge pair is extracted instead of multiple small ones.<br />

This happens because internally, all possible pairs of edges are analyzed according to the specified fuzzy<br />

membership functions and no condition for the size of the edge pairs was given. See appendix B.6 on<br />

page 61 for an example where in addition to a fuzzy membership function for the position of the edge<br />

pairs a fuzzy membership function for their size is specified. <strong>Note</strong> also that even though the same fuzzy<br />

membership function has been used as in appendix B.3.1 on page 50 one more edge pair is extracted<br />

because the reference point is located at the first edge pair instead of the start of the profile line.<br />

Figure 60: The extracted edge pairs.<br />

The fuzzy membership function displayed in figure 59a can be created with the following HDevelop<br />

code:<br />

SetType := ’position_first_pair’<br />

create_funct_1d_pairs ([0,50,250,300], [0,1,1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 59b can be created<br />

with the following HDevelop code:


SetType := ’position_first_pair’<br />

PairSize := 10<br />

create_funct_1d_pairs ([0,5,25,30], [0,1,1,0],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.3.5 Subtype ’position_last_pair’<br />

B.3.5 Subtype ’position_last_pair’ 55<br />

’position_last_pair’ behaves like ’position_pair’ with the reference point located at the position of the<br />

last edge pair.<br />

The x values of fuzzy membership functions for the sub set type ’position_last_pair’ must lie within the<br />

range<br />

−length of the ROI ≤ x ≤ 0.0.<br />

Figure 61 shows fuzzy membership functions that can be used to extract edge pairs close to the last edge<br />

pair.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-500 -400 -300 -200 -100 0<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-50 -40 -30 -20 -10 0<br />

normalized feature value<br />

Figure 61: Fuzzy membership functions that can be used to extract edge pairs close to the last edge pair<br />

(SetType = ’position_last_pair’, PairSize = 10).<br />

Figure 62 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 61. Only edge pairs in the second half of<br />

the profile line are returned. <strong>Note</strong> that even though the same fuzzy membership function has been used<br />

as in appendix B.3.3 on page 52, more edge pairs are extracted. This is because the reference point is<br />

located at the last edge pair instead of the end of the profile line.<br />

The fuzzy membership function displayed in figure 61a can be created with the following HDevelop<br />

code:<br />

Appendix


56 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

Figure 62: The extracted edge pairs.<br />

SetType := ’position_last_pair’<br />

create_funct_1d_pairs ([-300,-200,0], [0,0.9,1], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 61b can be created<br />

with the following HDevelop code:<br />

SetType := ’position_last_pair’<br />

PairSize := 10<br />

create_funct_1d_pairs ([-30,-20,0], [0,0.9,1],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.4 Set Type size<br />

B.4.1 Subtype ’size’<br />

Evaluates the size of the edge pairs, i.e., the distance between the two edges.<br />

The x values of fuzzy membership functions for the sub set type ’size’ must lie within the range<br />

x ≥ 0.0.<br />

Figure 63 shows fuzzy membership functions that can be used to extract edge pairs that are approximately<br />

50 pixels wide.<br />

Figure 64 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 63. Only edge pairs that are approximately<br />

50 pixels wide are returned.<br />

The fuzzy membership function displayed in figure 63a can be created with the following HDevelop<br />

code:<br />

SetType := ’size’<br />

create_funct_1d_pairs ([20,50,80], [0,1,0], FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)<br />

The equivalent normalized fuzzy membership function, which is displayed in figure 63b can be created<br />

with the following HDevelop code:


membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

B.4.2 Subtype ’size_diff’ 57<br />

0 0.5 1 1.5 2<br />

normalized feature value<br />

Figure 63: Fuzzy membership functions that can be used to extract edge pairs that are approximately<br />

50 pixels wide (SetType = ’size’, PairSize = 50).<br />

Figure 64: The extracted edge pairs.<br />

SetType := ’size’<br />

PairSize := 50<br />

create_funct_1d_pairs ([0.4,1,1.6], [0,1,0],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

B.4.2 Subtype ’size_diff’<br />

Evaluates the signed difference between the desired PairSize and the actual size of the edge pairs.The<br />

signed difference is defined by:<br />

x =<br />

PairSize − actual size of a pair<br />

PairSize<br />

The x values of fuzzy membership functions for the sub set type ’size_diff’ must lie within the range<br />

x ≤ 1.0.<br />

Figure 65 shows a fuzzy membership function that can be used to extract edge pairs that have the specified<br />

PairSize or are a little bit smaller.<br />

Figure 66 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 65. Only edge pairs that are between<br />

11 pixels and 15 pixels wide are returned.<br />

Appendix


58 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

The sub set type ’size_diff’ can only be specified<br />

with a normalized fuzzy membership function.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

-1 -0.5 0 0.5 1<br />

normalized feature value<br />

(a) (b)<br />

Figure 65: A fuzzy membership function that can be used to extract edge pairs that have the specified<br />

PairSize or are a little bit smaller (SetType = ’size_diff’, PairSize = 15).<br />

Figure 66: The extracted edge pairs.<br />

The normalized fuzzy membership function displayed in figure 65b can be created with the following<br />

HDevelop code:<br />

SetType := ’size_diff’<br />

PairSize := 15<br />

create_funct_1d_pairs ([-0.01,0,0.5], [0,1,0],<br />

NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

<strong>Note</strong> that with the subtype ’size_diff’ asymmetrical fuzzy membership functions can be specified for<br />

the difference between the PairSize and the actual size of an edge pair. This is not possible with the<br />

subtype ’size_abs_diff’ (see appendix B.4.3).<br />

B.4.3 Subtype ’size_abs_diff’<br />

Evaluates the absolute difference between the desired PairSize and the actual size of the edge pairs.The<br />

absolute difference is defined by:<br />

x =<br />

|PairSize − actual size of a pair|<br />

PairSize<br />

The x values of fuzzy membership functions for the sub set type ’size_abs_diff’ must lie within the range<br />

x ≥ 0.0.


B.4.3 Subtype ’size_abs_diff’ 59<br />

Figure 67 shows a fuzzy membership function that can be used to extract edge pairs that are approximately<br />

as wide as the specified PairSize.<br />

The sub set type ’size_abs_diff’ can only be<br />

specified with a normalized fuzzy membership<br />

function.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 0.2 0.4 0.6 0.8 1<br />

normalized feature value<br />

(a) (b)<br />

Figure 67: A fuzzy membership function that can be used to extract edge pairs that are approximately as<br />

wide as the specified PairSize (SetType = ’size_abs_diff’, PairSize = 15).<br />

Figure 68 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership function displayed in figure 67. Only edge pairs that are between<br />

11 pixels and 19 pixels wide are returned. <strong>Note</strong> that in addition to the edge pairs that are extracted in<br />

appendix B.4.2 on page 57 also larger edge pairs are returned.<br />

Figure 68: The extracted edge pairs.<br />

The normalized fuzzy membership function displayed in figure 67b can be created with the following<br />

HDevelop code:<br />

SetType := ’size_abs_diff’<br />

PairSize := 15<br />

create_funct_1d_pairs ([0,0.5], [1,0], NormalizedFuzzyMembershipFunction)<br />

set_fuzzy_measure_norm_pair (MeasureHandle, PairSize, SetType,<br />

NormalizedFuzzyMembershipFunction)<br />

<strong>Note</strong> that with the subtype ’size_abs_diff’ only symmetrical fuzzy membership functions can be specified<br />

for the difference between the PairSize and the actual size of an edge pair. To specify asymetrical fuzzy<br />

membership functions, use the subtype ’size_abs_diff’ (see appendix B.4.2 on page 57). Appendix


60 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

B.5 Set Type gray<br />

B.5.1 Subtype gray<br />

Evaluates the mean gray value between the two edges of edge pairs.<br />

The x values of fuzzy membership functions for the sub set type ’gray’ must lie within the range of gray<br />

values, i.e.,<br />

0.0 ≤ x ≤ 255.0 for ’byte’ images and<br />

0.0 ≤ x ≤ 65535.0 for ’uint2’ images.<br />

Figure 69 shows a fuzzy membership function that can be used to extract edge pairs that enclose areas<br />

with a gray value of approximately 50 or 150.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 50 100 150 200 250<br />

feature value<br />

The sub set type ’gray’ cannot be specified<br />

with a normalized fuzzy membership function.<br />

(a) (b)<br />

Figure 69: A fuzzy membership function that can be used to extract edge pairs that enclose areas with a<br />

gray value of approximately 50 or 150 (SetType = ’gray’).<br />

Figure 70 shows the positions of the edges that will be extracted if the the fuzzy measure object is created<br />

with the fuzzy membership function displayed in figure 69. With this fuzzy measure object, only those<br />

edge pairs are returned that enclose areas of the specified gray values.<br />

Figure 70: The extracted edges.<br />

The fuzzy membership function displayed in figure 69a can be created with the following HDevelop<br />

code:<br />

SetType := ’gray’<br />

create_funct_1d_pairs ([20,40,60,80,120,140,160,180], [0,1,1,0,0,1,1,0],<br />

FuzzyMembershipFunction)<br />

set_fuzzy_measure (MeasureHandle, SetType, FuzzyMembershipFunction)


B.6 Set Type position_pair combined with size<br />

B.6 Set Type position_pair combined with size 61<br />

Figure 71 shows two fuzzy membership functions that can be used to determine edge pairs in approximately<br />

the first half of the profile line. In addition to only specifying the position of the edge pairs (see<br />

appendix B.3.1 on page 50), also a fuzzy membership function for the size of the edge pairs is specified<br />

(see appendix B.4.1 on page 56). With this, it is possible to define precisely which kind of edge pairs<br />

must be returned.<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

(a) (b)<br />

membership value<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

0<br />

0 100 200 300 400 500<br />

feature value<br />

Figure 71: Fuzzy membership functions that can be used to extract edge pairs in approximately the first<br />

half of the profile line: (a) The restriction for the position of the pairs (SetType = ’position_pair’)<br />

and (b) a fuzzy membership function that favors small edge pairs (SetType = ’size’).<br />

Figure 72 shows the positions of the edge pairs that will be extracted if the the fuzzy measure object is<br />

created with the fuzzy membership functions displayed in figure 71. Only edge pairs in approximately<br />

the first half of the profile line are returned. <strong>Note</strong> that smaller edge pairs than in the example in appendix<br />

B.3.1 on page 50 are extracted. This is because of the constraint on the size of the edge pairs,<br />

which is introduced by the fuzzy membership function for the size of the edge pairs (figure 71b).<br />

Figure 72: The extracted edge pairs.<br />

The fuzzy membership function displayed in figure 71a can be created with the following HDevelop<br />

code:<br />

create_funct_1d_pairs ([0,50,250,300], [0,1,1,0],<br />

FuzzyMembershipFunctionPositionPair)<br />

The fuzzy membership function displayed in figure 71b can be created with the following HDevelop<br />

code:<br />

create_funct_1d_pairs ([0,50], [1,0.5], FuzzyMembershipFunctionSize)<br />

Then, the fuzzy measure object can be created:<br />

Appendix


62 <strong>Application</strong> <strong>Note</strong> on <strong>1D</strong> <strong>Metrology</strong><br />

set_fuzzy_measure (MeasureHandle, ’position_pair’,<br />

FuzzyMembershipFunctionPositionPair)<br />

set_fuzzy_measure (MeasureHandle, ’size’, FuzzyMembershipFunctionSize)<br />

C Definition of the Geometric Mean<br />

The geometric mean of a sequence {ai} n i=1<br />

Thus,<br />

and so on.<br />

is defined by<br />

G(a1, . . . , an) ≡<br />

� n�<br />

i=1<br />

ai<br />

G(a1, a2) = � (a1a2)<br />

� 1/n<br />

G(a1, a2, a3) = (a1a2a3) 1/3


Provided Functionality<br />

<strong>HALCON</strong> <strong>Application</strong> <strong>Note</strong><br />

Machine Vision in World<br />

Coordinates<br />

⊲ Calibration of camera systems (single camera, multiple camera setup, binocular stereo system)<br />

⊲ Transformation of image coordinates into 3D world coordinates and vice versa<br />

⊲ Rectification of images to compensate distortion or camera orientation<br />

⊲ Determination of orientation and position of known 3D objects<br />

⊲ 3D reconstruction of unknown 3D objects using binocular stereo vision<br />

⊲ Combination of multiple images into a larger mosaic image (image stitching)<br />

⊲ Calibration of hand-eye (robot-camera) systems and transformation of image processing results<br />

from camera into robot coordinates<br />

Typical <strong>Application</strong>s<br />

⊲ Inspection of dimensional accuracy in world coordinates<br />

⊲ Generation of overview images of large objects<br />

⊲ 3D reconstruction<br />

⊲ Robot vision<br />

Copyright c○ 2003-2008 by <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>, München, Germany <strong>MVTec</strong> <strong>Software</strong> <strong>GmbH</strong>


Overview<br />

Measurements in 3D become more and more important. <strong>HALCON</strong> provides many methods to perform<br />

3D measurements. This application note gives you an overview over these methods, and it assists you<br />

with the selection and the correct application of the appropriate method.<br />

A short characterisation of the various methods is given in section 1 on page 5. Principles of 3D transformations<br />

and poses as well as the description of the camera model can be found in section 2 on page<br />

8. Afterwards, the methods to perform 3D measurements are described in detail.<br />

Unless specified otherwise, the HDevelop example programs can be found in the subdirectory<br />

3d_machine_vision of the directory <strong>HALCON</strong>ROOT \examples\application_guide.<br />

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted in<br />

any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written<br />

permission of the publisher.<br />

Edition 1 December 2003 (<strong>HALCON</strong> 7.0)<br />

Edition 1a July 2004 (<strong>HALCON</strong> 7.0.1)<br />

Edition 1b April 2005 (<strong>HALCON</strong> 7.0.2)<br />

Edition 2 July 2005 (<strong>HALCON</strong> 7.1)<br />

Edition 2a December 2006 (<strong>HALCON</strong> 7.1.2)<br />

Microsoft, Windows, Windows NT, Windows 2000, and Windows XP are either trademarks or registered trademarks<br />

of Microsoft Corporation.<br />

All other nationally and internationally recognized trademarks and tradenames are hereby recognized.<br />

More information about <strong>HALCON</strong> can be found at:<br />

http://www.halcon.com/


Contents<br />

1 Can You Really Perform 3D Machine Vision with <strong>HALCON</strong>? 5<br />

2 Basics 8<br />

2.1 3D Transformations and Poses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.2 Camera Model and Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

3 3D Machine Vision in a Specified Plane With a Single Camera 27<br />

3.1 Calibrating the Camera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />

3.2 Transforming Image into World Coordinates and Vice Versa . . . . . . . . . . . . . . . 44<br />

3.3 Rectifying Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />

3.4 Inspection of Non-Planar Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

4 Calibrated Mosaicking 59<br />

4.1 Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

4.2 Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

4.3 Merging the Individual Images into One Larger Image . . . . . . . . . . . . . . . . . . 63<br />

5 Uncalibrated Mosaicking 69<br />

5.1 Rules for Taking Images for a Mosaic Image . . . . . . . . . . . . . . . . . . . . . . . . 72<br />

5.2 Definition of Overlapping Image Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

5.3 Detection of Characteristic Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />

5.4 Matching of Characteristic Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

5.5 Generation of the Mosaic Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

5.6 Bundle Adjusted Mosaicking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

5.7 Spherical Mosaicking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />

6 Pose Estimation of Known 3D Objects With a Single Camera 84<br />

6.1 Pose Estimation for General 3D Objects . . . . . . . . . . . . . . . . . . . . . . . . . . 84<br />

6.2 Pose Estimation for 3D Circles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88<br />

7 3D Machine Vision With a Binocular Stereo System 88<br />

7.1 The Principle of Stereo Vision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />

7.2 The Setup of a Stereo Camera System . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />

7.3 Calibrating the Stereo Camera System . . . . . . . . . . . . . . . . . . . . . . . . . . . 93<br />

3


4 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

7.4 Obtaining 3D Information from Images . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />

7.5 Uncalibrated Stereo Vision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />

8 Robot Vision 109<br />

8.1 The Principle of Hand-Eye Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />

8.2 Determining Suitable Input Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />

8.3 Performing the Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118<br />

8.4 Using the Calibration Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119<br />

9 Rectification of Arbitrary Distortions 123<br />

9.1 Basic Principle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

9.2 Rules for Taking Images of the Rectification Grid . . . . . . . . . . . . . . . . . . . . . 125<br />

9.3 Machine Vision on Ruled Surfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

9.4 Using Self-Defined Rectification Grids . . . . . . . . . . . . . . . . . . . . . . . . . . . 130<br />

A The <strong>HALCON</strong> Calibration Plate 136<br />

B HDevelop Procedures Used in this <strong>Application</strong> <strong>Note</strong> 137<br />

B.1 gen_hom_mat3d_from_three_points . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137<br />

B.2 parameters_image_to_world_plane_centered . . . . . . . . . . . . . . . . . . . . . . . 138<br />

B.3 parameters_image_to_world_plane_entire . . . . . . . . . . . . . . . . . . . . . . . . . 139<br />

B.4 tilt_correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

B.5 visualize_results_of_find_marks_and_pose . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

B.6 display_calplate_coordinate_system . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

B.7 display_3d_coordinate_system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

B.8 select_values_for_ith_image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

B.9 calc_base_start_pose_movingcam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

B.10 calc_cam_start_pose_movingcam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

B.11 calc_calplate_pose_movingcam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

B.12 calc_base_start_pose_stationarycam . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

B.13 calc_cam_start_pose_stationarycam . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143<br />

B.14 calc_calplate_pose_stationarycam . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144<br />

B.15 define_reference_coord_system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144


1 Can You Really Perform 3D Machine Vision with <strong>HALCON</strong>? 5<br />

1 Can You Really Perform 3D Machine Vision with <strong>HALCON</strong>?<br />

Do you have an application at hand where it is necessary to perform 3D measurements from images?<br />

Then, <strong>HALCON</strong> is exactly the right software solution for you. This application note will introduce you<br />

to the world of 3D machine vision with <strong>HALCON</strong>.<br />

What makes <strong>HALCON</strong> very powerful in the area of 3D measurements is its ability to model the whole<br />

imaging process in 3D with the camera calibration. Among other things, this allows to transform the<br />

image processing results into arbitrary 3D coordinate systems and with this to derive metrical information<br />

from the images, regardless of the position and orientation of the camera with respect to the object.<br />

In general, no 3D measurements are possible if only one image of the object is available. But nevertheless,<br />

by using <strong>HALCON</strong>’s camera calibration you can perform inspection tasks in 3D coordinates in<br />

specified object planes (section 3 on page 27). These planes can be oriented arbitrarily with respect to<br />

the camera. This is, e.g., useful if the camera cannot be mounted such that it looks perpendicular to the<br />

object surface. In any case, you can perform the image processing in the original images. Afterwards,<br />

the results can be transformed into 3D coordinates.<br />

It is also possible to rectify the images such that they appear as if they were acquired from a camera<br />

that has no lens distortions and that looks exactly perpendicular onto the object surface (section 3.3 on<br />

page 49). This is useful for tasks like OCR or the recognition and localization of objects, which rely on<br />

images that are not distorted too much with respect to the training images.<br />

If the object is too large to be covered by one image with the desired resolution, multiple images, each<br />

covering only a part of the object, can be combined into one larger mosaic image. This can be done either<br />

based on a calibrated camera setup with very high precision (section 4 on page 59) or highly automated<br />

for arbitrary and even varying image configurations (section 5 on page 69).<br />

The position and orientation of 3D objects with respect to a given 3D coordinate system can be determined<br />

with the <strong>HALCON</strong> camera calibration (section 6 on page 84). This is, e.g., necessary for<br />

pick-and-place applications.<br />

If you need to determine the 3D shape of arbitrary objects, you can use <strong>HALCON</strong>’s binocular stereo<br />

vision functionality (section 7 on page 88). The 3D coordinates of any point on the object surface can<br />

be determined based on two images that are acquired suitably from different points of view. Thus, 3D<br />

inspection becomes possible.<br />

A typical application area for 3D machine vision is robot vision, i.e., using the results of machine vision<br />

to command a robot. In such applications you must perform an additional calibration: the so-called<br />

hand-eye calibration, which determines the relation between camera and robot coordinates. Again, this<br />

calibration must be performed only once (offline), its results allow you to quickly transform machine<br />

vision results from camera into robot coordinates.<br />

Thus, we can answer the question that was posed at the beginning: Yes, you can perform 3D machine<br />

vision with <strong>HALCON</strong>, but you have to calibrate your camera first. Don’t be afraid of the calibration<br />

process: In <strong>HALCON</strong>, this can be done with just a few lines of code.<br />

What is more, if you want to achieve accurate results it is essential to calibrate the camera. It is of no use<br />

to extract edges with an accuracy of 1/40 pixel if the lens distortion of the uncalibrated camera accounts<br />

for a couple of pixels. This also applies if you use cameras with telecentric lenses.<br />

We propose to read section 2.2 on page 19 first, as the camera model is described there. Then, depending<br />

on the task at hand, you can step into the appropriate section. To find this section, you can use the<br />

Introduction


6 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

overview given in figure 1 and figure 2. For details on 3D transformations and poses, please refer to<br />

section 2.1 on page 8.<br />

High-precision 3D<br />

measurements from<br />

images<br />

✲ Object with planar<br />

surfaces<br />

✲ Object with arbitrary<br />

surface<br />

Determine the position<br />

✲ and orientation of<br />

known 3D objects<br />

✲ Robot vision<br />

✲ Object fits into one<br />

image<br />

Object is too large to<br />

✲ be covered by one<br />

image<br />

✲ section 3 on page 27<br />

✲ section 4 on page 59<br />

✲ section 7 on page 88<br />

✲ section 6 on page 84<br />

✲ section 8 on page 109<br />

Figure 1: How to find the appropriate section of this application note (part 1).


Rectification of<br />

distorted images<br />

Transformation of 3D<br />

coordinates into<br />

images for ROI<br />

definition or<br />

visualization<br />

Combination of<br />

images into a larger<br />

mosaic image<br />

✲ Correction for lens<br />

distortion only<br />

✲ Images of objects with<br />

planar surfaces<br />

✲ Images of objects with<br />

arbitrary surfaces<br />

✲ For high-precision<br />

measurement tasks<br />

✲ Flexible and highly<br />

automated<br />

1 Can You Really Perform 3D Machine Vision with <strong>HALCON</strong>? 7<br />

✲ Object fits into one<br />

image<br />

Object is too large to<br />

✲ be covered by one<br />

image<br />

✲ section 3.3.2 on page<br />

55<br />

✲ section 3.3.1 on page<br />

49<br />

✲ section 4 on page 59<br />

✲ section 9 on page 123<br />

✲ section 3.2.5 on page<br />

47<br />

✲ section 4 on page 59<br />

✲ section 5 on page 69<br />

Figure 2: How to find the appropriate section of this application note (part 2).<br />

Introduction


8 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

2 Basics<br />

2.1 3D Transformations and Poses<br />

Before we start explaining how to perform machine vision in world coordinates with <strong>HALCON</strong>, we take<br />

a closer look at some basic questions regarding the use of 3D coordinates:<br />

• How to describe the transformation (translation and rotation) of points and coordinate systems,<br />

• how to describe the position and orientation of one coordinate system relative to another, and<br />

• how to determine the coordinates of a point in different coordinate systems, i.e., how to transform<br />

coordinates between coordinate systems.<br />

In fact, all these tasks can be solved using one and the same means: homogeneous transformation matrices<br />

and their more compact equivalent, 3D poses.<br />

2.1.1 3D Coordinates<br />

The position of a 3D point P is described by its three coordinates (xp, yp, zp). The coordinates can<br />

also be interpreted as a 3D vector (indicated by a bold-face lower-case letter). The coordinate system<br />

in which the point coordinates are given is indicated to the upper right of a vector or coordinate. For<br />

example, the coordinates of the point P in the camera coordinate system (denoted by the letter c) and in<br />

the world coordinate system (denoted by the letter w) would be written as:<br />

⎛<br />

p c = ⎝<br />

x c p<br />

y c p<br />

z c p<br />

⎞<br />

⎛<br />

⎠ p w = ⎝<br />

Figure 3 depicts an example point lying in a plane where measurements are to be performed and its<br />

coordinates in the camera and world coordinate system, respectively.<br />

Measurement plane<br />

x c y c z c Camera coordinate system<br />

( , , )<br />

p =<br />

c<br />

0<br />

2<br />

4<br />

c<br />

y<br />

P<br />

p =<br />

w<br />

z c<br />

4<br />

3.3<br />

0<br />

x c<br />

x w<br />

x w p<br />

y w p<br />

z w p<br />

z w<br />

y w<br />

⎞<br />

⎠<br />

x w y w z w World coordinate system<br />

( , , )<br />

Figure 3: Coordinates of a point in two different coordinate systems.


2.1.2 Translation<br />

Translation of Points<br />

In figure 4, our example point has been translated along the x-axis of the camera coordinate system.<br />

x c y c z c ( , , )<br />

x c<br />

Camera coordinate system<br />

c<br />

y<br />

z c<br />

p = 1<br />

0<br />

2<br />

4<br />

p = 2<br />

P1<br />

t =<br />

4<br />

0<br />

0<br />

P2<br />

Figure 4: Translating a point.<br />

4<br />

2<br />

4<br />

2.1.2 Translation 9<br />

The coordinates of the resulting point P2 can be calculated by adding two vectors, the coordinate vector<br />

p1 of the point and the translation vector t:<br />

⎛<br />

p2 = p1 + t = ⎝<br />

xp1 + xt<br />

yp1 + yt<br />

zp1 + zt<br />

⎞<br />

⎠ (1)<br />

Multiple translations are described by adding the translation vectors. This operation is commutative, i.e.,<br />

the sequence of the translations has no influence on the result.<br />

Translation of Coordinate Systems<br />

Coordinate systems can be translated just like points. In the example in figure 5, the coordinate system<br />

c1 is translated to form a second coordinate system, c2. Then, the position of c2 in c1, i.e., the coordinate<br />

vector of its origin relative to c1 (o c1<br />

c2<br />

Coordinate Transformations<br />

), is identical to the translation vector:<br />

t c1 = o c1<br />

c2<br />

Let’s turn to the question how to transform point coordinates between (translated) coordinate systems.<br />

In fact, the translation of a point can also be thought of as translating it together with its local coordinate<br />

system. This is depicted in figure 5: The coordinate system c1, together with the point Q1, is translated<br />

(2)<br />

Basics


10 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Coordinate system 1<br />

x c1 ( ,<br />

y , c1 z c1 )<br />

1<br />

c1<br />

q =<br />

c1<br />

y<br />

0<br />

0<br />

4<br />

z c1<br />

Q<br />

2<br />

c1<br />

q =<br />

1<br />

t =<br />

c2<br />

y<br />

2<br />

0<br />

6<br />

2<br />

0<br />

2<br />

x c1<br />

2<br />

z c2<br />

2<br />

c2<br />

q =<br />

x c2 y c2 z c2<br />

Coordinate system 2<br />

( , , )<br />

x c2<br />

Figure 5: Translating a coordinate system (and point).<br />

by the vector t, resulting in the coordinate system c2 and the point Q2. The points Q1 and Q2 then have<br />

the same coordinates relative to their local coordinate system, i.e., q c1<br />

1<br />

Q<br />

0<br />

0<br />

4<br />

= qc2<br />

2 .<br />

If coordinate systems are only translated relative to each other, coordinates can be transformed very<br />

easily between them by adding the translation vector:<br />

q c1<br />

2<br />

= qc2 2 + tc1 = q c2<br />

2 + oc1<br />

c2<br />

In fact, figure 5 visualizes this equation: q c1<br />

2 , i.e., the coordinate vector of Q2 in the coordinate system<br />

c1, is composed by adding the translation vector t and the coordinate vector of Q2 in the coordinate<br />

system c2 (q c2<br />

2 ).<br />

The downside of this graphical notation is that, at first glance, the direction of the translation vector<br />

appears to be contrary to the direction of the coordinate transformation: The vector points from the<br />

coordinate system c1 to c2, but transforms coordinates from the coordinate system c2 to c1. According<br />

to this, the coordinates of Q1 in the coordinate system c2, i.e., the inverse transformation, can be obtained<br />

by subtracting the translation vector from the coordinates of Q1 in the coordinate system c1:<br />

Summary<br />

q c2<br />

1<br />

= qc1 1 − tc1 = q c1<br />

1 − oc1<br />

c2<br />

• Points are translated by adding the translation vector to their coordinate vector. Analogously, coordinate<br />

systems are translated by adding the translation vector to the position (coordinate vector)<br />

of their origin.<br />

• To transform point coordinates from a translated coordinate system c2 into the original coordinate<br />

system c1, you apply the same transformation to the points that was applied to the coordinate<br />

system, i.e., you add the translation vector used to translate the coordinate system c1 into c2.<br />

(3)<br />

(4)


2.1.3 Rotation 11<br />

• Multiple translations are described by adding all translation vectors; the sequence of the translations<br />

does not affect the result.<br />

2.1.3 Rotation<br />

Rotation of Points<br />

In figure 6a, the point p1 is rotated by −90 ◦ around the z-axis of the camera coordinate system.<br />

p =<br />

1<br />

0<br />

2<br />

4<br />

c<br />

y<br />

z c<br />

c<br />

x<br />

P<br />

3<br />

p =<br />

P R (−90°)<br />

P<br />

1 z<br />

1<br />

3<br />

2<br />

0<br />

4<br />

p =<br />

a) first rotation b) second rotation<br />

1<br />

0<br />

2<br />

4<br />

c<br />

y<br />

z c<br />

p =<br />

4<br />

x c<br />

p =<br />

Figure 6: Rotate a point: (a) first around z-axis; (b) then around y-axis.<br />

3<br />

4<br />

0<br />

−2<br />

P<br />

R (90°)<br />

Rotating a point is expressed by multiplying its coordinate vector with a 3 × 3 rotation matrix R. A<br />

rotation around the z-axis looks as follows:<br />

⎡<br />

p3 = Rz(γ) · p1 = ⎣<br />

cos γ − sin γ 0<br />

sin γ cos γ 0<br />

0 0 1<br />

⎤<br />

⎛<br />

⎦ · ⎝<br />

xp1<br />

yp1<br />

zp1<br />

⎞<br />

⎛<br />

⎠ = ⎝<br />

3<br />

y<br />

2<br />

0<br />

4<br />

cos γ · xp1 − sin γ · yp1<br />

sin γ · xp1 + cos γ · yp1<br />

Rotations around the x- and y-axis correspond to the following rotation matrices:<br />

⎡<br />

Ry(β) = ⎣<br />

cos β<br />

0<br />

0<br />

1<br />

sin β<br />

0<br />

⎤<br />

⎦<br />

⎡<br />

1<br />

Rx(α) = ⎣ 0<br />

0<br />

cos α<br />

0<br />

− sin α<br />

− sin β 0 cos β<br />

0 sin α cos α<br />

Chain of Rotations<br />

zp1<br />

⎤<br />

P<br />

4<br />

⎞<br />

⎠ (5)<br />

⎦ (6)<br />

In figure 6b, the rotated point is further rotated around the y-axis. Such a chain of rotations can be<br />

expressed very elegantly by a chain of rotation matrices:<br />

p4 = Ry(β) · p3 = Ry(β) · Rz(γ) · p1<br />

<strong>Note</strong> that in contrast to a multiplication of scalars, the multiplication of matrices is not commutative, i.e.,<br />

if you change the sequence of the rotation matrices, you get a different result.<br />

(7)<br />

Basics


12 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Rotation of Coordinate Systems<br />

In contrast to points, coordinate systems have an orientation relative to other coordinates systems. This<br />

orientation changes when the coordinate system is rotated. For example, in figure 7a the coordinate system<br />

c3 has been rotated around the y-axis of the coordinate system c1, resulting in a different orientation<br />

of the camera. <strong>Note</strong> that in order to rotate a coordinate system in your mind’s eye, it may help to image<br />

the points of the axis vectors being rotated.<br />

Coordinate system 1<br />

x c1 ( ,<br />

y , c1 z c1 )<br />

1<br />

c1<br />

0<br />

0<br />

4<br />

1<br />

y<br />

x<br />

z<br />

c3 y c3 z c3<br />

Coordinate system 3<br />

( , , )<br />

4<br />

4<br />

0<br />

x 0<br />

3<br />

4<br />

0<br />

0<br />

3<br />

4 3<br />

0<br />

0<br />

0<br />

0<br />

3<br />

4<br />

4<br />

4<br />

c4 x c3<br />

x c3<br />

z c1<br />

x c1<br />

z c3<br />

c4<br />

y<br />

z c1<br />

q =<br />

c3<br />

q =<br />

Q<br />

c1<br />

z c4<br />

z c3<br />

c3<br />

c3<br />

y y<br />

c1<br />

c1<br />

q =<br />

y<br />

y<br />

c4<br />

q =<br />

c1<br />

Q = Q<br />

q =<br />

Q<br />

R (90°) R (−90°)<br />

1<br />

c1<br />

q =<br />

a) first rotation b) second rotation<br />

0<br />

0<br />

4<br />

Q<br />

1<br />

x c4 y c4 z c4<br />

Coordinate system 4<br />

( , , )<br />

Figure 7: Rotate coordinate system with point: (a) first around z-axis; (b) then around y-axis.<br />

Just like the position of a coordinate system can be expressed directly by the translation vector (see<br />

equation 2 on page 9), the orientation is contained in the rotation matrix: The columns of the rotation<br />

matrix correspond to the axis vectors of the rotated coordinate system in coordinates of the original one:<br />

R = � x c1<br />

c3<br />

For example, the axis vectors of the coordinate system c3 in figure 7a can be determined from the<br />

corresponding rotation matrix Ry(90◦ ) as shown in the following equation; you can easily check the<br />

result in the figure.<br />

⎡<br />

Ry(90◦ ) = ⎣<br />

⇒ x c1<br />

c3 =<br />

yc1<br />

c3<br />

z c1<br />

c3<br />

cos(90 ◦ ) 0 sin(90 ◦ )<br />

0 1 0<br />

− sin(90 ◦ ) 0 cos(90 ◦ )<br />

⎛<br />

⎝ 0<br />

0<br />

−1<br />

⎞<br />

⎠ y c1<br />

c3 =<br />

⎛<br />

⎝<br />

0<br />

1<br />

0<br />

⎤<br />

�<br />

⎡<br />

⎦ = ⎣<br />

⎞<br />

⎠ z c1<br />

c3 =<br />

0 0 1<br />

0 1 0<br />

−1 0 0<br />

⎛<br />

⎝<br />

1<br />

0<br />

0<br />

⎞<br />

⎠<br />

⎤<br />

⎦<br />

(8)


Coordinate Transformations<br />

2.1.3 Rotation 13<br />

Like in the case of translation, to transform point coordinates from a rotated coordinate system c3 into<br />

the original coordinate system c1, you apply the same transformation to the points that was applied to<br />

the coordinate system c3, i.e., you multiply the point coordinates with the rotation vector used to rotate<br />

the coordinate system c1 into c3:<br />

q c1<br />

3 = c1 Rc3 ·q c3<br />

3<br />

This is depicted in figure 7 also for a chain of rotations, which corresponds to the following equation:<br />

q c1<br />

4 = c1 Rc3 · c3 Rc4 ·q c4<br />

4 = Ry(β) · Rz(γ) · q c4<br />

4 = c1 Rc4 ·q c4<br />

4<br />

In Which Sequence and Around Which Axes are Rotations Performed?<br />

If you compare the chains of rotations in figure 6 and figure 7 and the corresponding equations 7 and<br />

10, you will note that two different sequences of rotations are described by the same chain of rotation<br />

matrices: In figure 6, the point was rotated first around the z-axis and then around the y-axis, whereas in<br />

figure 7 the coordinate system is rotated first around the y-axis and then around the z-axis. Yet, both are<br />

described by the chain Ry(β) · Rz(γ)!<br />

The solution to this seemingly paradox situation is that in the two examples the chain of rotation matrices<br />

can be “read” in different directions: In figure 6 it is read from the right to left, and in figure 7 from left<br />

to the right.<br />

However, there still must be a difference between the two sequences because, as we already mentioned,<br />

the multiplication of rotation matrices is not commutative. This difference lies in the second question in<br />

the title, i.e., around which axes the rotations are performed.<br />

Performing a chain of rotations:<br />

x c1<br />

y<br />

R y (90°) * R z (−90°)<br />

a) reading from left to right = rotating around "new" axes<br />

c1<br />

y<br />

z c1<br />

c1<br />

R (90°)<br />

c3’<br />

y<br />

x c3’<br />

b) reading from right to left = rotating around "old" axes<br />

c1<br />

y<br />

z c1<br />

x c1<br />

c1<br />

y<br />

z c3’<br />

c1<br />

c1<br />

R z (−90°)<br />

c3 y<br />

z c3<br />

x c3<br />

y<br />

R (−90°)<br />

z<br />

R (90°)<br />

c4<br />

y x c4<br />

c4<br />

y x c4<br />

Figure 8: Performing a chain of rotations (a) from left to the right, or (b) from right to left.<br />

c3’<br />

z c4<br />

z c4<br />

(9)<br />

(10)<br />

Basics


14 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Let’s start with the second rotation of the coordinate system in figure 7b. Here, there are two possible<br />

sets of axes to rotate around: those of the “old” coordinate system c1 and those of the already rotated,<br />

“new” coordinate system c3. In the example, the second rotation is performed around the “new” z-axis.<br />

In contrast, when rotating points as in figure 6, there is only one set of axes around which to rotate: those<br />

of the “old” coordinate system.<br />

From this, we derive the following rules:<br />

• When reading a chain from the left to right, rotations are performed around the “new” axes.<br />

• When reading a chain from the right to left, rotations are performed around the “old” axes.<br />

As already remarked, point rotation chains are always read from right to left. In the case of coordinate<br />

systems, you have the choice how to read a rotation chain. In most cases, however, it is more intuitive to<br />

read them from left to right.<br />

Figure 8 shows that the two reading directions really yield the same result.<br />

Summary<br />

• Points are rotated by multiplying their coordinate vector with a rotation matrix.<br />

• If you rotate a coordinate system, the rotation matrix describes its resulting orientation: The column<br />

vectors of the matrix correspond to the axis vectors of the rotated coordinate system in coordinates<br />

of the original one.<br />

• To transform point coordinates from a rotated coordinate system c3 into the original coordinate<br />

system c1, you apply the same transformation to the points that was applied to the coordinate<br />

system, i.e., you multiply them with the rotation matrix that was used to rotate the coordinate<br />

system c1 into c3.<br />

• Multiple rotations are described by a chain of rotation matrices, which can be read in two directions.<br />

When read from left to right, rotations are performed around the “new” axes; when read<br />

from right to left, the rotations are performed around the “old” axes.<br />

2.1.4 Rigid Transformations and Homogeneous Transformation Matrices<br />

Rigid Transformation of Points<br />

If you combine translation and rotation, you get a so-called rigid transformation. For example, in figure 9,<br />

the translation and rotation of the point from figures 4 and 6 are combined. Such a transformation is<br />

described as follows:<br />

p5 = R ·p1 + t (11)<br />

For multiple transformations, such equations quickly become confusing, as the following example with<br />

two transformations shows:<br />

p6 = Ra ·(Rb ·p1 + tb) + ta = Ra · Rb ·p1 + Ra ·tb + ta<br />

(12)


p =<br />

1<br />

2.1.4 Rigid Transformations and Homogeneous Transformation Matrices 15<br />

0<br />

2<br />

4<br />

c<br />

y<br />

P<br />

1<br />

z c<br />

z<br />

4 4 −2 0<br />

4<br />

p = P<br />

x c<br />

R (−90°)<br />

P<br />

3<br />

p =<br />

3<br />

2<br />

0<br />

4<br />

y<br />

t =<br />

R (90°)<br />

Figure 9: Combining the translation from figure 4 on page 9 and the rotation of figure 6 on page 11 to form<br />

a rigid transformation.<br />

An elegant alternative is to use so-called homogeneous transformation matrices and the corresponding<br />

homogeneous vectors. A homogeneous transformation matrix H contains both the rotation matrix and<br />

the translation vector. For example, the rigid transformation from equation 11 can be rewritten as follows:<br />

� p5<br />

1<br />

�<br />

=<br />

� R t<br />

0 0 0 1<br />

� �<br />

p1<br />

·<br />

1<br />

�<br />

=<br />

� R ·p1 + t<br />

1<br />

4<br />

0<br />

0<br />

P<br />

5<br />

p =<br />

5<br />

�<br />

= H ·p1<br />

The usefulness of this notation becomes apparent when dealing with sequences of rigid transformations,<br />

which can be expressed as chains of homogeneous transformation matrices, similarly to the rotation<br />

chains:<br />

H1 · H2 =<br />

� Ra ta<br />

0 0 0 1<br />

� �<br />

Rb tb<br />

·<br />

0 0 0 1<br />

� �<br />

Ra · Rb<br />

=<br />

Ra ·tb + ta<br />

0 0 0 1<br />

As explained for chains of rotations, chains of rigid transformation can be read in two directions. When<br />

reading from left to right, the transformations are performed around the “new” axes, when read from<br />

right to left around the “old” axes.<br />

In fact, a rigid transformation is already a chain, since it consists of a translation and a rotation:<br />

�<br />

R<br />

H =<br />

0 0 0<br />

t<br />

1<br />

⎡<br />

�<br />

⎢<br />

= ⎢<br />

⎣<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

t<br />

⎤<br />

⎥<br />

⎦<br />

0 0 0 1<br />

·<br />

⎡<br />

⎢<br />

⎣ R<br />

0<br />

0<br />

0<br />

⎤<br />

⎥<br />

⎦ = H(t) · H(R) (15)<br />

0 0 0 1<br />

If the rotation is composed of multiple rotations around axes as in figure 9, the individual rotations can<br />

8<br />

0<br />

−2<br />

�<br />

(13)<br />

(14)<br />

Basics


16 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

also be written as homogeneous transformation matrices:<br />

H =<br />

�<br />

Ry(β) · Rz(γ)<br />

0 0 0<br />

t<br />

1<br />

⎡<br />

�<br />

⎢<br />

= ⎢<br />

⎣<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

t<br />

⎤<br />

⎥<br />

⎦<br />

0 0 0 1<br />

·<br />

⎡<br />

⎢<br />

⎣ Ry(β)<br />

0<br />

0<br />

0<br />

0 0 0 1<br />

⎤<br />

⎥<br />

⎦ ·<br />

⎡<br />

⎢<br />

⎣ Rz(γ)<br />

0<br />

0<br />

0<br />

0 0 0 1<br />

Reading this chain from right to left, you can follow the transformation of the point in figure 9: First, it<br />

is rotated around the z-axis, then around the (“old”) y-axis, and finally it is translated.<br />

Rigid Transformation of Coordinate Systems<br />

Rigid transformations of coordinate systems work along the same lines as described for a separate translation<br />

and rotation. This means that the homogeneous transformation matrix c1 Hc5 describes the transformation<br />

of the coordinate system c1 into the coordinate system c5. At the same time, it describes the<br />

position and orientation of coordinate system c5 relative to coordinate system c1: Its column vectors<br />

contain the coordinates of the axis vectors and the origin.<br />

c1 Hc5 =<br />

� x c1<br />

c5<br />

yc1<br />

c5<br />

z c1<br />

c5<br />

o c1<br />

c5<br />

0 0 0 1<br />

As already noted for rotations, chains of rigid transformations of coordinate systems are typically read<br />

from left to right. Thus, the chain above can be read as first translating the coordinate system, then<br />

rotating it around its “new” y-axis, and finally rotating it around its “newest” z-axis.<br />

Coordinate Transformations<br />

As described for the separate translation and the rotation, to transform point coordinates from a rigidly<br />

transformed coordinate system c5 into the original coordinate system c1, you apply the same transformation<br />

to the points that was applied to the coordinate system c5, i.e., you multiply the point coordinates<br />

with the homogeneous transformation matrix:<br />

� p c1<br />

5<br />

1<br />

�<br />

= c1 � c5 p<br />

Hc5 · 5<br />

1<br />

Typically, you leave out the homogeneous vectors if there is no danger of confusion and simply write:<br />

Summary<br />

p c1<br />

5 = c1 Hc5 ·p c5<br />

5<br />

• Rigid transformations consist of a rotation and a translation. They are described very elegantly by<br />

homogeneous transformation matrices, which contain both the rotation matrix and the translation<br />

vector.<br />

• Points are transformed by multiplying their coordinate vector with the homogeneous transformation<br />

matrix.<br />

�<br />

�<br />

⎤<br />

⎥<br />

⎦<br />

(16)<br />

(17)<br />

(18)


2.1.5 3D Poses 17<br />

• If you transform a coordinate system, the homogeneous transformation matrix describes the coordinate<br />

system’s resulting position and orientation: The column vectors of the matrix correspond to<br />

the axis vectors and the origin of the coordinate system in coordinates of the original one. Thus,<br />

you could say that a homogeneous transformation matrix “is” the position and orientation of a<br />

coordinate system.<br />

• To transform point coordinates from a rigidly transformed coordinate system c5 into the original<br />

coordinate system c1, you apply the same transformation to the points that was applied to the<br />

coordinate system, i.e., you multiply them with the homogeneous transformation matrix that was<br />

used to transform the coordinate system c1 into c5.<br />

• Multiple rigid transformations are described by a chain of transformation matrices, which can be<br />

read in two directions. When read from left to the right, rotations are performed around the “new”<br />

axes; when read from the right to left, the transformations are performed around the “old” axes.<br />

<strong>HALCON</strong> Operators<br />

As we already anticipated at the beginning of section 2.1 on page 8, homogeneous transformation matrices<br />

are the answer to all our questions regarding the use of 3D coordinates. Because of this, they form the<br />

basis for <strong>HALCON</strong>’s operators for 3D transformations. Below, you find a brief overview of the relevant<br />

operators. For more details follow the links into the Reference Manual.<br />

• hom_mat3d_identity creates the identical transformation<br />

• hom_mat3d_translate translates along the “old” axes: H2 = H(t) · H1<br />

• hom_mat3d_translate_local translates along the “new” axes: H2 = H1 · H(t)<br />

• hom_mat3d_rotate rotates around the “old” axes: H2 = H(R) · H1<br />

• hom_mat3d_rotate_local rotates around the “new” axes: H2 = H1 · H(R)<br />

• hom_mat3d_compose multiplies two transformation matrices: H3 = H1 · H2<br />

• hom_mat3d_invert inverts a transformation matrix: H2 = H1 -1<br />

• affine_trans_point_3d transforms a point using a transformation matrix: p2 = H0 ·p1<br />

2.1.5 3D Poses<br />

Homogeneous transformation matrices are a very elegant means of describing transformations, but their<br />

content, i.e., the elements of the matrix, are often difficult to read, especially the rotation part. This<br />

problem is alleviated by using so-called 3D poses.<br />

A 3D pose is nothing more than an easier-to-understand representation of a rigid transformation:<br />

Instead of the 12 elements of the homogeneous transformation matrix, a pose describes<br />

the rigid transformation with 6 parameters, 3 for the rotation and 3 for the translation:<br />

(TransX, TransY, TransZ, RotX, RotY, RotZ). The main principle behind poses is that even a rotation<br />

around an arbitrary axis can always be represented by a sequence of three rotations around the axes<br />

of a coordinate system.<br />

In <strong>HALCON</strong>, you create 3D poses with create_pose; to transform between poses and homogeneous<br />

matrices you can use hom_mat3d_to_pose and pose_to_hom_mat3d.<br />

Basics


18 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Sequence of Rotations<br />

However, there is more than one way to represent an arbitrary rotation by three parameters. This is<br />

reflected by the <strong>HALCON</strong> operator create_pose, which lets you choose between different pose types<br />

with the parameter OrderOfRotation. If you pass the value ’gba’, the rotation is described by the<br />

following chain of rotations:<br />

Rgba = Rx(RotX) · Ry(RotY) · Rz(RotZ) (19)<br />

You may also choose the inverse order by passing the value ’abg’:<br />

Rabg = Rz(RotZ) · Ry(RotY) · Rx(RotX) (20)<br />

For example, the transformation discussed in the previous sections can be represented by the homogeneous<br />

transformation matrix<br />

�<br />

Ry(β) · Rz(γ)<br />

H =<br />

0 0 0<br />

⎡<br />

� cos β · cos γ<br />

t ⎢<br />

= ⎢ sin γ<br />

1 ⎣ − sin β · cos γ<br />

− cos β · sin γ<br />

cos γ<br />

sin β · sin γ<br />

sin β<br />

0<br />

cos β<br />

xt<br />

yt<br />

zt<br />

⎤<br />

⎥<br />

⎦<br />

0 0 0 1<br />

The corresponding pose with the rotation order ’gba’ is much easier to read:<br />

(TransX = xt, TransY = yt, TransZ = zt, RotX = 0, RotY = 90 ◦ , RotZ = 90 ◦ )<br />

If you look closely at figure 7 on page 12, you can see that the rotation can also be described by the<br />

sequence Rz(90 ◦ ) · Rx(90 ◦ ). Thus, the transformation can also be described by the following pose with<br />

the rotation order ’abg’:<br />

(TransX = xt, TransY = yt, TransZ = zt, RotX = 90 ◦ , RotY = 0, RotZ = 90 ◦ )<br />

<strong>HALCON</strong> Operators<br />

Below, the relevant <strong>HALCON</strong> operators for dealing with 3D poses are briefly described. For more details<br />

follow the links into the Reference Manual.<br />

• create_pose creates a pose<br />

• hom_mat3d_to_pose converts a homogeneous transformation matrix into a pose<br />

• pose_to_hom_mat3d converts a pose into a homogeneous transformation matrix<br />

• convert_pose_type changes the pose type<br />

• write_pose writes a pose into a file<br />

• read_pose reads a pose from a file<br />

• set_origin_pose translates a pose along its “new” axes


How to Determine the Pose of a Coordinate System<br />

2.2 Camera Model and Parameters 19<br />

The previous sections showed how to describe known transformations using translation vectors, rotations<br />

matrices, homogeneous transformation matrices, or poses. Sometimes, however, there is another task:<br />

How to describe the position and orientation of a coordinate system with a pose. This is necessary, e.g.,<br />

when you want to use your own calibration object and need to determine starting values for the exterior<br />

camera parameters as described in section 3.1.3 on page 32.<br />

Figure 10 shows how to proceed for a rather simple example. The task is to determine the pose of the<br />

world coordinate system from figure 3 on page 8 relative to the camera coordinate system.<br />

4<br />

c’<br />

Camera coordinate system t = −1.3 Intermediate coordinate system R y (180°) World coordinate system<br />

4<br />

c<br />

y<br />

x c y c z c ( , , )<br />

z c<br />

x c<br />

x w<br />

z w<br />

y w<br />

c<br />

y<br />

( x , , c’ y c’ z c’ )<br />

z c<br />

x c<br />

x w<br />

z w<br />

y<br />

c’<br />

y<br />

w<br />

c’<br />

z<br />

x c’<br />

c<br />

y<br />

c<br />

P w =<br />

z c<br />

x c<br />

x w y w z w ( , , )<br />

x w=c<br />

y w=c<br />

(4, −1.3, 4, 0, 180°, 0)<br />

Figure 10: Determining the pose of the world coordinate system in camera coordinates.<br />

In such a case, we recommend to build up the rigid transformation from individual translations and<br />

rotations from left to right. Thus, in figure 10 the camera coordinate system is first translated such that<br />

its origin coincides with that of the world coordinate system. Now, the y-axes of the two coordinate<br />

systems coincide; after rotating the (translated) camera coordinate system around its (new) y-axis by<br />

180 ◦ , it has the correct orientation.<br />

2.2 Camera Model and Parameters<br />

If you want to derive accurate world coordinates from your imagery, you first have to calibrate your<br />

camera. To calibrate a camera, a model for the mapping of the 3D points of the world to the 2D image<br />

generated by the camera, lens, and frame grabber is necessary.<br />

<strong>HALCON</strong> supports the calibration of two different kinds of cameras: area scan cameras and line scan<br />

cameras. While area scan cameras aquire the image in one step, line scan cameras generate the image<br />

line by line (see <strong>Application</strong> <strong>Note</strong> on Image Acquisition, section 6.3 on page 34). Therefore, the line<br />

scan camera must move relative to the object during the acquisition process.<br />

Two different types of lenses are relevant for machine vision tasks. The first type of lens effects a<br />

perspective projection of the world coordinates into the image, just like the human eye does. With this<br />

type of lens, objects become smaller in the image the farther they are away from the camera. This<br />

combination of camera and lens is called a pinhole camera model because the perspective projection can<br />

z w=c<br />

Basics


20 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

also be achieved if a small hole is drilled in a thin planar object and this plane is held parallel in front of<br />

another plane (the image plane).<br />

The second type of lens that is relevant for machine vision is called a telecentric lens. Its major difference<br />

is that it effects a parallel projection of the world coordinates onto the image plane (for a certain range<br />

of distances of the object from the camera). This means that objects have the same size in the image<br />

independent of their distance to the camera. This combination of camera and lens is called a telecentric<br />

camera model.<br />

In the following, first the camera model for area scan cameras is described in detail, then, the camera<br />

model for line scan cameras is explained.<br />

2.2.1 Area scan cameras<br />

Figure 11 displays the perspective projection effected by a pinhole camera graphically. The world point<br />

P is projected through the optical center of the lens to the point P ′ in the image plane, which is located<br />

at a distance of f (the focal length) behind the optical center. Actually, the term focal length is not<br />

quite correct and would be appropriate only for an infinite object distance. To simplify matters, in the<br />

following always the term focal length is used even if the image distance is meant. <strong>Note</strong> that the<br />

focal length and thus the focus must not be changed after applying the camera calibration.<br />

Although the image plane in reality lies behind the optical center of the lens, it is easier to pretend that<br />

it lies at a distance of f in front of the optical center, as shown in figure 12. This causes the image<br />

coordinate system to be aligned with the pixel coordinate system (row coordinates increase downward<br />

and column coordinates to the right) and simplifies most calculations.<br />

With this, we are now ready to describe the projection of objects in 3D world coordinates to the 2D<br />

image plane and the corresponding camera parameters. First, we should note that the points P are given<br />

in a world coordinate system (WCS). To make the projection into the image plane possible, they need<br />

to be transformed into the camera coordinate system (CCS). The CCS is defined so that its x and y axes<br />

are parallel to the column and row axes of the image, respectively, and the z axis is perpendicular to the<br />

image plane.<br />

The transformation from the WCS to the CCS is a rigid transformation, which can be expressed by a pose<br />

or, equivalently, by the homogeneous transformation matrix c Hw . Therefore, the camera coordinates<br />

p c = (x c , y c , z c ) T of point P can be calculated from its world coordinates p w = (x w , y w , z w ) T<br />

simply by<br />

p c = c Hw ·p w<br />

The six parameters of this transformation (the three translations tx, ty, and tz and the three rotations α,<br />

β, and γ) are called the exterior camera parameters because they determine the position of the camera<br />

with respect to the world. In <strong>HALCON</strong>, they are stored as a pose, i.e, together with a code that describes<br />

the order of translation and rotations.<br />

The next step is the projection of the 3D point given in the CCS into the image plane coordinate system<br />

(IPCS). For the pinhole camera model, the projection is a perspective projection, which is given by<br />

� �<br />

u<br />

=<br />

v<br />

f<br />

zc � c x<br />

yc �<br />

(22)<br />

(21)


CCD chip<br />

c<br />

Camera with<br />

optical center<br />

y w<br />

Sx<br />

z w<br />

u<br />

y c<br />

x w<br />

P’<br />

Cx<br />

z c<br />

f<br />

v<br />

C y<br />

x c<br />

Sy<br />

P<br />

r<br />

Image plane coordinate system<br />

Image coordinate system ( r, c)<br />

Figure 11: Perspective projection by a pinhole camera.<br />

2.2.1 Area scan cameras 21<br />

( u, v)<br />

x c y c z c Camera coordinate system ( , , )<br />

x w y w z w<br />

World coordinate system ( , , )<br />

Basics


22 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

y w<br />

r<br />

S y<br />

z w<br />

C<br />

y<br />

y c<br />

v<br />

x w<br />

z c<br />

f<br />

C<br />

P’<br />

x<br />

x c<br />

u<br />

Sx<br />

P<br />

Figure 12: Image plane and virtual image plane.<br />

c<br />

x c y c z c Camera coordinate system ( , , )<br />

Image coordinate system ( r, c)<br />

Image plane coordinate system<br />

( u, v)<br />

x w y w z w<br />

World coordinate system ( , , )<br />

For the telecentric camera model, the projection is a parallel projection, which is given by<br />

� � � c u x<br />

=<br />

v yc �<br />

As can be seen, there is no focal length f for telecentric cameras. Furthermore, the distance z of the<br />

object to the camera has no influence on the image coordinates.<br />

After the projection into the image plane, the lens distortion causes the coordinates (u, v) T to be modified.<br />

If no lens distortions were present, the projected point P ′ would lie on a straight line from P<br />

(23)


2.2.1 Area scan cameras 23<br />

through the optical center, indicated by the dotted line in figure 13. Lens distortions cause the point P ′<br />

to lie at a different position.<br />

CCD chip<br />

Optical center<br />

P’<br />

Figure 13: Schematic illustration of the effect of the lens distortion.<br />

The lens distortion is a transformation that can be modeled in the image plane alone, i.e., 3D information<br />

is unnecessary. For most lenses, the distortion can be approximated sufficiently well by a radial<br />

distortion, which is given by<br />

� �<br />

ũ<br />

=<br />

˜v<br />

2<br />

1 + � 1 − 4κ(u 2 + v 2 )<br />

f<br />

� �<br />

u<br />

v<br />

The parameter κ models the magnitude of the radial distortions. If κ is negative, the distortion is barrelshaped,<br />

while for positive κ it is pincushion-shaped (see figure 14). This model for the lens distortions<br />

has the great advantage that the distortion correction can be calculated analytically by<br />

� �<br />

u<br />

v<br />

=<br />

1<br />

1 + κ(ũ 2 + ˜v 2 )<br />

Finally, the point (ũ, ˜v) T is transformed from the image plane coordinate system into the image coordinate<br />

system (the pixel coordinate system):<br />

⎛<br />

� �<br />

r<br />

= ⎝<br />

c<br />

˜v<br />

Sy<br />

ũ<br />

Sx<br />

+ Cy<br />

+ Cx<br />

� ũ<br />

˜v<br />

⎞<br />

�<br />

P<br />

(24)<br />

(25)<br />

⎠ (26)<br />

Here, Sx and Sy are scaling factors. For pinhole cameras, they represent the horizontal and vertical<br />

distance of the sensors elements on the CCD chip of the camera. For cameras with telecentric lenses,<br />

they represent the size of a pixel in world coordinates (not taking into account the radial distortions).<br />

The point (Cx, Cy) T is the principal point of the image. For pinhole cameras, this is the perpendicular<br />

Basics


24 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Figure 14: Effect of radial distortions for κ > 0 (left), κ = 0 (middle), and κ < 0 (right).<br />

projection of the optical center onto the image plane, i.e., the point in the image from which a ray through<br />

the optical center is perpendicular to the image plane. It also defines the center of the radial distortions.<br />

For telecentric cameras, no optical center exists. Therefore, the principal point is solely defined by the<br />

radial distortions.<br />

The six parameters (f, κ, Sx, Sy, Cx, Cy) of the pinhole camera and the five parameters<br />

(κ, Sx, Sy, Cx, Cy) of the telecentric camera are called the interior camera parameters because they<br />

determine the projection from 3D to 2D performed by the camera.<br />

In <strong>HALCON</strong>, the differentiation among the two camera models (pinhole and telecentric) is done based<br />

on the value of the focal length. If it has a positive value, a pinhole camera with the given focal length is<br />

assumed. If the focal length is set to zero, the telecentric camera model is used.<br />

With this, we can see that camera calibration is the process of determining the interior camera parameters<br />

(f, κ, Sx, Sy, Cx, Cy) and the exterior camera parameters (tx, ty, tz, α, β, γ).<br />

2.2.2 Line scan cameras<br />

A line scan camera has only a one-dimensional line of sensor elements, i.e., to acquire an image, the<br />

camera must move relative to the object (see figure 15). This means that the camera moves over a fixed<br />

object, the object travels in front of a fixed camera, or camera and object are both moving.<br />

The relative motion between the camera and the object is modeled in <strong>HALCON</strong> as part of the interior<br />

camera parameters. In <strong>HALCON</strong>, the following assumptions for this motion are made:<br />

1. the camera moves — relative to the object — with constant velocity along a straight line<br />

2. the orientation of the camera is constant with respect to the object<br />

3. the motion is equal for all images<br />

The motion is described by the motion vector V = (Vx, Vy, Vz) T , which must be given in [meters/scanline]<br />

in the camera coordinate system. The motion vector describes the motion of the camera,<br />

i.e., it assumes a fixed object. In fact, this is equivalent to the assumption of a fixed camera with the<br />

object traveling along −V .


CCD sensor line<br />

Motion vector<br />

⎛ ⎞<br />

⎜ Vx ⎟<br />

⎜ ⎟<br />

⎜ ⎟<br />

⎜ Vy<br />

⎟<br />

⎜ ⎟<br />

⎝ ⎠<br />

Vz<br />

Optical center<br />

Figure 15: Principle of line scan image acquisition.<br />

2.2.2 Line scan cameras 25<br />

The camera coordinate system of line scan cameras is defined as follows (see figure 16 on page 26): The<br />

origin of the coordinate system is the center of projection. The z-axis is identical to the optical axis and<br />

it is directed so that the visible points have positive z coordinates. The y-axis is perpendicular to the<br />

sensor line and to the z-axis. It is directed so that the motion vector has a positive y-component, i.e., if a<br />

fixed object is assumed, the y-axis points in the direction in which the camera is moving. The x-axis is<br />

perpendicular to the y- and z-axis, so that the x-, y-, and z-axis form a right-handed coordinate system.<br />

Similarly to area scan cameras, the projection of a point given in world coordinates into the image is<br />

modeled in two steps: First, the point is transformed into the camera coordinate system. Then, it is<br />

projected into the image.<br />

As the camera moves over the object during the image acquisition, also the camera coordinate system<br />

moves relative to the object, i.e., each image line has been imaged from a different position. This means<br />

that there would be an individual pose for each image line. To make things easier, in <strong>HALCON</strong> all<br />

transformations from world coordinates into camera coordinates and vice versa are based on the pose of<br />

the first image line only. The motion V is taken into account during the projection of the point p c into<br />

the image.<br />

The transformation from the WCS to the CCS of the first image line is a rigid transformation, which can<br />

be expressed by a pose or, equivalently, by the homogeneous transformation matrix c Hw . Therefore,<br />

the camera coordinates pc = (xc , yc , zc ) T of point P can be calculated from its world coordinates<br />

pw = (xw , yw , zw ) T simply by<br />

p c = c Hw ·p w<br />

(27)<br />

The six parameters of this transformation (the three translations tx, ty, and tz and the three rotations α,<br />

β, and γ) are called the exterior camera parameters because they determine the position of the camera<br />

Basics


26 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

y w<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

z w<br />

r s<br />

Cy<br />

x w<br />

Sy<br />

⎛<br />

⎜<br />

⎝<br />

y c<br />

v<br />

−Vx<br />

−Vy<br />

−Vz<br />

z c<br />

⎞<br />

f<br />

⎟<br />

⎠<br />

Cx<br />

P ′<br />

x c<br />

u<br />

Sx<br />

c s<br />

Camera coordinate system (x c , y c , z c )<br />

Sensor line coordinate system (r s , c s )<br />

Image plane coordinate system (u, v)<br />

P<br />

World coordinate system (x w , y w , z w )<br />

Figure 16: Coordinate systems in regard to a line scan camera.<br />

with respect to the world. In <strong>HALCON</strong>, they are stored as a pose, i.e, together with a code that describes<br />

the order of translation and rotations.<br />

For line scan cameras, the projection of the point p c that is given in the camera coordinate system of the<br />

first image line into a (sub-)pixel [r,c] in the image is defined as follows:<br />

Assuming<br />

⎛<br />

p c = ⎝<br />

x<br />

y<br />

z<br />

⎞<br />

⎠ ,<br />

the following set of equations must be solved for m, ũ, and t:<br />

with<br />

m · D · ũ = x − t · Vx<br />

−m · D · pv = y − t · Vy<br />

D =<br />

m · f = z − t · Vz<br />

1<br />

1 + κ(ũ 2 + pv 2 )


3 3D Machine Vision in a Specified Plane With a Single Camera 27<br />

pv = Sy · Cy<br />

This already includes the compensation for radial distortions.<br />

Finally, the point is transformed into the image coordinate system, i.e., the pixel coordinate system:<br />

c = ũ<br />

Sx<br />

+ Cx and r = t<br />

Sx and Sy are scaling factors. Sx represents the distance of the sensor elements on the CCD line, Sy is<br />

the extent of the sensor elements in y-direction. The point (Cx, Cy) T is the principal point. <strong>Note</strong> that<br />

in contrast to area scan images, (Cx, Cy) T does not define the position of the principal point in image<br />

coordinates. It rather describes the relative position of the principal point with respect to the sensor line.<br />

The nine parameters (f, κ, Sx, Sy, Cx, Cy, Vx, Vy, Vz) of the pinhole line scan camera are called the<br />

interior camera parameters because they determine the projection from 3D to 2D performed by the<br />

camera.<br />

As for area scan cameras, the calibration of a line scan camera is the process of determining<br />

the interior camera parameters (f, κ, Sx, Sy, Cx, Cy, Vx, Vy, Vz) and the exterior camera parameters<br />

(tx, ty, tz, α, β, γ) of the first image line.<br />

3 3D Machine Vision in a Specified Plane With a Single Camera<br />

In <strong>HALCON</strong> it is easy to obtain undistorted measurements in world coordinates from images. In general,<br />

this can only be done if two or more images of the same object are taken at the same time with cameras<br />

at different spatial positions. This is the so-called stereo approach; see section 7 on page 88.<br />

In industrial inspection, we often have only one camera available and time constraints do not allow us<br />

to use the expensive process of finding corresponding points in the stereo images (the so-called stereo<br />

matching process).<br />

Nevertheless, it is possible to obtain measurements in world coordinates for objects acquired through<br />

telecentric lenses and objects that lie in a known plane, e.g., on an assembly line, for pinhole cameras.<br />

Both of these tasks can be solved by intersecting an optical ray (also called line of sight) with a plane.<br />

With this, it is possible to measure objects that lie in a plane, even when the plane is tilted with respect to<br />

the optical axis. The only prerequisite is that the camera has been calibrated. In <strong>HALCON</strong>, the calibration<br />

process is very easy as can be seen in the following first example, which introduces the operators that are<br />

necessary for the calibration process.<br />

The easiest way to perform the calibration is to use the <strong>HALCON</strong> standard calibration plates. You just<br />

need to take a few images of the calibration plate (see figure 17 for an example), where in one image the<br />

calibration plate has been placed directly on the measurement plane.<br />

<strong>Note</strong> that the calibration plate has an asymmetrical pattern such that the coordinate system can be<br />

uniquely determined. Older calibration plates do not have this pattern but you can easily add it by<br />

yourself (see appendix A on page 136).<br />

Single Camera


28 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Figure 17: The <strong>HALCON</strong> calibration plate.<br />

After reading in the calibration images, the operators find_caltab and find_marks_and_pose can be<br />

used to detect the calibration plate and to determine the exact positions of the (dark) calibration targets on<br />

it. Additionally, some approximate values are determined, which are necessary for the further processing.<br />

find_caltab (Image, Caltab, CaltabName, SizeGauss, MarkThresh,<br />

MinDiamMarks)<br />

find_marks_and_pose (Image, Caltab, CaltabName, StartCamPar,<br />

StartThresh, DeltaThresh, MinThresh, Alpha,<br />

MinContLength, MaxDiamMarks, RCoord, CCoord,<br />

StartPose)<br />

After collecting the positions of the calibration targets and the approximate values for all the calibration<br />

images, the operator camera_calibration can be called. It determines the interior camera parameters<br />

as well as the pose of the calibration plate in each of the calibration images.<br />

camera_calibration (X, Y, Z, NRow, NCol, StartCamPar, NStartPose, ’all’,<br />

CamParam, NFinalPose, Errors)<br />

Now, you can pick the pose of the calibration plate from the image, where the calibration plate has been<br />

placed on the measurement plane.<br />

Based on this pose, it is easy to transform image coordinates into world coordinates. For example, to<br />

transform point coordinates, the operator image_points_to_world_plane can be used.<br />

image_points_to_world_plane (CamParam, Pose, Row, Col, ’mm’, X1, Y1)<br />

Alternatively, the image can be transformed into the world coordinate system by using the operator<br />

image_to_world_plane (see section 3.3.1 on page 49).<br />

image_to_world_plane (Image, ImageMapped, CamParam, PoseForCenteredImage,<br />

WidthMappedImage, HeightMappedImage,<br />

ScaleForCenteredImage, ’bilinear’)<br />

In the following sections, we will describe the calibration process as well as the transformation between<br />

the image and the world coordinates in detail.


3.1 Calibrating the Camera<br />

3.1 Calibrating the Camera 29<br />

In <strong>HALCON</strong>, area scan cameras as well as line scan cameras can be calibrated. In both cases, the same<br />

operators are used. The differentiation among area scan and line scan cameras is done based on the<br />

number of interior camera parameters. If the interior camera parameters contain the motion vector, a line<br />

scan camera is assumed. Otherwise, the camera model of an area scan camera is used. See section 2.2<br />

on page 19 for the description of the underlying camera models.<br />

As you have seen above, in <strong>HALCON</strong> the calibration is determined simply by using the operator camera_calibration.<br />

Its input can be grouped into two categories:<br />

1. Corresponding points, given in world coordinates as well as in image coordinates<br />

2. Initial values for the camera parameters.<br />

The first category of input parameters requires the location of a sufficiently large number of 3D points in<br />

world coordinates and the correspondence between the world points and their projections in the image.<br />

To define the 3D points in world coordinates, usually objects or marks that are easy to extract, e.g.,<br />

circles or linear grids, are placed into known locations. If the location of a camera must be known with<br />

respect to a given coordinate system, e.g., with respect to the building plan of, say, a factory building,<br />

then each mark location must be measured very carefully within this coordinate system. Fortunately,<br />

in most cases it is sufficient to know the position of a reference object with respect to the camera to<br />

be able to measure the object precisely, since the absolute position of the object in world coordinates is<br />

unimportant. Therefore, we propose to use a <strong>HALCON</strong> calibration plate (figure 18). See section 3.1.6 on<br />

page 43 on how to obtain this calibration plate. You can place it almost anywhere in front of the camera<br />

to determine the camera parameters.<br />

Figure 18: Examples of calibration plates used by <strong>HALCON</strong> .<br />

The determination of the correspondence of the known world points and their projections in the image is<br />

in general a hard problem. The <strong>HALCON</strong> calibration plate is constructed such that this correspondence<br />

can be determined automatically.<br />

Also the second category of input parameters, the starting values, can be determined automatically if the<br />

<strong>HALCON</strong> calibration plate is used.<br />

Single Camera


30 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

The results of the operator camera_calibration are the interior camera parameters and the pose of<br />

the calibration plate in each of the images from which the corresponding points were determined. If the<br />

calibration plate was placed directly on the measurement plane its pose can be used to easily derive the<br />

exterior camera parameters, which are the pose of the measurement plane.<br />

<strong>Note</strong> that the determination of the interior and of the exterior camera parameters can be separated. For<br />

this, the operator camera_calibration must be called twice. First, for the determination of the interior<br />

camera parameters only. Then, for the determination of the exterior camera parameters with the interior<br />

camera parameters remaining unchanged. This may be useful in cases where the measurements should<br />

be carried out in several planes when using a single camera.<br />

In the following, the calibration process is described in detail, especially the determination of the necessary<br />

input values. Additionally, some hints are given on how to obtain precise results.<br />

3.1.1 Camera Calibration Input I: Corresponding Points<br />

The first category of input parameters for the operator camera_calibration comprises corresponding<br />

points, i.e., points, for which the world coordinates as well as the image coordinates of their projections<br />

into the image are given.<br />

If the <strong>HALCON</strong> calibration plate is used, the world coordinates of the calibration marks can be read<br />

from the calibration plate description file using the operator caltab_points. It returns the coordinates<br />

stored in the tuples X, Y, and Z. The length of these tuples depends on the number of calibration marks.<br />

Assume we have a calibration plate with m calibration marks. Then, X, Y, and Z are of length m.<br />

caltab_points (CaltabName, X, Y, Z)<br />

As mentioned above, it is necessary to extract the marks of the calibration plate and to know the correspondence<br />

between the marks extracted from the image and the respective 3D points. If the <strong>HALCON</strong><br />

calibration plate is used, this can be achieved by using the operator find_caltab to find the inner part<br />

of the calibration plate and find_marks_and_pose to locate the centers of the circles and to determine<br />

the correspondence.<br />

for I := 1 to NumImages by 1<br />

read_image (Image, ImgPath+’calib_’+I$’02d’)<br />

find_caltab (Image, Caltab, CaltabName, SizeGauss, MarkThresh,<br />

MinDiamMarks)<br />

find_marks_and_pose (Image, Caltab, CaltabName, StartCamPar,<br />

StartThresh, DeltaThresh, MinThresh, Alpha,<br />

MinContLength, MaxDiamMarks, RCoord, CCoord,<br />

StartPose)<br />

NStartPose := [NStartPose,StartPose]<br />

NRow := [NRow,RCoord]<br />

NCol := [NCol,CCoord]<br />

endfor<br />

find_caltab searches for the calibration plate based on the knowledge that it appears bright with dark<br />

calibration marks on it. SizeGauss determines the size of the Gauss filter that is used to smooth the<br />

input image. A larger value leads to a stronger smoothing, which might be necessary if the image is<br />

very noisy. After smoothing the image, a thresholding operator with minimum gray value MarkThresh


3.1.2 Rules for Taking Calibration Images 31<br />

and maximum gray value 255 is applied with the intention to find the calibration plate. Therefore,<br />

MarkThresh should be set to a gray value that is lower than that of the white parts of the calibration<br />

plate, but preferably higher than that of any other large bright region in the image. Among the regions<br />

resulting from the threshold operation, the most convex region with an almost correct number of holes<br />

(corresponding to the dark marks of the calibration plate) is selected. Holes with a diameter smaller than<br />

MinDiamMarks are eliminated to reduce the impact of noise. The number of marks is read from the<br />

calibration plate description file CalTabDescrFile.<br />

find_marks_and_pose extracts the calibration marks and precisely determines their image coordinates.<br />

Therefore, in the input image Image an edge detector is applied to the region CalTabRegion, which<br />

can be found by the operator find_caltab. The edge detector can be controlled via the parameter<br />

Alpha. Larger values for Alpha lead to a higher sensitivity of the edge detector with respect to small<br />

details, but also to less robustness to noise.<br />

In the edge image, closed contours are extracted. For the detection of the contours a threshold operator<br />

is applied to the amplitude of the edges. All points with a high amplitude (i.e., borders of marks) are<br />

selected. First, the threshold value is set to StartThresh. If the search for the closed contours or<br />

the successive pose estimate (see section 3.1.3) fails, this threshold value is successively decreased by<br />

DeltaThresh down to a minimum value of MinThresh.<br />

The number of closed contours must correspond to the number of calibration marks as described in<br />

the calibration plate description file CalTabDescrFile and the contours must have an elliptical shape.<br />

Contours shorter than MinContLength are discarded, just as contours enclosing regions with a diameter<br />

larger than MaxDiamMarks (e.g., the border of the calibration plate).<br />

The image coordinates of the calibration marks are determined by applying find_marks_and_pose for<br />

each image separately. They must be concatenated such that all row coordinates are together in one tuple<br />

and all column coordinates are in a second tuple.<br />

The length of these tuples depends on the number of calibration marks and on the number of calibration<br />

images. Assume we have a calibration plate with m calibration marks and l calibration images. Then,<br />

the tuples containing all the image coordinates of the calibration marks have a length of m · l, because<br />

they contain the coordinates of the m calibration marks extracted from each of the l images. The order of<br />

the values is “image by image”, i.e., the first m values correspond to the coordinates of the m calibration<br />

marks extracted from the first image, namely in the order in which they appear in the parameters X, Y,<br />

and Z, which are returned by the operator caltab_points. The next m values correspond to the marks<br />

extracted from the second image, etc.<br />

<strong>Note</strong> that the order of all the parameter values must be followed strictly. Therefore, it is very important<br />

that each calibration mark is extracted in each image.<br />

3.1.2 Rules for Taking Calibration Images<br />

If you want to achieve accurate results, please follow the rules given in this section:<br />

• Use a clean calibration plate.<br />

• Cover the whole field of view with multiple images, i.e, place the calibration plate in all areas of<br />

the field of view at least once.<br />

Single Camera


32 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

• Vary the orientations of the calibration plate. This includes rotations around the x- and y-axis<br />

of the calibration plate, such that the perspective distortions of the calibration pattern are clearly<br />

visible.<br />

• Use at least 10 – 15 images.<br />

• Use an illumination where the background is darker than the calibration plate.<br />

• The bright parts of the calibration plate should have a gray value of at least 100.<br />

• The contrast between the bright and the dark parts of the calibration plate should be more than 100<br />

gray values.<br />

• Use an illumination where the calibration plate is homogeneous<br />

• The images should not be overexposed.<br />

• The diameter of a circle should be at least 10 pixels.<br />

• The calibration plate should be completely inside the image.<br />

• The images should contain as little noise as possible.<br />

If you take into account these few rules for the acquisition of the calibration images, you can expect all<br />

<strong>HALCON</strong> operators used for the calibration process to work properly.<br />

If only one image is used for the calibration process or if the orientations of the calibration plate do not<br />

vary over the different calibration images it is not possible to determine both the focal length and the pose<br />

of the camera correctly; only the ratio between the focal length and the distance between calibration plate<br />

and camera can be determined in this case. Nevertheless, it is possible to measure world coordinates in<br />

the plane of the calibration plate but it is not possible to adapt the camera parameters in order to measure<br />

in another plane, e.g., the plane onto which the calibration plate was placed.<br />

The accuracy of the resulting world coordinates depends — apart of the measurement accuracy in the<br />

image — very much on the number of images used for the calibration process. The more images are<br />

used, the more accurate results will be achieved.<br />

3.1.3 Camera Calibration Input II: Initial Values<br />

The second category of input parameters of the operator camera_calibration comprises initial values<br />

for the camera parameters.<br />

As the camera calibration is a difficult non-linear optimization problem, good initial values are required<br />

for the parameters.<br />

The initial values for the interior camera parameters can be determined from the specifications of the<br />

CCD sensor and the lens. They must be given as a tuple of the form [f, κ, Sx, Sy, Cx, Cy, NumColumns,<br />

NumRows] for area scan cameras and [f, κ, Sx, Sy, Cx, Cy, NumColumns, NumRows, Vx, Vy, Vz] for<br />

line scan cameras, respectively, i.e., in addition to the interior camera parameters, the width (number of<br />

columns) and height (number of rows) of the image must be given. See section 2.2 on page 19 for a<br />

description of the interior camera parameters.


StartCamPar := [0.016,0,0.0000074,0.0000074,326,247,652,494]<br />

3.1.3 Camera Calibration Input II: Initial Values 33<br />

In the following, some hints for the determination of the initial values for the interior camera parameters<br />

of an area scan camera are given:<br />

Focus f: The initial value is the nominal focal length of the used lens, e.g., 0.016 m.<br />

κ: Use 0.0 as initial value.<br />

Sx: For pinhole cameras, the initial value for the horizontal distance between two neighboring<br />

CCD cells depends on the dimension of the used CCD chip of the camera<br />

(see technical specifications of the camera). Generally, common CCD chips are<br />

either 1/3”-Chips (e.g., SONY XC-73, SONY XC-777), 1/2”-Chips (e.g., SONY<br />

XC-999, Panasonic WV-CD50), or 2/3”-Chips (e.g., SONY DXC-151, SONY XC-<br />

77). Notice: The value of Sx increases if the image is sub-sampled! Appropriate<br />

initial values are:<br />

Full image (640*480) Subsampling (320*240)<br />

1/3"-Chip 0.0000055 m 0.0000110 m<br />

1/2"-Chip 0.0000086 m 0.0000172 m<br />

2/3"-Chip 0.0000110 m 0.0000220 m<br />

The value for Sx is calibrated, since the video signal of a CCD camera normally is<br />

not sampled pixel-synchronously.<br />

Sy: Since most off-the-shelf cameras have square pixels, the same values for Sy are<br />

valid as for Sx. In contrast to Sx the value for Sy will not be calibrated for pinhole<br />

cameras because the video signal of a CCD camera normally is sampled linesynchronously.<br />

Thus, the initial value is equal to the final value. Appropriate initial<br />

values are:<br />

Full image (640*480) Subsampling (320*240)<br />

1/3"-Chip 0.0000055 m 0.0000110 m<br />

1/2"-Chip 0.0000086 m 0.0000172 m<br />

2/3"-Chip 0.0000110 m 0.0000220 m<br />

Cx and Cy: Initial values for the coordinates of the principal point are the coordinates of the<br />

image center, i.e., the half image width and the half image height. Notice: The<br />

values of Cx and Cy decrease if the image is subsampled! Appropriate initial values<br />

are, for example:<br />

ImageWidth<br />

and<br />

ImageHeight:<br />

Full image (640*480) Subsampling (320*240)<br />

Cx 320.0 160.0<br />

Cy 240.0 120.0<br />

These two parameters are set by the the used frame grabber and therefore are not<br />

calibrated. Appropriate initial values are, for example:<br />

Full image (640*480) Subsampling (320*240)<br />

ImageWidth 640 320<br />

ImageHeight 480 240<br />

Single Camera


34 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

In the following, some hints for the determination of the initial values for the interior camera parameters<br />

of a line scan camera are given:<br />

Focus f: The initial value is the nominal focal length of the the used lens, e.g., 0.035 m.<br />

κ: Use 0.0 as initial value.<br />

Sx: The initial value for the horizontal distance between two neighboring sensor elements<br />

can be taken from the technical specifications of the camera. Typical initial<br />

values are 7·10 −6 m, 10·10 −6 m, and 14·10 −6 m. Notice: The value of Sx increases<br />

if the image is subsampled!<br />

Sy: The initial value for the size of a cell in the direction perpendicular to the sensor<br />

line can also be taken from the technical specifications of the camera. Typical<br />

initial values are 7·10 −6 m, 10·10 −6 m, and 14·10 −6 m. Notice: The value of Sy<br />

increases if the image is subsampled! In contrast to Sx, the value for Sy will NOT<br />

be calibrated for line scan cameras because it cannot be determined separately from<br />

the parameter Cy.<br />

Cx: The initial value for the x-coordinate of the principal point is half the image width.<br />

Notice: The values of Cx decreases if the image is subsampled! Appropriate initial<br />

values are:<br />

Image width: 1024 2048 4096 8192<br />

Cx: 512 1024 2048 4096<br />

Cy: Normally, the initial value for the y-coordinate of the principal point can be set to<br />

0.<br />

ImageWidth<br />

and<br />

ImageHeight:<br />

These two parameters are determined by the used frame grabber and therefore are<br />

not calibrated.


3.1.3 Camera Calibration Input II: Initial Values 35<br />

Vx, Vy, Vz: The initial values for the x-, y-, and z-component of the motion vector depend on<br />

the image acquisition setup. Assuming a fixed camera that looks perpendicularly<br />

onto a conveyor belt, such that the y-axis of the camera coordinate system is antiparallel<br />

to the moving direction of the conveyor belt (see figure 19 on page 36),<br />

the initial values are Vx = Vz = 0. The initial value for Vy can then be determined,<br />

e.g., from a line scan image of an object with known size (e.g., calibration plate or<br />

ruler):<br />

Vy = L[m]/L[row]<br />

with:<br />

L[m] = Length of the object in object coordinates [meter]<br />

L[row] = Length of the object in image coordinates [rows]<br />

If, compared to the above setup, the camera is rotated 30 degrees around its optical<br />

axis, i.e., around the z-axis of the camera coordinate system (figure 20 on page 37),<br />

the above determined initial values must be changed as follows:<br />

Vzx = sin(30 ◦ ) · Vy<br />

Vzy = cos(30 ◦ ) · Vy<br />

Vzz = Vz = 0<br />

If, compared to the first setup, the camera is rotated -20 degrees around the x-axis<br />

of the camera coordinate system (figure 21 on page 38), the following initial values<br />

result:<br />

Vxx = Vx = 0<br />

Vxy = cos(−20 ◦ ) · Vy<br />

Vxz = sin(−20 ◦ ) · Vy<br />

The quality of the initial values for Vx, Vy, and Vz are crucial for the success of the<br />

whole calibration. If they are not accurate enough, the calibration may fail.<br />

The initial values for the exterior parameters are in general harder to obtain. For the <strong>HALCON</strong> calibration<br />

plate, good starting values are computed by the operator find_marks_and_pose based on the geometry<br />

and size of the projected calibration marks. Again, these values are determined for each calibration image<br />

separately. They must be concatenated into one tuple. Assume we have l calibration images. Then, the<br />

length of this tuple is l · 7 (l times the 6 exterior camera parameters together with the code for the pose<br />

type). The first 7 values correspond to the camera pose of the first image, the next 7 values to the pose<br />

of the second image, etc.<br />

If you use another calibration object the operator find_marks_and_pose cannot be used. In this case,<br />

you must determine the initial values for the exterior parameters yourself.<br />

Single Camera


36 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

y w<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

z w<br />

r s<br />

Cy<br />

x w<br />

Sy<br />

⎛<br />

⎜<br />

⎝<br />

y c<br />

v<br />

−Vx<br />

−Vy<br />

−Vz<br />

z c<br />

⎞<br />

f<br />

⎟<br />

⎠<br />

Cx<br />

P ′<br />

x c<br />

u<br />

Sx<br />

c s<br />

Camera coordinate system (x c , y c , z c )<br />

Sensor line coordinate system (r s , c s )<br />

Image plane coordinate system (u, v)<br />

P<br />

World coordinate system (x w , y w , z w )<br />

Figure 19: Line scan camera looking perpendicularly onto a conveyor belt.<br />

3.1.4 Determining the Interior Camera Parameters<br />

Given some initial values for the camera parameters, the known 3D locations of the calibration marks<br />

can be projected into the CCS. Then, the camera parameters can be determined such that the distance of<br />

the projections of the calibration marks and the mark locations extracted from the imagery is minimized.<br />

This minimization process will return fairly accurate values for the camera parameters. However, to<br />

obtain the camera parameters with the highest accuracy, it is essential that more than one image of the<br />

calibration plate is taken, where the plate is placed and rotated differently in each image so as to use<br />

all degrees of freedom of the exterior orientation. A typical sequence of images used for calibration is<br />

displayed in figure 22.<br />

If l images of the calibration plate are taken, the parameters to optimize are the interior parameters and<br />

l sets of the exterior parameters. Now, the aim of the optimization is to determine all these parameters<br />

such that in each of the l images the distance of the extracted mark locations and the projections of the respective<br />

3D locations is minimal. In <strong>HALCON</strong>, this is exactly what the operator camera_calibration<br />

does.


y w<br />

Camera with<br />

optical center<br />

Sy<br />

Virtual image plane<br />

z w<br />

r s<br />

x w<br />

y c<br />

z c<br />

f<br />

x c<br />

3.1.4 Determining the Interior Camera Parameters 37<br />

Camera coordinate system (x c , y c , z c )<br />

P ′ Sensor line coordinate system (rs , cs Cx Sx<br />

)<br />

Cy cs ⎛<br />

⎜<br />

⎝<br />

v<br />

−Vx<br />

−Vy<br />

−Vz<br />

⎞<br />

⎟<br />

⎠<br />

u<br />

Image plane coordinate system (u, v)<br />

P<br />

World coordinate system (x w , y w , z w )<br />

Figure 20: Line scan camera rotated around the optical axis.<br />

camera_calibration (X, Y, Z, NRow, NCol, StartCamPar, NStartPose, ’all’,<br />

CamParam, NFinalPose, Errors)<br />

The operator camera_calibration needs the coordinates of the corresponding points in the world coordinate<br />

system and the pixel coordinate system as well as some initial values for the camera parameters.<br />

See section 3.1.1 on page 30 and section 3.1.3 on page 32 for a description on how to obtain these input<br />

values.<br />

If the parameter EstimateParams is set to ’all’, the interior parameters for the used camera<br />

are determined as well as the exterior parameters for each image. If the parameter is<br />

set to ’pose’, only the exterior parameters are determined. To determine just selected parameters,<br />

EstimateParams can be set to a list that contains the respective parameter names ([’alpha’,’beta’,’gamma’,’transx’,’transy’,’transz’,’focus’,’kappa’,’cx’,’cy’,’sx’,’sy’]).<br />

It is also possible to prevent<br />

the determination of certain parameters by adding their names with the prefix ~ to the list, e.g., if<br />

EstimateParams is set to [’all’, ’~focus’], all parameters but the focal length are determined.<br />

The computed average errors (Errors) give an impression of the accuracy of the calibration. The error<br />

values (deviations in x- and y-coordinates) are given in pixels.<br />

Up to now, the exterior parameters are not necessarily related to the measurement plane.<br />

Single Camera


38 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

y w<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

r s<br />

z w<br />

Cy<br />

Sy<br />

x w<br />

v<br />

⎛<br />

⎜<br />

⎝<br />

y c<br />

f<br />

−Vx<br />

−Vy<br />

−Vz<br />

z c<br />

⎞<br />

⎟<br />

⎠<br />

Cx<br />

P ′<br />

u<br />

x c<br />

Sx<br />

c s<br />

P<br />

Camera coordinate system (x c , y c , z c )<br />

Sensor line coordinate system (r s , c s )<br />

Image plane coordinate system (u, v)<br />

World coordinate system (x w , y w , z w )<br />

Figure 21: Line scan camera rotated around the x-axis.<br />

Figure 22: A sequence of calibration images..


3.1.5 Determining the Exterior Camera Parameters<br />

3.1.5 Determining the Exterior Camera Parameters 39<br />

The exterior camera parameters describe the relation between the measurement plane and the camera,<br />

i.e., only if the exterior parameters are known it is possible to transform coordinates from the CCS into<br />

the coordinate system of the measurement plane and vice versa. In <strong>HALCON</strong>, the measurement plane is<br />

defined as the plane z = 0 of the world coordinate system (WCS). The exterior camera parameters can<br />

be determined in different ways:<br />

1. Use the pose of the calibration plate present in one of the calibration images. In this case, it is not<br />

necessary to call the operator camera_calibration a second time.<br />

2. Obtain an additional calibration image where the calibration plate has been placed directly on<br />

the measurement plane. Apply find_caltab and find_marks_and_pose to extract the calibration<br />

marks. Then, use the operator camera_calibration to determine only the exterior camera<br />

parameters.<br />

3. Determine the correspondences between 3D world points and their projections in the image by<br />

yourself. Again, use the operator camera_calibration to determine the exterior camera parameters.<br />

If it is only necessary to measure accurately the dimensions of an object, regardless of the absolute<br />

position of the object in a given coordinate system, one of the first two cases can be used.<br />

The latter two cases have the advantage that the exterior camera parameters can be determined independently<br />

from the interior camera parameters. This is more flexible and might be useful if the measurements<br />

should be done in several planes from one camera only or if it is not possible to calibrate the camera in<br />

situ.<br />

In the following, these different cases are described in more detail.<br />

The first case is the easiest way of determining the exterior parameters. The calibration plate must be<br />

placed directly on the measurement plane, e.g., the assembly line, in one of the (many) images used for<br />

the determination of the interior parameters.<br />

Since the pose of the calibration plate is determined by the operator camera_calibration, you can<br />

just pick the respective pose from the output parameter NFinalPose. In this way, interior and exterior<br />

parameters are determined in one single calibration step. The following code fragment from the program<br />

hdevelop\camera_calibration_multi_image.dev is an example for this easy way of determining<br />

the exterior parameters. Here, the pose of the calibration plate in the eleventh calibration image is<br />

determined. Please note that each pose consists of seven values.<br />

NumImage := 11<br />

Pose := NFinalPose[(NumImage-1)*7:(NumImage-1)*7+6]<br />

The resulting pose would be the true pose of the measurement plane if the calibration plate were infinitely<br />

thin. Because real calibration plates have a thickness d > 0, the pose of the calibration plate is shifted<br />

by an amount −d perpendicular to the measurement plane, i.e., along the z axis of the WCS. To correct<br />

this, we need to shift the pose by d along the z axis of the WCS. To perform this shift, the operator<br />

set_origin_pose can be used. The corresponding <strong>HALCON</strong> code is:<br />

Single Camera


40 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

set_origin_pose (Pose, 0, 0, 0.00075, Pose)<br />

In general, the calibration plate can be oriented arbitrarily within the WCS (see figure 23). In this case,<br />

to derive the pose of the measurement plane from the pose of the calibration plate a rigid transformation<br />

is necessary. In the following example, the pose of the calibration plate is adapted by a translation along<br />

the y axis followed by a rotation around the x axis.<br />

pose_to_hom_mat3d (FinalPose, HomMat3D)<br />

hom_mat3d_translate_local (HomMat3D, 0, 3.2, 0, HomMat3DTranslate)<br />

hom_mat3d_rotate_local (HomMat3DTranslate, rad(-14), ’x’, HomMat3DAdapted)<br />

hom_mat3d_to_pose (HomMat3DAdapted, PoseAdapted)<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

Calibration plate<br />

y w<br />

S y<br />

cp<br />

Hw Measurement plane (z w=<br />

0)<br />

r<br />

c<br />

Hw z w<br />

C<br />

y<br />

y c<br />

v<br />

x w<br />

z c<br />

f<br />

c<br />

Hcp<br />

y cp<br />

C<br />

z cp<br />

x<br />

x c<br />

u<br />

x cp<br />

Sx<br />

c<br />

x c y c z c Camera coordinate system ( , , )<br />

Image coordinate system ( r, c)<br />

Image plane coordinate system<br />

( u, v)<br />

Calibration plate coordinate system<br />

x w y w z w<br />

World coordinate system ( , , )<br />

Figure 23: Relation between calibration plate and measurement plane.<br />

x cp y cp z cp ( , , )


3.1.5 Determining the Exterior Camera Parameters 41<br />

If the advantages of using the <strong>HALCON</strong> calibration plate should be combined with the flexibility given<br />

by the separation of the interior and exterior camera parameters the second method for the determination<br />

of the exterior camera parameters can be used.<br />

At first, only the interior parameters are determined as described in section 3.1.4 on page 36. This can<br />

be done, e.g., prior to the deployment of the camera.<br />

This is shown in the example program hdevelop\camera_calibration_interior.dev, which is<br />

similar to the example program given above, except that no image is used in which the calibration plate<br />

is positioned on the object and that the calculated interior camera parameters are written to a file.<br />

<strong>Note</strong> that we do not use any of the images to derive the pose of the measurement plane.<br />

for I := 1 to NumImages by 1<br />

read_image (Image, ImgPath+’calib_’+I$’02d’)<br />

find_caltab (Image, Caltab, CaltabName, SizeGauss, MarkThresh,<br />

MinDiamMarks)<br />

find_marks_and_pose (Image, Caltab, CaltabName, StartCamPar,<br />

StartThresh, DeltaThresh, MinThresh, Alpha,<br />

MinContLength, MaxDiamMarks, RCoord, CCoord,<br />

StartPose)<br />

NStartPose := [NStartPose,StartPose]<br />

NRow := [NRow,RCoord]<br />

NCol := [NCol,CCoord]<br />

endfor<br />

camera_calibration (X, Y, Z, NRow, NCol, StartCamPar, NStartPose, ’all’,<br />

CamParam, NFinalPose, Errors)<br />

Then, the interior camera parameters can be written to a file:<br />

write_cam_par (CamParam, ’camera_parameters.dat’)<br />

Then, after installing the camera at its usage site, the exterior parameters can be determined. The only<br />

thing to be done is to take an image where the calibration plate is placed directly on the measurement<br />

plane, from which the exterior parameters can be determined.<br />

Again the operators find_caltab and find_marks_and_pose can be used to extract the calibration<br />

marks. Then, the operator camera_calibration with the parameter EstimateParams set to ’pose’<br />

determines just the pose of the calibration plate and leaves the interior camera parameter unchanged.<br />

Alternatively, EstimateParams can be set to the tuple [’alpha’, ’beta’, ’gamma’, ’transx’, ’transy’,<br />

’transz’], which also means that the six exterior parameters will be estimated. Again, the pose must be<br />

corrected for the thickness of the calibration plate as described above.<br />

The program hdevelop\camera_calibration_exterior.dev shows how to determine the exterior<br />

camera parameters from a calibration plate that is positioned on the object’s surface.<br />

First, the interior camera parameters, the image, where the calibration plate was placed directly on the<br />

measurement plane, and the world coordinates of the calibration marks are read from file:<br />

read_cam_par (’camera_parameters.dat’, CamParam)<br />

read_image (Image, ImgPath+’calib_11’)<br />

caltab_points (CaltabName, X, Y, Z)<br />

Then, the calibration marks are extracted.:<br />

Single Camera


42 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

find_caltab (Image, Caltab, CaltabName, SizeGauss, MarkThresh,<br />

MinDiamMarks)<br />

find_marks_and_pose (Image, Caltab, CaltabName, CamParam, StartThresh,<br />

DeltaThresh, MinThresh, Alpha, MinContLength,<br />

MaxDiamMarks, RCoord, CCoord,<br />

InitialPoseForCalibrationPlate)<br />

Now, the actual calibration can be carried out:<br />

camera_calibration (X, Y, Z, RCoord, CCoord, CamParam,<br />

InitialPoseForCalibrationPlate, ’pose’,<br />

CamParamUnchanged, FinalPoseFromCalibrationPlate,<br />

Errors)<br />

Finally, to take the thickness of the calibration plate into account, the z value of the origin given by the<br />

camera pose must be translated by the thickness of the calibration plate:<br />

set_origin_pose (FinalPoseFromCalibrationPlate, 0, 0, 0.00075,<br />

FinalPoseFromCalibrationPlate)<br />

<strong>Note</strong> that it is very important to fix the focus of your camera if you want to separate the calibration<br />

process into two steps as described in this section, because changing the focus is equivalent to changing<br />

the focal length, which is part of the interior parameters.<br />

If it is necessary to perform the measurements within a given world coordinate system, the third case for<br />

the determination of the exterior camera parameters can be used. Here, you need to know the 3D world<br />

coordinates of at least three points that do not lie on a straight line. Then, you must determine the corresponding<br />

image coordinates of the projections of these points. Now, the operator camera_calibration<br />

with the parameter EstimateParams set to ’pose’ can be used for the determination of the exterior camera<br />

parameters.<br />

<strong>Note</strong> that in this case, no calibration plate needs to be placed on the measurement plane. This means also<br />

that the operator find_marks_and_pose cannot be used to extract the calibration marks. Therefore,<br />

you must generate the input parameter tuples NX, NY, and NZ as well as NRow and NCol yourself. Also<br />

the initial values for the pose must be set appropriately because in this case they are not determined<br />

automatically since the operator find_marks_and_pose is not used.<br />

An example for this possibility of determining the exterior parameters is given in the following program.<br />

First, the world coordinates of three points are set:<br />

X := [0,50,100]<br />

Y := [5,0,5]<br />

Z := [0,0,0]<br />

Then, the image coordinates of the projections of these points in the image are determined. In this<br />

example, they are simply set to some approximate values. In reality, they should be determined with<br />

subpixel accuracy since they define the exterior camera parameters:<br />

RCoord := [414,227,85]<br />

CCoord := [119,318,550]<br />

Now, the starting value for the pose must be set appropriately:


3.1.6 How to Obtain a Suitable Calibration Plate 43<br />

create_pose (-50, 25, 400, 0, 0, -30, ’Rp+T’, ’gba’, ’point’, InitialPose)<br />

Finally, the actual determination of the exterior camera parameters can be carried out:<br />

camera_calibration (X, Y, Z, RCoord, CCoord, CamParam, InitialPose, ’pose’,<br />

CamParamUnchanged, FinalPose, Errors)<br />

Also in this case, it is very important to fix the focus of your camera because changing the focus is<br />

equivalent to changing the focal length, which is part of the interior parameters.<br />

3.1.6 How to Obtain a Suitable Calibration Plate<br />

The simplest method to determine the camera parameters of a CCD camera is to use the <strong>HALCON</strong><br />

calibration plate. In this case, the whole process of finding the calibration plate, extracting the calibration<br />

marks, and determining the correspondences between the extracted calibration marks and the respective<br />

3D world coordinates can be carried out automatically. Even more important, these calibration plates are<br />

highly accurate, up to ± 150 nm (nanometers), which is a prerequisite for high accuracy applications.<br />

Therefore, we recommend to obtain such a calibration plate from the local distributor from which you<br />

purchased <strong>HALCON</strong>.<br />

The calibration plates are available in different materials (ceramics for front light and glass for back<br />

light applications) and sizes (e.g., 0.65 × 0.65 mm 2 , 10 × 10 mm 2 , 200 × 200 mm 2 ). Thus, you can<br />

choose the one that is optimal for your application. As a rule of thumb, the width of the calibration<br />

plate should be approximately one third of the image width. For example, if the image shows an area of<br />

100 mm × 70 mm, the 30 × 30 mm 2 calibration plate would be appropriate. Detailed information about<br />

the available materials, sizes, and the accuracy can be obtained from your distributor.<br />

Each calibration plate comes with a description file. Place this file in the subdirectory calib of the folder<br />

where you installed <strong>HALCON</strong>, then you can use its file name directly in the operator caltab_points<br />

(see section 3.1.1 on page 30).<br />

For test purposes, you can create a calibration plate yourself with the operator gen_caltab. Print the<br />

resulting PostScript file and mount it on a planar and rigid surface, e.g., an aluminum plate or a solid<br />

cardboard. If you do not mount the printout on a planar and rigid surface, you will not get meaningful<br />

results by <strong>HALCON</strong>’s camera calibration as the operator gen_caltab assumes that the calibration marks<br />

lie within a plane. Such self-made calibration plates should only be used for test purposes as you will not<br />

achieve the high accuracy that can be obtained with an original <strong>HALCON</strong> calibration plate. <strong>Note</strong> that<br />

the printing process is typically not accurate enough to create calibration plates smaller than 3 cm.<br />

3.1.7 Using Your Own Calibration Object<br />

With <strong>HALCON</strong>, you are not restricted to using a planar calibration object like the <strong>HALCON</strong> calibration<br />

plate. The operator camera_calibration is designed such that the input tuples NX, NY, and NZ for<br />

the world coordinates of the calibration marks and NRow and NCol for the image coordinates of the<br />

locations of the calibration marks within the images can contain any 3D/2D correspondences (compare<br />

section 3.1.4 on page 36).<br />

Thus, it is not important how the required 3D model marks and the corresponding extracted 2D marks<br />

are determined. You can use a 3D calibration object or even arbitrary characteristic points (natural<br />

Single Camera


44 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

landmarks). The only requirement is that the 3D world position of the model points is known with high<br />

accuracy.<br />

However, if you use your own calibration object, you cannot use the operators find_caltab and<br />

find_marks_and_pose anymore. Instead, you must determine the 2D locations of the model points<br />

and the correspondence to the respective 3D points as well as the initial value for the poses yourself.<br />

3.1.8 Special information for the calibration of line scan cameras<br />

In general, the procedure for the calibration of line scan cameras is identical to the one for the calibration<br />

of area scan cameras.<br />

However, line scan imaging suffers from a high degree of parameter correlation. For example, any small<br />

rotation of the linear array around the x-axis of the camera coordinate system can be compensated by<br />

changing the y-component of the translation vector of the respective pose. Even the focal length is<br />

correlated with the scale factor Sx and with the z-component of the translation vector of the pose, i.e.,<br />

with the distance of the object from the camera.<br />

The consequences of these correlations for the calibration of line scan cameras are that some parameters<br />

cannot be determined with high absolute accuracy. Nevertheless, the set of parameters is determined<br />

consistently, what means that the world coordinates can be measured with high accuracy.<br />

Another consequence of the parameter correlations is that the calibration may fail in some cases where<br />

the start values for the interior camera parameters are not accurate enough. If this happens, try the<br />

following approach: In many cases, the start values for the motion vector are the most difficult to set.<br />

To achieve better start values for the parameters Vx, Vy, and Vz, reduce the number of parameters to be<br />

estimated such that the camera calibration succeeds. Try first to estimate the parameters Vx, Vy, Vz, α,<br />

β, γ, tx, ty, and tz by setting EstimateParams to [’vx’, ’vy’, ’vz’, ’alpha’, ’beta’, ’gamma’, ’transx’,<br />

’transy’, ’transz’] and if this does not work, try to set EstimateParams to [’vx’, ’vy’, ’vz’, ’transx’,<br />

’transy’, ’transz’]. Then, determine the whole set of parameters using the above determined values for<br />

Vx, Vy, and Vz as start values.<br />

If this still does not work, repeat the determination of the start poses with the operator<br />

find_marks_and_pose using the above determined values for the interior camera parameters as start<br />

values. Then retry to calibrate the camera with the operator camera_calibration.<br />

If none of the above works, try to determine better start values directly from the camera setup. If possible,<br />

change the setup such that it is easier to determine appropriate start values, e.g., mount the camera such<br />

that it looks approximately perpendicularly onto the conveyor belt (see figure 19 on page 36).<br />

3.2 Transforming Image into World Coordinates and Vice Versa<br />

In this section, you learn how to obtain world coordinates from images based on the calibration data. On<br />

the one hand, it is possible to process the images as usual and then to transform the extraction results<br />

into the world coordinate system. In many cases, this will be the most efficient way of obtaining world<br />

coordinates. On the other hand, some applications may require that the segmentation itself must be<br />

carried out in images that are already transformed into the world coordinate system (see section 3.3 on<br />

page 49).


3.2.1 The Main Principle 45<br />

In general, the segmentation process reduces the amount of data that needs to be processed. Therefore,<br />

rectifying the segmentation results is faster than rectifying the underlying image. What is more, it is<br />

often better to perform the segmentation process directly on the original images because smoothing or<br />

aliasing effects may occur in the rectified image, which could disturb the segmentation and may lead to<br />

inaccurate results. These arguments suggest to rectify the segmentation results instead of the images.<br />

In the following, first some general remarks on the underlying principle of the transformation of image<br />

coordinates into world coordinates are given. Then, it is described how to transform points, contours,<br />

and regions into the world coordinate system. Finally, we show that it is possible to transform world<br />

coordinates into image coordinates as well, e.g., in order to visualize information given in the world<br />

coordinate system.<br />

3.2.1 The Main Principle<br />

Given the image coordinates of one point, the goal is to determine the world coordinates of the corresponding<br />

point in the measurement plane. For this, the line of sight, i.e., a straight line from the optical<br />

center of the camera through the given point in the image plane, must be intersected with the measurement<br />

plane (see figure 24).<br />

The calibration data is necessary to transform the image coordinates into camera coordinates and finally<br />

into world coordinates.<br />

All these calculations are performed by the operators of the family ..._to_world_plane.<br />

Again, please remember that in <strong>HALCON</strong> the measurement plane is defined as the plane z = 0 with<br />

respect to the world coordinate system. This means that all points returned by the operators of the family<br />

..._to_world_plane have a z-coordinated equal to zero, i.e., they lie in the plane z = 0 of the world<br />

coordinate system.<br />

3.2.2 World Coordinates for Points<br />

The world coordinates of an image point (r, c) can be determined using the operator<br />

image_points_to_world_plane. In the following code example, the row and column coordinates<br />

of pitch lines are transformed into world coordinates.<br />

image_points_to_world_plane (CamParam, FinalPose, RowPitchLine,<br />

ColPitchLine, 1, X1, Y1)<br />

As input, the operator requires the interior and exterior camera parameters as well as the row and column<br />

coordinates of the point(s) to be transformed.<br />

Additionally, the unit in which the resulting world coordinates are to be given is specified by the parameter<br />

Scale (see also the description of the operator image_to_world_plane in section 3.3.1 on page<br />

49). This parameter is the ratio between the unit in which the resulting world coordinates are to be given<br />

and the unit in which the world coordinates of the calibration target are given (equation 28).<br />

Scale =<br />

unit of resulting world coordinates<br />

unit of world coordinates of calibration target<br />

(28)<br />

Single Camera


46 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

y w<br />

S y<br />

c<br />

Hw z w z w<br />

Measurement plane ( = 0)<br />

r<br />

C<br />

y<br />

y c<br />

v<br />

x w<br />

z c<br />

f<br />

C<br />

P’<br />

x<br />

x c<br />

u<br />

Line of sight<br />

Sx<br />

P<br />

c<br />

x c y c z c Camera coordinate system ( , , )<br />

Image coordinate system ( r, c)<br />

Image plane coordinate system<br />

( u, v)<br />

x w y w z w<br />

World coordinate system ( , , )<br />

Figure 24: Intersecting the line of sight with the measurement plane..<br />

In many cases the coordinates of the calibration target are given in meters. In this case, it is possible to<br />

set the unit of the resulting coordinates directly by setting the parameter Scale to ’m’ (corresponding<br />

to the value 1.0, which could be set alternatively for the parameter Scale), ’cm’ (0.01), ’mm’ (0.001),<br />

’microns’ (1e-6), or ’µm’ (again, 1e-6). Then, if the parameter Scale is set to, e.g., ’m’, the resulting<br />

coordinates are given in meters. If, e.g., the coordinates of the calibration target are given in µm and the


esulting coordinates have to be given in millimeters, the parameter Scale must be set to:<br />

3.2.3 World Coordinates for Contours<br />

3.2.3 World Coordinates for Contours 47<br />

Scale = mm<br />

µm = 1 · 10−3 m<br />

1 · 10−6 = 1000 (29)<br />

m<br />

If you want to convert an XLD object containing pixel coordinates into world coordinates, the operator<br />

contour_to_world_plane_xld can be used. Its parameters are similar to those of the operator<br />

image_points_to_world_plane, as can be seen from the following example program:<br />

lines_gauss (ImageReduced, Lines, 1, 3, 8, ’dark’, ’true’, ’true’, ’true’)<br />

contour_to_world_plane_xld (Lines, ContoursTrans, CamParam, PoseAdapted, 1)<br />

3.2.4 World Coordinates for Regions<br />

In <strong>HALCON</strong>, regions cannot be transformed directly into the world coordinate system. Instead, you<br />

must first convert them into XLD contours using the operator gen_contour_region_xld, then apply<br />

the transformation to these XLD contours as described in the previous section.<br />

If the regions have holes and if these holes would influence your further calculations, set the parameter<br />

Mode of the operator gen_contour_region_xld to ’border_holes’. Then, in addition to the outer<br />

border of the input region the operator gen_contour_region_xld returns the contours of all holes.<br />

3.2.5 Transforming World Coordinates into Image Coordinates<br />

In this section, the transformation between image coordinates and world coordinates is performed in<br />

the opposite direction, i.e., from world coordinates to image coordinates. This is useful if you want to<br />

visualize information given in world coordinates or it may be helpful for the definition of meaningful<br />

regions of interest (ROI).<br />

First, the world coordinates must be transformed into the camera coordinate system. For this, the homogeneous<br />

transformation matrix CCS HW CS is needed, which can easily be derived from the pose of the<br />

measurement plane with respect to the camera by the operator pose_to_hom_mat3d. The transformation<br />

itself can be carried out using the operator affine_trans_point_3d. Then, the 3D coordinates,<br />

now given in the camera coordinate system, can be projected into the image plane with the operator<br />

project_3d_point. An example program is given in the following:<br />

First, the world coordinates of four points defining a rectangle in the WCS are defined.<br />

ROI_X_WCS := [-2,-2,112,112]<br />

ROI_Y_WCS := [0,0.5,0.5,0]<br />

ROI_Z_WCS := [0,0,0,0]<br />

Then, the transformation matrix CCS HW CS is derived from the respective pose.<br />

pose_to_hom_mat3d (FinalPose, CCS_HomMat_WCS)<br />

Finally, the world points are transformed into the image coordinate system.<br />

Single Camera


48 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

affine_trans_point_3d (CCS_HomMat_WCS, ROI_X_WCS, ROI_Y_WCS, ROI_Z_WCS,<br />

CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ)<br />

project_3d_point (CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ,<br />

CamParamUnchanged, RectangleRow, RectangleCol)<br />

3.2.6 Compensate for Radial Distortions Only<br />

All operators discussed above automatically compensate for radial distortions. In some cases, you might<br />

want to compensate for radial distortions only without transforming results or images into world coordinates.<br />

The procedure is to specify the original interior camera parameters and those of a virtual camera that<br />

does not produce radial distortions, i.e., with κ = 0.<br />

The easiest way to obtain the interior camera parameters of the virtual camera would be to simply set κ<br />

to zero. This can be done directly by changing the respective value of the interior camera parameters.<br />

CamParVirtualFixed := CamParOriginal<br />

CamParVirtualFixed[1] := 0<br />

Alternatively, the operator change_radial_distortion_cam_par can be used with the parameter<br />

Mode set to ’fixed’ and the parameter Kappa set to 0.<br />

change_radial_distortion_cam_par (’fixed’, CamParOriginal, 0,<br />

CamParVirtualFixed)<br />

Then, for the rectification of the segmentation results, the <strong>HALCON</strong> operator<br />

change_radial_distortion_contours_xld can be used, which requires as input parameters<br />

the original and the virtual interior camera parameters.<br />

change_radial_distortion_contours_xld (Edges, EdgesRectifiedFixed,<br />

CamParOriginal, CamParVirtualFixed)<br />

This changes the visible part of the scene (see figure 25b). To obtain virtual camera parameters such that<br />

the whole image content lies within the visible part of the scene, the parameter Mode of the operator<br />

change_radial_distortion_cam_par must be set to ’fullsize’ (see figure 25c). Again, to eliminate<br />

the radial distortions, the parameter Kappa must be set to 0.<br />

change_radial_distortion_cam_par (’fullsize’, CamParOriginal, 0,<br />

CamParVirtualFullsize)<br />

If the radial distortions are eliminated in the image itself using the rectification procedure described in<br />

section 3.3.2 on page 55, the mode ’fullsize’ may lead to undefined pixels in the rectified image. The<br />

mode ’adaptive’ (see figure 25d) slightly reduces the visible part of the scene to prevent such undefined<br />

pixels.<br />

change_radial_distortion_cam_par (’adaptive’, CamParOriginal, 0,<br />

CamParVirtualAdaptive)<br />

<strong>Note</strong> that this compensation for radial distortions is not possible for line scan images because of the<br />

acquisition geometry of line scan cameras. To eliminate radial distortions from segmentation results of


(a) (b)<br />

(c) (d)<br />

3.3 Rectifying Images 49<br />

Figure 25: Eliminating radial distortions: The original image overlaid with (a) edges extracted from the<br />

original image; (b) edges rectified by setting κ to zero; (c) edges rectified with mode ’fullsize’;<br />

(d) edges rectified with mode ’adaptive’.<br />

line scan images, the segmentation results must be transformed into the WCS (see section 3.2.2 on page<br />

45, section 3.2.3 on page 47, and section 3.2.4 on page 47).<br />

3.3 Rectifying Images<br />

For applications like blob analysis or OCR, it may be necessary to have undistorted images. Imagine<br />

that an OCR has been trained based on undistorted image data. Then, it will not be able to recognize<br />

characters in heavily distorted images. In such a case, the image data must be rectified, i.e., the radial<br />

and perspective distortions must be eliminated before the OCR can be applied.<br />

3.3.1 Transforming Images into the WCS<br />

The operator image_to_world_plane rectifies an image by transforming it into the measurement plane,<br />

i.e., the plane z = 0 of the WCS. The rectified image shows no radial and no perspective distortions. It<br />

Single Camera


50 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

corresponds to an image captured by a camera that produces no radial distortions and that looks perpendicularly<br />

to the measurement plane.<br />

image_to_world_plane (Image, ImageMapped, CamParam, PoseForCenteredImage,<br />

WidthMappedImage, HeightMappedImage,<br />

ScaleForCenteredImage, ’bilinear’)<br />

If more than one image must be rectified, a projection map can be determined with<br />

the operator gen_image_to_world_plane_map, which is used analogously to the operator<br />

image_to_world_plane, followed by the actual transformation of the images, which is carried out<br />

by the operator map_image.<br />

gen_image_to_world_plane_map (Map, CamParam, PoseForCenteredImage,<br />

WidthOriginalImage, HeightOriginalImage,<br />

WidthMappedImage, HeightMappedImage,<br />

ScaleForCenteredImage, ’bilinear’)<br />

map_image (Image, Map, ImageMapped)<br />

The size of the rectified image can be chosen with the parameters Width and Height for the operator<br />

image_to_world_plane and with the parameters WidthMapped and HeightMapped for the operator<br />

gen_image_to_world_plane_map. The size of the rectified image must be given in pixels.<br />

The pixel size of the rectified image is specified by the parameter Scale (see also the description of<br />

the operator image_points_to_world_plane in section 3.2.2 on page 45). This parameter is the ratio<br />

between the pixel size of the rectified image and the unit in which the world coordinates of the calibration<br />

target are given (equation 30).<br />

Scale =<br />

pixel size of rectified image<br />

unit of world coordinates of calibration target<br />

In many cases the coordinates of the calibration targets are given in meters. In this case, it is possible to<br />

set the pixel size directly by setting the parameter Scale to ’m’ (corresponding to the value 1.0, which<br />

could be set alternatively for the parameter Scale), ’cm’ (0.01), ’mm’ (0.001), ’microns’ (1e-6), or ’µm’<br />

(again, 1e-6). Then, if the parameter Scale is set to, e.g., ’µm’, one pixel of the rectified image has a<br />

size that corresponds to an area of 1 µm × 1 µm in the world. The parameter Scale should be chosen<br />

such that in the center of the area of interest the pixel size of the input image and of the rectified image<br />

is similar. Large scale differences would lead to aliasing or smoothing effects. See below for examples<br />

of how the scale can be determined.<br />

The parameter Interpolation specifies whether bilinear interpolation (’bilinear’) should be applied<br />

between the pixels in the input image or whether the gray value of the nearest neighboring pixel (’none’)<br />

should be used.<br />

The rectified image ImageWorld is positioned such that its upper left corner is located exactly at the<br />

origin of the WCS and that its column axis is parallel to the x-axis of the WCS. Since the WCS is defined<br />

by the exterior camera parameters CamPose the position of the rectified image ImageWorld can be<br />

translated by applying the operator set_origin_pose to the exterior camera parameters. Arbitrary<br />

transformations can be applied to the exterior camera parameters based on homogeneous transformation<br />

matrices. See below for examples of how the exterior camera parameters can be set.<br />

In figure 26, the WCS has been defined such that the upper left corner of the rectified image corresponds<br />

to the upper left corner of the input image. To illustrate this, in figure 26, the full domain of the rectified<br />

(30)


Camera with<br />

optical center<br />

Virtual image plane<br />

Height<br />

y w<br />

z w<br />

z w<br />

Measurement plane ( = 0)<br />

r<br />

y c<br />

c<br />

Hw z c<br />

x w<br />

Width<br />

Rectified image<br />

f<br />

x c<br />

Scale Unit<br />

c<br />

3.3.1 Transforming Images into the WCS 51<br />

x c y c z c Camera coordinate system ( , , )<br />

Image coordinate system ( r, c)<br />

Figure 26: Projection of the image into the measurement plane.<br />

World coordinate system ( )<br />

x w y w z w<br />

, ,<br />

image, transformed into the virtual image plane of the input image, is displayed. As can be seen, the<br />

upper left corner of the input image and of the projection of the rectified image are identical.<br />

<strong>Note</strong> that it is also possible to define the WCS such that the rectified image does not lie or lies only partly<br />

within the imaged area. The domain of the rectified image is set such that it contains only those pixels<br />

that lie within the imaged area, i.e., for which gray value information is available. In figure 27, the WCS<br />

has been defined such that the upper part of the rectified image lies outside the imaged area. To illustrate<br />

this, the part of the rectified image for which no gray value information is available is displayed dark<br />

gray. Also in figure 27, the full domain of the rectified image, transformed into the virtual image plane<br />

Single Camera


52 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

of the input image, is displayed. It can be seen that for the upper part of the rectified image no image<br />

information is available.<br />

Camera with<br />

optical center<br />

Virtual image plane<br />

y w<br />

z w<br />

Measurement plane ( = 0)<br />

r<br />

y c<br />

z c<br />

f<br />

c<br />

Hw z w<br />

x w<br />

x c<br />

Rectified image<br />

c<br />

x c y c z c Camera coordinate system ( , , )<br />

Image coordinate system ( r, c)<br />

World coordinate system ( )<br />

x w y w z w<br />

, ,<br />

Figure 27: Projection of the image into the measurement plane with part of the rectified image lying outside<br />

the image area.<br />

If several images must be rectified using the same camera parameters the operator<br />

gen_image_to_world_plane_map in combination with map_image is much more efficient than<br />

the operator image_to_world_plane because the transformation must be determined only once. In<br />

this case, a projection map that describes the transformation between the image plane and the world<br />

plane is generated first by the operator gen_image_to_world_plane_map. Then, this map is used by<br />

the operator map_image to transform the image very efficiently.


3.3.1 Transforming Images into the WCS 53<br />

The following example from hdevelop\transform_image_into_wcs.dev shows how to perform<br />

the transformation of images into the world coordinate system using the operators<br />

gen_image_to_world_plane_map together with map_image as well as the operator<br />

image_to_world_plane.<br />

In the first part of the example program the parameters Scale and CamPose are set such that a given<br />

point appears in the center of the rectified image and that in the surroundings of this point the scale of<br />

the rectified image is similar to the scale of the original image.<br />

First, the size of the rectified image is defined.<br />

WidthMappedImage := 652<br />

HeightMappedImage := 494<br />

Then, the scale is determined based on the ratio of the distance between points in the WCS and of the<br />

respective distance in the ICS.<br />

Dist_ICS := 1<br />

image_points_to_world_plane (CamParam, Pose, CenterRow, CenterCol, 1,<br />

CenterX, CenterY)<br />

image_points_to_world_plane (CamParam, Pose, CenterRow+Dist_ICS,<br />

CenterCol, 1, BelowCenterX, BelowCenterY)<br />

image_points_to_world_plane (CamParam, Pose, CenterRow,<br />

CenterCol+Dist_ICS, 1, RightOfCenterX,<br />

RightOfCenterY)<br />

distance_pp (CenterY, CenterX, BelowCenterY, BelowCenterX,<br />

Dist_WCS_Vertical)<br />

distance_pp (CenterY, CenterX, RightOfCenterY, RightOfCenterX,<br />

Dist_WCS_Horizontal)<br />

ScaleVertical := Dist_WCS_Vertical/Dist_ICS<br />

ScaleHorizontal := Dist_WCS_Horizontal/Dist_ICS<br />

ScaleForCenteredImage := (ScaleVertical+ScaleHorizontal)/2.0<br />

Now, the pose of the measurement plane is modified such that a given point will be displayed in the<br />

center of the rectified image.<br />

DX := CenterX-ScaleForCenteredImage*WidthMappedImage/2.0<br />

DY := CenterY-ScaleForCenteredImage*HeightMappedImage/2.0<br />

DZ := 0<br />

set_origin_pose (Pose, DX, DY, DZ, PoseForCenteredImage)<br />

These calculations are implemented in the HDevelop procedure<br />

procedure parameters_image_to_world_plane_centered (: : CamParam, Pose,<br />

CenterRow, CenterCol,<br />

WidthMappedImage,<br />

HeightMappedImage:<br />

ScaleForCenteredImage,<br />

PoseForCenteredImage)<br />

which is part of the example program hdevelop\transform_image_into_wcs.dev (see appendix B.2<br />

on page 138).<br />

Single Camera


54 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Finally, the image can be transformed.<br />

gen_image_to_world_plane_map (Map, CamParam, PoseForCenteredImage,<br />

WidthOriginalImage, HeightOriginalImage,<br />

WidthMappedImage, HeightMappedImage,<br />

ScaleForCenteredImage, ’bilinear’)<br />

map_image (Image, Map, ImageMapped)<br />

The second part of the example program hdevelop\transform_image_into_wcs.dev shows how to<br />

set the parameters Scale and CamPose such that the entire image is visible in the rectified image.<br />

First, the image coordinates of the border of the original image are transformed into world coordinates.<br />

full_domain (Image, ImageFull)<br />

get_domain (ImageFull, Domain)<br />

gen_contour_region_xld (Domain, ImageBorder, ’border’)<br />

contour_to_world_plane_xld (ImageBorder, ImageBorderWCS, CamParam,<br />

Pose, 1)<br />

Then, the extent of the image in world coordinates is determined.<br />

smallest_rectangle1_xld (ImageBorderWCS, MinY, MinX, MaxY, MaxX)<br />

ExtentX := MaxX-MinX<br />

ExtentY := MaxY-MinY<br />

The scale is the ratio of the extent of the image in world coordinates and of the size of the rectified image.<br />

ScaleX := ExtentX/WidthMappedImage<br />

ScaleY := ExtentY/HeightMappedImage<br />

Now, the maximum value must be selected as the final scale.<br />

ScaleForEntireImage := max([ScaleX,ScaleY])<br />

Finally, the origin of the pose must be translated appropriately.<br />

set_origin_pose (Pose, MinX, MinY, 0, PoseForEntireImage)<br />

These calculations are implemented in the HDevelop procedure<br />

procedure parameters_image_to_world_plane_entire (Image: : CamParam, Pose,<br />

WidthMappedImage,<br />

HeightMappedImage:<br />

ScaleForEntireImage,<br />

PoseForEntireImage)<br />

which is part of the example program hdevelop\transform_image_into_wcs.dev (see appendix B.3<br />

on page 139).<br />

If the object is not planar the projection map that is needed by the operator map_image may be determined<br />

by the operator gen_grid_rectification_map, which is described in section 9.3 on page<br />

127.<br />

If only the radial distortions should be eliminated the projection map can be determined by the operator<br />

gen_radial_distortion_map, which is described in the following section.


3.3.2 Compensate for Radial Distortions Only<br />

3.3.2 Compensate for Radial Distortions Only 55<br />

The principle of the compensation for radial distortions has already be described in section 3.2.6 on page<br />

48.<br />

If only one image must be rectified the operator change_radial_distortion_image can be used. It<br />

is used analogously to the operator change_radial_distortion_contours_xld described in section<br />

3.2.6, with the only exception that a region of interest (ROI) can be defined with the parameter<br />

Region.<br />

change_radial_distortion_image (GrayImage, ROI, ImageRectifiedAdaptive,<br />

CamParOriginal, CamParVirtualAdaptive)<br />

Again, the interior parameters of the virtual camera (with κ = 0) can be determined by setting only<br />

κ to zero (see figure 28b) or by using the operator change_radial_distortion_cam_par with the<br />

parameter Mode set to ’fixed’ (equivalent to setting κ to zero; see figure 28b), ’adaptive’ (see figure 28c),<br />

or ’fullsize’ (see figure 28d).<br />

(a) (b)<br />

(c) (d)<br />

Figure 28: Eliminating radial distortions: (a) The original image; (b) the image rectified by setting κ to<br />

zero; (c) the image rectified with mode ’fullsize’; (d) the image rectified with mode ’adaptive’.<br />

If more than one image must be rectified, a projection map can be determined with<br />

the operator gen_radial_distortion_map, which is used analogously to the operator<br />

Single Camera


56 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

change_radial_distortion_image, followed by the actual transformation of the images, which is<br />

carried out by the operator map_image, described in section 3.3.1 on page 49. If a ROI is to be specified,<br />

it must be rectified separately (see section 3.2.4 on page 47).<br />

gen_radial_distortion_map (MapFixed, CamParOriginal, CamParVirtualFixed,<br />

’bilinear’)<br />

map_image (GrayImage, MapFixed, ImageRectifiedFixed)<br />

<strong>Note</strong> that this compensation for radial distortions is not possible for line scan images because of the<br />

acquisition geometry of line scan cameras. To eliminate radial distortions from line scan images, the<br />

images must be transformed into the WCS (see section 3.3.1 on page 49).<br />

3.4 Inspection of Non-Planar Objects<br />

<strong>Note</strong> that the measurements described so far will only be accurate if the object to be measured is planar,<br />

i.e., if it has a flat surface. If this is not the case the perspective projection of the pinhole camera (see<br />

equation 22 on page 20) will make the parts of the object that lie closer to the camera appear bigger than<br />

the parts that lie farther away. In addition, the respective world coordinates are displaced systematically.<br />

If you want to measure the top side of objects with a flat surface that have a significant thickness that is<br />

equal for all objects it is best to place the calibration plate onto one of these objects during calibration.<br />

With this, you can make sure that the optical rays are intersected with the correct plane.<br />

The displacement that results from deviations of the object surface from the measurement plane can be<br />

estimated very easily. Figure 29 shows a vertical section of a typical measurement configuration. The<br />

measurement plane is drawn as a thick line, the object surface as a dotted line. <strong>Note</strong> that the object surface<br />

does not correspond to the measurement plane in this case. The deviation of the object surface from the<br />

measurement plane is indicated by ∆z, the distance of the projection center from the measurement plane<br />

by z, and the displacement by ∆r. The point N indicates the perpendicular projection of the projection<br />

center (P C) onto the measurement plane.<br />

For the determination of the world coordinates of point Q, which lies on the object surface, the optical<br />

ray from the projection center of the camera through Q ′ , which is the projection of Q into the<br />

image plane, is intersected with the measurement plane. For this reason, the operators of the family<br />

..._to_world_plane do not return the world coordinates of Q, but the world coordinates of point P ,<br />

which is the perspective projection of point Q ′ onto the measurement plane.<br />

If we know the distance r from P to N, the distance z, which is the shortest distance from the projection<br />

center to the measurement plane, and the deviation ∆z of the object’s surface from the measurement<br />

plane, the displacement ∆r can be calculated by:<br />

∆r = ∆z · r<br />

z<br />

Often, it will be sufficient to have just a rough estimate for the value of ∆r. Then, the values r, z, and<br />

∆z can be approximately determined directly from the measurement setup.<br />

If you need to determine ∆r more precisely, you first have to calibrate the camera. Then you have to<br />

select a point Q ′ in the image for which you want to know the displacement ∆r. The transformation<br />

of Q ′ into the WCS using the operator image_points_to_world_plane yields the world coordinates<br />

of point P . Now, you need to derive the world coordinates of the point N. An easy way to<br />

(31)


P<br />

Virtual image plane<br />

∆r<br />

Q<br />

∆z<br />

Camera<br />

Projection center (PC)<br />

r<br />

P’ = Q’<br />

N<br />

z<br />

3.4 Inspection of Non-Planar Objects 57<br />

Object surface<br />

Measurement plane<br />

Figure 29: Displacement ∆r caused by a deviation of the object surface from the measurement plane.<br />

do this is to transform the camera coordinates of the projection center P C, which are (0, 0, 0) T , into<br />

the world coordinate system, using the operator affine_trans_point_3d. To derive the homogeneous<br />

transformation matrix W CS HCCS needed for the above mentioned transformation, first, generate<br />

the homogeneous transformation matrix CCS HW CS from the pose of the measurement plane via<br />

the operator pose_to_hom_mat3d and then, invert the resulting homogeneous transformation matrix<br />

(hom_mat3d_invert). Because N is the perpendicular projection of P C onto the measurement plane,<br />

its x and y world coordinates are equal to the respective world coordinates of P C and its z coordinate<br />

is equal to zero. Now, r and z can be derived as follows: r is the distance from P to N, which can be<br />

calculated by the operator distance_pp; z is simply the z coordinate of P C, given in the WCS.<br />

The following <strong>HALCON</strong> program (hdevelop\height_displacement.dev) shows how to implement<br />

this approach. First, the camera parameters are read from file.<br />

read_cam_par (’camera_parameters.dat’, CamParam)<br />

read_pose (’pose_from_three_points.dat’, Pose)<br />

Then, the deviation of the object surface from the measurement plane is set.<br />

DeltaZ := 2<br />

Finally, the displacement is calculated, according to the method described above.<br />

Single Camera


58 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

get_mbutton (WindowHandle, RowQ, ColumnQ, _)<br />

image_points_to_world_plane (CamParam, Pose, RowQ, ColumnQ, 1, WCS_PX,<br />

WCS_PY)<br />

pose_to_hom_mat3d (Pose, CCS_HomMat_WCS)<br />

hom_mat3d_invert (CCS_HomMat_WCS, WCS_HomMat_CCS)<br />

affine_trans_point_3d (WCS_HomMat_CCS, 0, 0, 0, WCS_PCX, WCS_PCY, WCS_PCZ)<br />

distance_pp (WCS_PX, WCS_PY, WCS_PCX, WCS_PCY, r)<br />

z := fabs(WCS_PCZ)<br />

DeltaR := DeltaZ*r/z<br />

Assuming a constant ∆z, the following conclusions can be drawn for ∆r:<br />

• ∆r increases with increasing r.<br />

• If the measurement plane is more or less perpendicular to the optical axis, ∆r increases towards<br />

the image borders.<br />

• At the point N, ∆r is always equal to zero.<br />

• ∆r increases the more the measurement plane is tilted with respect to the optical axis.<br />

The maximum acceptable deviation of the object’s surface from the measurement plane, given a maximum<br />

value for the resulting displacement, can be derived by the following formula:<br />

∆z = ∆r · z<br />

r<br />

The values for r and z can be determined as described above.<br />

If you want to inspect an object that has a surface that consists of several parallel planes you can first use<br />

equation 32 to evaluate if the measurement errors stemming from the displacements are acceptable within<br />

your project or not. If the displacements are too large, you can calibrate the camera such that the measurement<br />

plane corresponds to, e.g., the uppermost plane of the object. Now, you can derive a pose for<br />

each plane, which is parallel to the uppermost plane simply by applying the operator set_origin_pose.<br />

This approach is also useful if objects of different thickness may appear on the assembly line. If it is possible<br />

to classify these objects into classes corresponding to their thickness, you can select the appropriate<br />

pose for each object. Thus, it is possible to derive accurate world coordinates for each object.<br />

<strong>Note</strong> that if the plane in which the object lies is severely tilted with respect to the optical axis, and if the<br />

object has a significant thickness, the camera will likely see some parts of the object that you do not want<br />

to measure. For example, if you want to measure the top side of a cube and the plane is tilted, you will<br />

see the side walls of the cube as well, and therefore might measure the wrong dimensions. Therefore,<br />

it is usually best to align the camera so that its optical axis is perpendicular to the plane in which the<br />

objects are measured. If the objects do not have significant thickness, you can measure them accurately<br />

even if the plane is tilted.<br />

What is more, it is even possible to derive world coordinates for an object’s surface that consists of<br />

several non-parallel planes if the relation between the individual planes is known. In this case, you may<br />

define the relative pose of the tilted plane with respect to an already known measurement plane.<br />

RelPose := [0,3.2,0,-14,0,0,0]<br />

Then, you can transform the known pose of the measurement plane into the pose of the tilted plane.<br />

(32)


pose_to_hom_mat3d (FinalPose, HomMat3D)<br />

pose_to_hom_mat3d (RelPose, HomMat3DRel)<br />

hom_mat3d_compose (HomMat3D, HomMat3DRel, HomMat3DAdapted)<br />

hom_mat3d_to_pose (HomMat3DAdapted, PoseAdapted)<br />

4 Calibrated Mosaicking 59<br />

Alternatively, you can use the operators of the family hom_mat3d_..._local to adapt the pose.<br />

hom_mat3d_translate_local (HomMat3D, 0, 3.2, 0, HomMat3DTranslate)<br />

hom_mat3d_rotate_local (HomMat3DTranslate, rad(-14), ’x’, HomMat3DAdapted)<br />

hom_mat3d_to_pose (HomMat3DAdapted, PoseAdapted)<br />

Now, you can obtain world coordinates for points lying on the tilted plane, as well.<br />

contour_to_world_plane_xld (Lines, ContoursTrans, CamParam, PoseAdapted, 1)<br />

If the object is to complex to be approximated by planes, or if the relations between the planes are<br />

not known, it is not possible to perform precise measurements in world coordinates using the methods<br />

described in this section. In this case, it is necessary to use two cameras and to apply the <strong>HALCON</strong><br />

stereo operators described in section 7 on page 88.<br />

4 Calibrated Mosaicking<br />

Some objects are too large to be covered by one single image. Multiple images that cover different parts<br />

of the object must be taken in such cases. You can measure precisely across the different images if<br />

the cameras are calibrated and their exterior parameters are known with respect to one common world<br />

coordinate system.<br />

It is even possible to merge the individual images into one larger image that covers the whole object. This<br />

is done by rectifying the individual images with respect to the same measurement plane (see section 3.3.1<br />

on page 49). In the resulting image, you can measure directly in world coordinates.<br />

<strong>Note</strong> that the 3D coordinates of objects are derived based on the same principle as described in section 3<br />

on page 27, i.e., a measurement plane that coincides with the object surface must be defined. Although<br />

two or more cameras are used, this is no stereo approach. For more information on 3D machine vision<br />

with a binocular stereo system, please refer to section 7 on page 88.<br />

If the resulting image is not intended to serve for high-precision measurements in world coordinates, you<br />

can generate it using the mosaicking approach described in section 5 on page 69. With this approach, it<br />

is not necessary to calibrate the cameras.<br />

A setup for generating a high-precision mosaic image from two cameras is shown in figure 30. The<br />

cameras are mounted such that the resulting pair of images has a small overlap. The cameras are first<br />

calibrated and then the images are merged together into one larger image. All further explanations within<br />

this section refer to such a two-camera setup.<br />

Typically, the following steps must be carried out:<br />

1. Determination of the interior camera parameters for each camera separately.<br />

Mosaicking I


60 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Calibration<br />

Figure 30: Two-camera setup.<br />

2. Determination of the exterior camera parameters, using one calibration object, to facilitate that the<br />

relation between the cameras can be determined.<br />

3. Merge the images into one larger image that covers the whole object.<br />

4.1 Setup<br />

Two or more cameras must be mounted on a stable platform such that each image covers a part of the<br />

whole scene. The cameras can have an arbitrary orientation, i.e., it is not necessary that they are looking<br />

parallel or perpendicular onto the object surface.<br />

To setup focus, illumination, and overlap appropriately, use a big reference object that covers all fields<br />

of view. To permit that the images are merged into one larger image, they must have some overlap (see<br />

figure 31 for an example). The overlapping area can be even smaller than depicted in figure 31, since the<br />

overlap is only necessary to ensure that there are no gaps in the resulting combined image.


4.2 Calibration<br />

{<br />

{<br />

Overlapping area<br />

Figure 31: Overlapping images.<br />

The calibration of the images can be broken down into two separate steps.<br />

4.2 Calibration 61<br />

The first step is to determine the interior camera parameters for each of the cameras in use. This can be<br />

done for each camera independently, as described in section 3.1.4 on page 36.<br />

The second step is to determine the exterior camera parameters for all cameras. Because the final coordinates<br />

should refer to one world coordinate system for all images, a big calibration object that appears<br />

in all images has to be used. We propose to use a calibration object like the one displayed in figure 32,<br />

which consists of as many calibration plates as the number of cameras that are used.<br />

For the determination of the exterior camera parameters, it is sufficient to use one calibration image from<br />

each camera only. <strong>Note</strong> that the calibration object must not be moved in between the acquisition of the<br />

individual images. Ideally, the images are acquired simultaneously.<br />

In each image, at least three points of the calibration object, i.e., points for which the world coordinates<br />

are known, have to be measured in the images. Based on these point correspondences, the operator<br />

camera_calibration can determine the exterior camera parameters for each camera. See section 3.1.5<br />

on page 39 for details.<br />

The calibration is easy if standard <strong>HALCON</strong> calibration plates mounted on some kind of carrier plate<br />

are used such that in each image one calibration plate is completely visible. An example for such a<br />

calibration object for a two-camera setup is given in figure 32. The respective calibration images for the<br />

determination of the exterior camera parameters are shown in figure 33. <strong>Note</strong> that the relative position<br />

of the calibration plates with respect to each other must be known precisely. This can be done with the<br />

pose estimation described in section 6 on page 84.<br />

<strong>Note</strong> also that only the relative position of the calibration marks among each other shows the high accuracy<br />

stated in section 3.1.6 on page 43 but not the borders of the calibration plate. The rows of calibration<br />

Mosaicking I


62 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

marks may be slanted with respect to the border of the calibration plate and even the distance of the calibration<br />

marks from the border of the calibration plate may vary. Therefore, aligning the calibration plates<br />

along their boundaries may result in a shift in x- and y-direction with respect to the coordinate system of<br />

the calibration plate in its initial position.<br />

Figure 32: Calibration object for two-camera setup.<br />

Figure 33: Calibration images for two-camera setup.<br />

The world coordinates of the calibration marks of each calibration plate can be read from the respective<br />

calibration plate description file.<br />

caltab_points (CaltabName, X, Y, Z)<br />

If an arbitrary calibration object is used, these coordinates must be determined precisely in advance. For<br />

<strong>HALCON</strong> calibration plates, the image coordinates of the calibration marks as well as the initial values<br />

for the poses can be determined easily with the operators find_caltab and find_marks_and_pose.


4.3 Merging the Individual Images into One Larger Image 63<br />

min_max_gray (Image1, Image1, 3, Min, _, _)<br />

find_caltab (Image1, Caltab, CaltabName, 3, min([Min+40,200]), 5)<br />

find_marks_and_pose (Image1, Image1, CaltabName, CamParam1, 128, 10, 18,<br />

0.7, 15, 100, RCoord1, CCoord1, StartPose1)<br />

min_max_gray (Image2, Image2, 3, Min, _, _)<br />

find_caltab (Image2, Caltab, CaltabName, 3, min([Min+40,200]), 5)<br />

find_marks_and_pose (Image2, Image2, CaltabName, CamParam2, 128, 10, 18,<br />

0.7, 15, 100, RCoord2, CCoord2, StartPose2)<br />

The following code fragments shows the calibration of the two-camera setup. It assumes that the interior<br />

camera parameters of both cameras are already known.<br />

camera_calibration (X, Y, Z, RCoord1, CCoord1, CamParam1, StartPose1,<br />

’pose’, _, Pose1, Errors1)<br />

camera_calibration (X, Y, Z, RCoord2, CCoord2, CamParam2, StartPose2,<br />

’pose’, _, Pose2, Errors2)<br />

4.3 Merging the Individual Images into One Larger Image<br />

At first, the individual images must be rectified, i.e, transformed so that they exactly fit together. This<br />

can be achieved by using the operators gen_image_to_world_plane_map and map_image. Then,<br />

the mosaic image can be generated by the operator tile_images, which tiles multiple images into one<br />

larger image. These steps are visualized in figure 34.<br />

The operators gen_image_to_world_plane_map and map_image are described in section 3.3.1 on<br />

page 49. In the following, we will only discuss the problem of defining the appropriate image detail, i.e.,<br />

the position of the upper left corner and the size of the rectified images. Again, the description is based<br />

on the two-camera setup.<br />

4.3.1 Definition of the Rectification of the First Image<br />

For the first (here: left) image, the determination of the necessary shift of the pose is straightforward.<br />

You can define the upper left corner of the rectified image in image coordinates, e.g., interactively or, as<br />

in the example program, based on a preselected border width.<br />

ULRow := HeightImage1*BorderInPercent/100.0<br />

ULCol := WidthImage1*BorderInPercent/100.0<br />

Then, this point must be transformed into world coordinates.<br />

image_points_to_world_plane (CamParam1, Pose1, ULRow, ULCol, ’m’, ULX, ULY)<br />

The resulting coordinates can be used directly, together with the shift that compensates the thickness of<br />

the calibration plate (see section 3.1.5 on page 39) to modify the origin of the world coordinate system<br />

in the left image.<br />

set_origin_pose (Pose1, ULX, ULY, DiffHeight, PoseNewOrigin1)<br />

This means that we shift the origin of the world coordinate system from the center of the calibration plate<br />

to the position that defines the upper left corner of the rectified image (figure 35).<br />

Mosaicking I


64 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

map_image map_image<br />

tile_images<br />

Figure 34: Image rectification and tiling.<br />

The size of the rectified image, i.e., its width and height, can be determined from points originally defined<br />

in image coordinates, too. In addition, the desired pixel size of the rectified image must be specified.<br />

PixelSize := 0.0001<br />

For the determination of the height of the rectified image we need to define a point that lies near the<br />

lower border of the first image.<br />

LowerRow := HeightImage1*(100-BorderInPercent)/100.0<br />

Again, this point must be transformed into the world coordinate system.


Image 1<br />

Rectified image 1<br />

4.3.1 Definition of the Rectification of the First Image 65<br />

Image 2<br />

Figure 35: Definition of the upper left corner of the first rectified image.<br />

image_points_to_world_plane (CamParam1, Pose1, LowerRow, ULCol, ’m’, _,<br />

LowerY)<br />

The height can be determined as the vertical distance between the upper left point and the point near the<br />

lower image border, expressed in pixels of the rectified image.<br />

HeightRect := int((LowerY-ULY)/PixelSize)<br />

Analogously, the width can be determined from a point that lies in the overlapping area of the two images,<br />

i.e., near the right border of the first image.<br />

RightCol := WidthImage1*(100-OverlapInPercent/2.0)/100.0<br />

image_points_to_world_plane (CamParam1, Pose1, ULRow, RightCol, ’m’,<br />

RightX, _)<br />

WidthRect := int((RightX-ULX)/PixelSize)<br />

<strong>Note</strong> that the above described definitions of the image points, from which the upper left corner and the<br />

size of the rectified image are derived, assume that the x- and y-axes of the world coordinate system are<br />

approximately aligned to the column- and row-axes of the first image. This can be achieved by placing<br />

the calibration plate in the first image approximately aligned with the image borders. Otherwise, the<br />

distances between the above mentioned points make no sense and the upper left corner and the size of<br />

the rectified image must be determined in a manner that is adapted for the configuration at hand.<br />

With the shifted pose and the size of the rectified image, the rectification map for the first image can be<br />

derived.<br />

Mosaicking I


66 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

gen_image_to_world_plane_map (MapSingle1, CamParam1, PoseNewOrigin1, Width,<br />

Height, WidthRect, HeightRect, PixelSize,<br />

’bilinear’)<br />

4.3.2 Definition of the Rectification of the Second Image<br />

The second image must be rectified such that it fits exactly to the right of the first rectified image. This<br />

means that the upper left corner of the second rectified image must be identical with the upper right<br />

corner of the first rectified image. Therefore, we need to know the coordinates of the upper right corner<br />

of the first rectified image in the coordinate system that is defined by the calibration plate in the second<br />

image.<br />

First, we express the upper right corner of the first rectified image in the world coordinate system that<br />

is defined by the calibration plate in the first image. It can be determined by a transformation from<br />

the origin into the upper left corner of the first rectified image (a translation in the example program)<br />

followed by a translation along the upper border of the first rectified image. Together with the shift that<br />

compensates the thickness of the calibration plate, this transformation is represented by the homogeneous<br />

transformation matrix cp1 Hur1 (see figure 36), which can be defined in HDevelop by:<br />

hom_mat3d_translate_local (HomMat3DIdentity, ULX+PixelSize*WidthRect, ULY,<br />

DiffHeight, cp1Hur1)<br />

Image 1<br />

Rectified image 1<br />

cp1 H ur1<br />

Rectified image 2<br />

Image 2<br />

Figure 36: Definition of the upper right corner of the first rectified image.<br />

Then, we need the transformation between the two calibration plates of the calibration object. The<br />

homogeneous transformation matrix cp1 Hcp2 describes how the world coordinate system defined by<br />

the calibration plate in the first image is transformed into the world coordinate system defined by the


4.3.2 Definition of the Rectification of the Second Image 67<br />

calibration plate in the second image (figure 37). This transformation must be known beforehand from a<br />

precise measurement of the calibration object.<br />

Image 1<br />

Rectified image 1<br />

cp1<br />

H<br />

cp2<br />

Rectified image 2<br />

Image 2<br />

Figure 37: Transformation between the two world coordinate systems, each defined by the respective<br />

calibration plate.<br />

From these two transformations, it is easy to derive the transformation that transforms the world coordinate<br />

system of the second image such that its origin lies in the upper left corner of the second rectified<br />

image. For this, the two transformations have to be combined appropriately (see figure 38):<br />

This can be implemented in HDevelop as follows:<br />

hom_mat3d_invert (cp1Hcp2, cp2Hcp1)<br />

hom_mat3d_compose (cp2Hcp1, cp1Hur1, cp2Hul2)<br />

cp2 Hul2 = cp2 Hcp1 · cp1 Hur1 (33)<br />

= ( cp1 Hcp2) −1 · cp1 Hur1 (34)<br />

With this, the pose of the calibration plate in the second image can be modified such that the origin of<br />

the world coordinate system lies in the upper left corner of the second rectified image:<br />

pose_to_hom_mat3d (Pose2, cam2Hcp2)<br />

hom_mat3d_compose (cam2Hcp2, cp2Hul2, cam2Hul2)<br />

hom_mat3d_to_pose (cam2Hul2, PoseNewOrigin2)<br />

With the resulting new pose and the size of the rectified image, which can be the same as for the first<br />

rectified image, the rectification map for the second image can be derived.<br />

Mosaicking I


68 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Image 1<br />

Rectified image 1<br />

cp1 H ur1<br />

cp2<br />

H<br />

cp1<br />

cp2<br />

H<br />

ul2<br />

Rectified image 2<br />

Image 2<br />

Figure 38: Definition of the upper left corner of the second rectified image.<br />

gen_image_to_world_plane_map (MapSingle2, CamParam2, PoseNewOrigin2, Width,<br />

Height, WidthRect, HeightRect, PixelSize,<br />

’bilinear’)<br />

4.3.3 Rectification of the Images<br />

Once the rectification maps are created, every image pair from the two-camera setup can be rectified and<br />

tiled very efficiently. The resulting mosaic image consists of the two rectified images and covers a part<br />

as indicated in figure 39.<br />

The rectification is carried out by the operator map_image.<br />

map_image (Image1, MapSingle1, RectifiedImage1)<br />

map_image (Image2, MapSingle2, RectifiedImage2)<br />

This transforms the two images displayed in figure 40, into the two rectified images that are shown in<br />

figure 41.<br />

As a preparation for the tiling, the rectified images must be concatenated into one tuple, which then<br />

contains both images.<br />

Concat := [RectifiedImage1,RectifiedImage2]<br />

Then the two images can be tiled.


Image 1<br />

Mosaic image<br />

Figure 39: The position of the final mosaic image.<br />

Figure 40: Two test images acquired with the two-camera setup.<br />

tile_images (Concat, Combined, 2, ’vertical’)<br />

The resulting mosaic image is displayed in figure 42.<br />

5 Uncalibrated Mosaicking<br />

5 Uncalibrated Mosaicking 69<br />

Image 2<br />

If you need an image of a large object, but the field of view of the camera does not allow to cover the<br />

entire object with the desired resolution, you can use image mosaicking to generate a large image of the<br />

Mosaicking II


70 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Figure 41: Rectified images.<br />

Figure 42: Mosaic image.<br />

entire object from a sequence of overlapping images of parts of the object.<br />

An example for such an application is given in figure 43. On the left side, six separate images are<br />

displayed stacked upon each other. On the right side, the mosaic image generated from the six separate<br />

images is shown. <strong>Note</strong> that the folds visible in the image do not result from the mosaicking. They are<br />

due to some degradations on the PCB, which can be seen already in the separate images.<br />

The mosaicking approach described in this section is designed for applications where it is not necessary<br />

to achieve the high-precision mosaic images as described in section 4 on page 59. The advantages<br />

compared to this approach are that no camera calibration is necessary and that the individual images can<br />

be arranged automatically.<br />

The following example program (hdevelop\mosaicking.dev) generates the mosaic image displayed<br />

in figure 49 on page 76. First, the images are read from file and collected in one tuple.


→<br />

Figure 43: A first example for image mosaicking.<br />

5 Uncalibrated Mosaicking 71<br />

Mosaicking II


72 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Images := []<br />

for J := 1 to 10 by 1<br />

read_image (Image, ImgPath+ImgName+J$’02’)<br />

Images := [Images,Image]<br />

endfor<br />

Then, the image pairs must be defined, i.e., which image should be mapped to which image.<br />

From := [1,2,3,4,6,7,8,9,3]<br />

To := [2,3,4,5,7,8,9,10,8]<br />

Now, characteristic points must be extracted from the images, which are then used for the matching<br />

between the image pairs. The resulting projective transformation matrices 1 must be accumulated.<br />

Num := |From|<br />

ProjMatrices := []<br />

for J := 0 to Num-1 by 1<br />

F := From[J]<br />

T := To[J]<br />

ImageF := Images[F]<br />

ImageT := Images[T]<br />

points_harris (ImageF, SigmaGrad, SigmaSmooth, Alpha, Threshold,<br />

RowFAll, ColFAll)<br />

points_harris (ImageT, SigmaGrad, SigmaSmooth, Alpha, Threshold,<br />

RowTAll, ColTAll)<br />

proj_match_points_ransac (ImageF, ImageT, RowFAll, ColFAll, RowTAll,<br />

ColTAll, ’sad’, MaskSize, RowMove, ColMove,<br />

RowTolerance, ColTolerance, Rotation,<br />

MatchThreshold, ’gold_standard’,<br />

DistanceThreshold, RandSeed, ProjMatrix,<br />

Points1, Points2)<br />

ProjMatrices := [ProjMatrices,ProjMatrix]<br />

endfor<br />

Finally, the image mosaic can be generated.<br />

gen_projective_mosaic (Images, MosaicImage, StartImage, From, To,<br />

ProjMatrices, StackingOrder, ’false’,<br />

MosaicMatrices2D)<br />

<strong>Note</strong> that image mosaicking is a tool for a quick and easy generation of large images from several<br />

overlapping images. For this task, it is not necessary to calibrate the camera. If you need a high-precision<br />

image mosaic, you should use the method described in section 4 on page 59.<br />

In the following sections, the individual steps for the generation of a mosaic image are described.<br />

5.1 Rules for Taking Images for a Mosaic Image<br />

The following rules for the acquisition of the separate images should be considered:<br />

1 A projective transformation matrix describes a perspective projection. It consists of 3×3 values. If the last row contains the<br />

values [0,0,1], it corresponds to a homogeneous transformation matrix of <strong>HALCON</strong> and therefore describes an affine transformation.


• The images must overlap each other.<br />

5.1 Rules for Taking Images for a Mosaic Image 73<br />

• The overlapping area of the images must be textured in order to allow the automatic matching<br />

process to identify identical points in the images. The lack of texture in some overlapping areas<br />

may be overcome by an appropriate definition of the image pairs (see section 5.2 on page 75). If<br />

the whole object shows little texture, the overlapping areas should be chosen larger.<br />

• Overlapping images must have approximately the same scale. In general, the scale differences<br />

should not exceed 5-10 %.<br />

• The images should be radiometrically similar, at least in the overlapping areas, as no radiometric<br />

adaption of the images is carried out. Otherwise, i.e., if the brightness differs heavily between<br />

neighboring images, the seams between them will be clearly visible as can be seen in figure 44.<br />

→<br />

Figure 44: A second example for image mosaicking.<br />

The images are mapped onto a common image plane using a projective transformation. Therefore, to<br />

generate a geometrically accurate image mosaic from images of non-flat objects, the separate images<br />

must be acquired from approximately the same point of view, i.e., the camera can only be rotated around<br />

its optical center (see figure 45).<br />

When dealing with flat objects, it is possible to acquire the images from arbitrary positions and with<br />

arbitrary orientations if the scale difference between the overlapping images is not too large (figure 46).<br />

The radial distortions of the images are not compensated by the mosaicking process. Therefore, if<br />

radial distortions are present in the images, they cannot be mosaicked with high accuracy, i.e., small<br />

distortions at the seams between neighboring images cannot be prevented (see figure 50 on page 77). To<br />

Mosaicking II


74 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Camera in three orientations<br />

Common optical center<br />

Object surface<br />

Camera in three positions<br />

Object surface<br />

Figure 45: Image acquisition for non-flat objects.<br />

Figure 46: Image acquisition for flat objects.<br />

eliminate this effect, the radial distortions can be compensated before starting the mosaicking process<br />

(see section 3.3.2 on page 55).<br />

If processing time is an issue, it is advisable to acquire the images in the same orientation, i.e., neither<br />

the camera nor the object should be rotated around the optical axis, too much. Then, the rotation range<br />

can be restricted for the matching process (see section 5.4 on page 79).


5.2 Definition of Overlapping Image Pairs<br />

5.2 Definition of Overlapping Image Pairs 75<br />

As shown in the introductory example, it is necessary to define the overlapping image pairs between<br />

which the transformation is to be determined. The successive matching process will be carried out for<br />

these image pairs only.<br />

1 2 3<br />

1 2<br />

3 4<br />

(a) (b)<br />

Figure 47: Two configurations of overlapping images.<br />

Figure 47 shows two configurations of separate images. For configuration (a), the definition of the image<br />

pairs is simply (1,2) and (2,3), which can be defined in HDevelop as:<br />

From:=[1,2]<br />

To:=[2,3]<br />

In any case, it is important to ensure that each image must be “connected” to all the other images. For<br />

example, for configuration (b) of figure 47, it is not possible to define the image pairs as (1,2) and (3,4),<br />

only, because images 1 and 2 would not be connected to images 3 and 4. In this case, it would, e.g., be<br />

possible to define the three image pairs (1,2), (1,3), and (2,4):<br />

From:=[1,1,2]<br />

To:=[2,3,4]<br />

Assuming there is no texture in the overlapping area of image two and four, the matching could be carried<br />

out between images three and four instead:<br />

From:=[1,1,3]<br />

To:=[2,3,4]<br />

If a larger number of separate images are mosaicked, or, e.g., an image configuration similar to the<br />

one displayed in figure 48, where there are elongated rows of overlapping images, it is important to<br />

thoroughly arrange the image pair configuration. Otherwise it is possible that some images do not fit<br />

together precisely. This happens since the transformations between the images cannot be determined<br />

with perfect accuracy because of very small errors in the point coordinates due to noise. These errors are<br />

propagated from one image to the other.<br />

Mosaicking II


76 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

1 2 3 4 5<br />

6 7 8 9 10<br />

Figure 48: A configuration of ten overlapping images.<br />

Figure 49 shows such an image sequence of ten images of a BGA and the resulting mosaic image.<br />

Figure 50 shows a cut-out of that mosaic image. It depicts the seam between image 5 and image 10 for<br />

two image pair configurations, using the original images and the images where the radial distortions have<br />

been eliminated, respectively. The position of the cut-out is indicated in figure 49 by a rectangle.<br />

→<br />

Figure 49: Ten overlapping images and the resulting (rigid) mosaic image.<br />

First, the matching has been carried out in the two image rows separately and the two rows are connected<br />

via image pair 1 → 6:


unfavorable configuration<br />

good configuration<br />

5.2 Definition of Overlapping Image Pairs 77<br />

with radial distortions radial distortions eliminated<br />

Figure 50: Seam between image 5 and image 10 for various configurations.<br />

From:=[1,2,3,4,6,7,8,9,1]<br />

To:=[2,3,4,5,7,8,9,10,6]<br />

In this configuration the two neighboring images 5 and 10 are connected along a relatively long path<br />

(figure 51).<br />

1 2 3 4 5<br />

6 7 8 9 10<br />

Figure 51: Unfavorable configuration of image pairs.<br />

To improve the geometrical accuracy of the image mosaic, the connections between the two image rows<br />

could be established by the image pair (3,8), as visualized in (figure 52)).<br />

1 2 3 4 5<br />

6 7 8 9 10<br />

Figure 52: Good configuration of image pairs.<br />

This can be achieved by defining the image pairs as follows.<br />

From:=[1,2,3,4,6,7,8,9,3]<br />

To:=[2,3,4,5,7,8,9,10,8]<br />

As can be seen in figure 50, now the neighboring images fit better.<br />

Recapitulating, there are three basic rules for the arrangement of the image pairs:<br />

Take care that<br />

1. each image is connected to all the other images.<br />

Mosaicking II


78 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

2. the path along which neighboring images are connected is not too long.<br />

3. the overlapping areas of image pairs are large enough and contain enough texture to ensure a<br />

proper matching.<br />

In principle, it is also possible to define more image pairs than required (number of images minus one).<br />

However, then it cannot be controlled which pairs are actually used. Therefore, we do not recommend<br />

this approach.<br />

5.3 Detection of Characteristic Points<br />

<strong>HALCON</strong> provides you with various operators for the extraction of characteristic points (interest points).<br />

The most important of these operators are<br />

• points_foerstner<br />

• points_harris<br />

• points_sojka<br />

• saddle_points_sub_pix<br />

All of these operators can determine the coordinates of interest points with subpixel accuracy.<br />

In figure 53, a test image together with typical results of these interest operators is displayed.<br />

The operator points_foerstner classifies the interest points into two categories: junction-like features<br />

and area-like features. The results are very reproducible even in images taken from a different point of<br />

view. Therefore, it is very well suited for the extraction of points for the subsequent matching. It is very<br />

accurate but computationally the most expensive operator out of the four interest operators presented in<br />

this section.<br />

The results of the operator points_harris are very reproducible, too. Admittedly, the points extracted<br />

by the operator points_harris are sometimes not meaningful to a human, e.g., they often<br />

lie slightly beside a corner or an eye-catching image structure. Nevertheless, it is faster than the operator<br />

points_foerstner.<br />

The operator points_sojka is specialized in the extraction of corner points. It is the fastest out of the<br />

four operators presented in this section.<br />

The operator saddle_points_sub_pix is designed especially for the extraction of saddle points, i.e.,<br />

points whose image intensity is minimal along one direction and maximal along a different direction.<br />

The number of interest points influence the execution time and the result of the subsequent matching<br />

process. The more interest points are used, the longer the matching takes. If too few points are used the<br />

probability of an erroneous result increases.<br />

In most cases, the default parameters of the interest operators need not be changed. Only if too many<br />

or too few interest points are found adaptations of the parameters might be necessary. For a description<br />

of the parameters, please refer to the respective pages of the reference manual (points_foerstner,<br />

points_harris, points_sojka, saddle_points_sub_pix).


(a) (b) (c)<br />

(d) (e) (f)<br />

5.4 Matching of Characteristic Points 79<br />

Figure 53: Comparison of typical results of interest operators. a) Test image; b) Förstner, junctions; c)<br />

Förstner, area; d) Harris; e) Sojka; f) Saddle points.<br />

5.4 Matching of Characteristic Points in Overlapping Areas and Determination<br />

of the Transformation between the Images<br />

The most demanding task during the generation of an image mosaic is the matching process. The operator<br />

proj_match_points_ransac is able to perform the matching even if the two images are shifted<br />

and rotated arbitrarily.<br />

proj_match_points_ransac (ImageF, ImageT, RowFAll, ColFAll, RowTAll,<br />

ColTAll, ’sad’, MaskSize, RowMove, ColMove,<br />

RowTolerance, ColTolerance, Rotation,<br />

MatchThreshold, ’gold_standard’,<br />

DistanceThreshold, RandSeed, ProjMatrix,<br />

Points1, Points2)<br />

The only requirement is that the images should have approximately the same scale. If information about<br />

shift and rotation is available it can be used to restrict the search space, which speeds up the matching<br />

process and makes it more robust.<br />

In case the matching fails, ensure that there are enough characteristic points and that the search space<br />

and the maximum rotation are defined appropriately.<br />

Mosaicking II


80 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

If the images that should be mosaicked contain repetitive patterns, like the two images of a BGA shown<br />

in figure 54a, it may happen that the matching does not work correctly. In the resulting erroneous mosaic<br />

image, the separate images may not fit together or may be heavily distorted. To achieve a correct matching<br />

result for such images, it is important to provide initial values for the shift between the images with<br />

the parameters RowMove and ColMove. In addition, the search space should be restricted to an area that<br />

contains only one instance of the repetitive pattern, i.e., the values of the parameters RowTolerance<br />

and ColTolerance should be chosen smaller than the distance between the instances of the repetitive<br />

pattern. With this, it is possible to obtain proper mosaic images, even for objects like BGAs (see<br />

figure 54b).<br />

(a)<br />

Figure 54: Separate images (a) and mosaic image (b) of a BGA.<br />

For a detailed description of the other parameters, please refer to the reference manual<br />

(proj_match_points_ransac).<br />

The results of the operator proj_match_points_ransac are the projective transformation matrix and<br />

the two tuples Points1 and Points2 that contain the indices of the matched input points from the two<br />

images.<br />

The projective transformation matrices resulting from the matching between the image pairs must be<br />

accumulated.<br />

ProjMatrices := [ProjMatrices,ProjMatrix]<br />

Alternatively, if it is known that the mapping between the images is a rigid 2D transformation, the<br />

operator proj_match_points_ransac can be used to determine the point correspondences only, since<br />

it returns the indices of the corresponding points in the tuples Points1 and Points2. With this, the<br />

corresponding point coordinates can be selected.<br />

(b)


RowF := subset(RowFAll,Points1)<br />

ColF := subset(ColFAll,Points1)<br />

RowT := subset(RowTAll,Points2)<br />

ColT := subset(ColTAll,Points2)<br />

5.5 Generation of the Mosaic Image 81<br />

Then, the rigid transformation between the image pair can be determined with the operator<br />

vector_to_rigid. <strong>Note</strong> that we have to add 0.5 to the coordinates to make the extracted pixel positions<br />

fit the coordinate system that is used by the operator gen_projective_mosaic.<br />

vector_to_rigid (RowF+0.5, ColF+0.5, RowT+0.5, ColT+0.5, HomMat2D)<br />

Because gen_projective_mosaic expects a 3×3 transformation matrix, but vector_to_rigid returns<br />

a 2×3 matrix, we have to add the last row [0,0,1] to the transformation matrix before we can<br />

accumulate it.<br />

ProjMatrix := [HomMat2D,0,0,1]<br />

ProjMatrices := [ProjMatrices,ProjMatrix]<br />

5.5 Generation of the Mosaic Image<br />

Once the transformations between the image pairs are known the mosaic image can be generated with<br />

the operator gen_projective_mosaic.<br />

gen_projective_mosaic (Images, MosaicImage, StartImage, From, To,<br />

ProjMatrices, StackingOrder, ’false’,<br />

MosaicMatrices2D)<br />

It requires the images to be given in a tuple. All images are projected into the image plane of a so-called<br />

start image. The start image can be defined by its position in the image tuple (starting with 1) with the<br />

parameter StartImage.<br />

Additionally, the image pairs must be specified together with the corresponding transformation matrices.<br />

The order in which the images are added to the mosaic image can be specified with the parameter<br />

StackingOrder. The first index in this array will end up at the bottom of the image stack while the<br />

last one will be on top. If ’default’ is given instead of an array of integers, the canonical order (the order<br />

in which the images are given) will be used.<br />

If the domains of the images should be transformed as well, the parameter TransformRegion must be<br />

set to ’true’.<br />

The output parameter MosaicMatrices2D contains the projective 3×3 transformation matrices for<br />

the mapping of the separate images into the mosaic image. These matrices can, e.g., be used to<br />

transform features extracted from the separate images into the mosaic image by using the operators<br />

projective_trans_pixel, projective_trans_region, projective_trans_contour_xld, or<br />

projective_trans_image.<br />

Mosaicking II


82 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

5.6 Bundle Adjusted Mosaicking<br />

It is also possible to generate the mosaic based on the matching results of all overlapping image pairs. The<br />

transformation matrices between the images are then determined together within one bundle adjustment.<br />

For this, the operators bundle_adjust_mosaic and gen_bundle_adjusted_mosaic are used.<br />

The main advantage of the bundle adjusted mosaicking compared with the mosaicking based on single<br />

image pairs is that the bundle adjustment determines the geometry of the mosaic as robustly as possible.<br />

Typically, this leads to more accurate results. Another advantage is that there is no need to figure out<br />

a good pair configuration, you simply pass the matching results of all overlapping image pairs. What<br />

is more, it is possible to define the class of transformations that is used for the transformation between<br />

the individual images. A disadvantage of the bundle adjusted mosaicking is that it takes more time to<br />

perform the matching between all overlapping image pairs instead of just using a subset. Furthermore, if<br />

the matching between two images was erroneous, sometimes the respective image pair is difficult to find<br />

in the set of all image pairs.<br />

With this, it is obvious that the bundle adjustment is worthwhile if there are multiple overlaps between<br />

the images, i.e., if there are more than n − 1 overlapping image pairs, with n being the number of<br />

images. Another reason for using the bundle adjusted mosaicking is the possibility to define the class of<br />

transformations.<br />

The example program hdevelop\bundle_adjusted_mosaicking.dev shows how to generate the<br />

bundle adjusted mosaic from the ten images of the BGA displayed in figure 49 on page 76. The design<br />

of the program is very similar to that of the example program hdevelop\mosaicking.dev, which<br />

is described in the introduction of section 5 on page 69. The main differences are that<br />

• the matching is carried out between all overlapping images,<br />

• in addition to the projective transformation matrices also the coordinates of the corresponding<br />

points must be accumulated, and<br />

• the operator gen_projective_mosaic is replaced with the operators bundle_adjust_mosaic<br />

and gen_bundle_adjusted_mosaic.<br />

First, the matching is carried out between all overlapping image pairs, which can be defined as follows:<br />

From := [1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5]<br />

To := [6,7,2,6,7,8,3,7,8,9,4,8,9,10,5,9,10]<br />

In addition to the accumulation of the projective transformation matrices, as described in section 5.4 on<br />

page 79, also the coordinates of the corresponding points as well as the number of corresponding points<br />

must be accumulated.<br />

Rows1 := [Rows1,subset(RowFAll,Points1)]<br />

Cols1 := [Cols1,subset(ColFAll,Points1)]<br />

Rows2 := [Rows2,subset(RowTAll,Points2)]<br />

Cols2 := [Cols2,subset(ColTAll,Points2)]<br />

NumCorrespondences := [NumCorrespondences,|Points1|]<br />

This data is needed by the operator bundle_adjust_mosaic, which determines the bundle adjusted<br />

transformation matrices.


undle_adjust_mosaic (10, StartImage, From, To, ProjMatrices, Rows1,<br />

Cols1, Rows2, Cols2, NumCorrespondences,<br />

Transformation, MosaicMatrices2D, Rows, Cols,<br />

Error)<br />

5.7 Spherical Mosaicking 83<br />

The parameter Transformation defines the class of transformations that is used for the transformation<br />

between the individual images. Possible values are ’projective’, ’affine’, ’similarity’, and ’rigid’. Thus, if<br />

you know, e.g., that the camera looks perpendicular onto a planar object and that the camera movement<br />

between the images is restricted to rotations and translations in the object plane, you can choose the<br />

transformation class ’rigid’. If translations may also occur in the direction perpendicular to the object<br />

plane, you must use ’similarity’ because this transformation class allows scale differences between the<br />

images. If the camera looks tilted onto the object, the transformation class ’projective’ must be used,<br />

which can be approximated by the transformation class ’affine’. Figure 55 shows cut-outs of the resulting<br />

mosaic images. They depict the seam between image 5 and image 10. The mosaic images have been<br />

created using the images where the radial distortions have been eliminated. The position of the cut-out<br />

within the whole mosaic image is indicated by the rectangle in figure 49 on page 76.<br />

Finally, with the transformation matrices MosaicMatrices2D, which are determined by<br />

the operator bundle_adjust_mosaic, the mosaic can be generated with the operator<br />

gen_bundle_adjusted_mosaic.<br />

gen_bundle_adjusted_mosaic (Images, MosaicImage, MosaicMatrices2D,<br />

StackingOrder, TransformRegion, TransMat2D)<br />

(a) (b)<br />

(c) (d)<br />

Figure 55: Seam between image 5 and image 10 for different classes of transformations: (a) projective,<br />

(b) affine, (c) similarity, and (d) rigid.<br />

5.7 Spherical Mosaicking<br />

The methods described in the previous sections arranged the images on a plane. As the name suggests,<br />

using spherical mosaicking you can arrange them on a sphere instead. <strong>Note</strong> that this method can only be<br />

used if the camera is only rotated around its optical center or zoomed. If the camera movement includes<br />

a translation or if the rotation is not performed exactly around the optical center, the resulting mosaic<br />

image will not be accurate and can therefore not be used for high-accuracy applications.<br />

To create a spherical mosaic, you first perform the matching as described in the previous sections to<br />

determine the projective transformation matrices between the individual images. This information is<br />

the input for the operator stationary_camera_self_calibration, which determines the interior<br />

Mosaicking II


84 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

camera parameters of the camera and the rotation matrices for each image. Based on this information, the<br />

operator gen_spherical_mosaic then creates the mosaic image. Please have a look at the HDevelop<br />

example program hdevelop\Tools\Calibration\stationary_camera_self_calibration.dev<br />

for more information about how to use these operators.<br />

6 Pose Estimation of Known 3D Objects With a Single Camera<br />

With <strong>HALCON</strong>, it is possible to determine the pose of known 3D objects with a single camera. This is,<br />

e.g., necessary if you want to pick up objects that may be placed in an arbitrary position and orientation.<br />

Such an example application is described in section 8.4.1 on page 120. Besides the pose estimation for<br />

general 3D objects, <strong>HALCON</strong> offers an alternative approach for the determination of circle poses.<br />

6.1 Pose Estimation for General 3D Objects<br />

The basic idea is that the pose of the object, i.e., the exterior camera parameters with respect to the object,<br />

can be determined by a call of the operator camera_calibration.<br />

The individual steps are illustrated based on the example program<br />

hdevelop\pose_of_known_3d_object.dev, which determines the pose of a metal part with<br />

respect to a given world coordinate system.<br />

First, the camera must be calibrated, i.e., the interior camera parameters and, if the pose of the object<br />

is to be determined relative to a given world coordinate system, the exterior camera parameters must<br />

be determined. See section 3.1 on page 29 for a detailed description of the calibration process. The<br />

world coordinate system can either be identical to the calibration plate coordinate system belonging<br />

to the calibration plate from one of the calibration images, or it can be modified such that it fits to<br />

some given reference coordinate system (figure 56). This can be achieved, e.g., by using the operator<br />

set_origin_pose<br />

set_origin_pose (PoseOfWCS, -0.0568, 0.0372, 0, PoseOfWCS)<br />

or if other transformations than translations are necessary, via homogeneous transformation matrices<br />

(section 2.1 on page 8).<br />

pose_to_hom_mat3d (PoseOfWCS, camHwcs)<br />

hom_mat3d_rotate_local (camHwcs, rad(180), ’x’, camHwcs)<br />

hom_mat3d_to_pose (camHwcs, PoseOfWCS)<br />

With the homogeneous transformation matrix c Hw , which corresponds to the pose of the world coordinate<br />

system, world coordinates can be transformed into camera coordinates.<br />

Then, the pose of the object can be determined from at least three points (control points) for which both<br />

the 3D object coordinates and the 2D image coordinates are known.<br />

The 3D coordinates of the control points need to be determined only once. They must be given in a<br />

coordinate system that is attached to the object. You should choose points that can be extracted easily


Camera with<br />

optical center<br />

Calibration plate<br />

z w<br />

c<br />

Hw y w<br />

cp<br />

Hw y c<br />

x w<br />

z c<br />

c<br />

Hcp<br />

y cp<br />

z cp<br />

x c<br />

x cp<br />

6.1 Pose Estimation for General 3D Objects 85<br />

x c y c z c Camera coordinate system ( , , )<br />

Calibration plate coordinate system<br />

World coordinate system ( )<br />

Figure 56: Determination of the pose of the world coordinate system.<br />

x w y w z w<br />

, ,<br />

x cp y cp z cp ( , , )<br />

and accurately from the images. The 3D coordinates of the control points are then stored in three tuples,<br />

one for the x coordinates, one for the y coordinates, and the last one for the z coordinates.<br />

In each image from which the pose of the object should be determined, the control points must be<br />

extracted. This task depends heavily on the object and on the possible poses of the object. If it is known<br />

that the object will not be tilted with respect to the camera the detection can, e.g., be carried out by shapebased<br />

matching (for a detailed description of shape-based matching, please refer to the <strong>Application</strong> <strong>Note</strong><br />

on Shape-Based Matching).<br />

Once the image coordinates of the control points are determined, they must be stored in two tuples that<br />

contain the row and the column coordinates, respectively. <strong>Note</strong> that the 2D image coordinates of the<br />

control points must be stored in the same order as the 3D coordinates.<br />

In the example program, the centers of the three holes of the metal part are used as control points. Their<br />

Pose Estimation


86 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

image coordinates are determined with the HDevelop procedure<br />

procedure determine_control_points (Image: : : RowCenter, ColCenter)<br />

which is part of the example program hdevelop\pose_of_known_3d_object.dev.<br />

Now, the operator camera_calibration can be used to determine the pose of the object. For this, the<br />

3D object coordinates and the 2D image coordinates of the control points must be passed to the operator<br />

camera_calibration via the parameters NX, NY, and NZ (3D object coordinates) as well as NRow<br />

and NCol (2D image coordinates). The known interior camera parameters are given via the parameter<br />

StartCamParam and an initial pose of the object with respect to the camera must be specified by the<br />

parameter NStartPose. The parameter EstimateParams must be set to ’pose’.<br />

camera_calibration (ControlX, ControlY, ControlZ, RowCenter, ColCenter,<br />

CamParam, StartPose, ’pose’, _, PoseOfObject, Errors)<br />

You can determine the initial pose of the object from one image where the object is in a typical position<br />

and orientation. Place the <strong>HALCON</strong> calibration plate on the object and apply the operators<br />

find_caltab and find_marks_and_pose (see section 3.1.1 on page 30). The resulting estimation<br />

for the pose can be used as initial pose, even for images where the object appears slightly shifted or<br />

rotated. In the example program, the (initial) pose of the calibration plate that was used for the definition<br />

of the WCS is used as initial pose of the object.<br />

If both the pose of the world coordinate system and the pose of the object coordinate system are known<br />

with respect to the camera coordinate system (see figure 57), it is easy to determine the transformation<br />

matrices for the transformation of object coordinates into world coordinates and vice versa:<br />

w Ho = w Hc · c Ho (35)<br />

= ( c Hw ) −1 · c Ho (36)<br />

where w Ho is the homogeneous transformation matrix for the transformation of object coordinates into<br />

world coordinates and c Hw and c Ho are the homogeneous transformation matrices corresponding to<br />

the pose of the world coordinate system and the pose of the object coordinate system, respectively, each<br />

with respect to the camera coordinate system.<br />

The transformation matrix for the transformation of world coordinates into object coordinates can be<br />

derived by:<br />

o Hw = ( w Ho) −1<br />

The calculations described above can be implemented in HDevelop as follows. First, the homogeneous<br />

transformation matrices are derived from the respective poses.<br />

pose_to_hom_mat3d (PoseOfWCS, camHwcs)<br />

pose_to_hom_mat3d (PoseOfObject, camHobj)<br />

Then, the transformation matrix for the transformation of object coordinates into world coordinates is<br />

derived.<br />

(37)


Camera with<br />

optical center<br />

Object<br />

z w<br />

c<br />

Hw y c<br />

o<br />

Hw y w<br />

x w<br />

z c<br />

z o<br />

w<br />

Ho c<br />

Ho y o<br />

x o<br />

x c<br />

6.1 Pose Estimation for General 3D Objects 87<br />

x c y c z c Camera coordinate system ( , , )<br />

x o y o z o Object coordinate system ( , , )<br />

World coordinate system ( )<br />

x w y w z w<br />

, ,<br />

Figure 57: Pose of the object coordinate system and transformation between object coordinates and world<br />

coordinates.<br />

hom_mat3d_invert (camHwcs, wcsHcam)<br />

hom_mat3d_compose (wcsHcam, camHobj, wcsHobj)<br />

Now, known object coordinates can be transformed into world coordinates with:<br />

affine_trans_point_3d (wcsHobj, CornersXObj, CornersYObj, CornersZObj,<br />

CornersXWCS, CornersYWCS, CornersZWCS)<br />

In the example program hdevelop\pose_of_known_3d_object.dev, the world coordinates of the<br />

four corners of the rectangular hole of the metal part are determined from their respective object coordinates.<br />

The object coordinate system and the world coordinate system are visualized as well as the<br />

Pose Estimation


88 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

respective coordinates for the four points (see figure 58).<br />

z<br />

Object coordinates: World coordinates:<br />

1:(6.39,26.78,0.00) [mm] 1:(44.98,31.58,2.25) [mm]<br />

2:(6.27,13.62,0.00) [mm] 2:(49.55,19.62,5.28) [mm]<br />

3:(17.62,13.60,0.00) [mm] 3:(60.12,23.73,5.20) [mm]<br />

4:(17.68,26.66,0.00) [mm] 4:(55.54,35.58,2.20) [mm]<br />

y<br />

WCS x<br />

y<br />

1<br />

2<br />

z<br />

OBJ<br />

4<br />

3<br />

Figure 58: Object coordinates and world coordinates for the four corners of the rectangular hole of the<br />

metal part.<br />

6.2 Pose Estimation for 3D Circles<br />

<strong>HALCON</strong> offers an alternative approach to estimate the pose of 3D circles, which can be applied with<br />

less efford than the general approach. It is based on the known geometrical behavior of perspectively<br />

distorted circles. In particular, 3D circles are usually represented as ellipses in the image. Using the<br />

extracted 2D ellipse of a 3D circle together with the interior camera parameters and the known radius of<br />

the circle, the two possible 3D poses of the circle (having the same position but opposite orientations)<br />

can be obtained easily using the operator get_circle_pose. The HDevelop example <strong>HALCON</strong>ROOT<br />

\examples\hdevelop\<strong>Application</strong>s\Calibration\3d_position_of_circles.dev shows in<br />

detail how to apply the approach.<br />

7 3D Machine Vision With a Binocular Stereo System<br />

With a binocular stereo system, it is possible to derive 3D information of the surface of arbitrarily shaped<br />

objects. Figure 59 shows an image of a stereo camera system, the resulting stereo image pair, and the<br />

x


height map that has been derived from the images.<br />

The most important requirements for acquiring a pair of stereo images are that the images<br />

• show the same object,<br />

• at the same time, but<br />

• taken from different positions.<br />

7.1 The Principle of Stereo Vision 89<br />

The images must be calibrated and rectified. Thereafter, the 3D information can be determined either<br />

in form of disparities or as the distance of the object surface from the stereo camera system. The 3D<br />

information is available as images that encode the disparities or the distances, respectively.<br />

Additionally, it is possible to directly determine 3D coordinates for points of the object’s surface.<br />

<strong>Application</strong>s for a binocular stereo system comprise, but are not limited to, completeness checks, inspection<br />

of ball grid arrays, etc.<br />

The example programs used in this section are<br />

• hdevelop\stereo_calibration.dev<br />

• hdevelop\height_above_reference_plane_from_stereo.dev<br />

• hdevelop\3d_information_for_selected_points.dev<br />

As an alternative to fully calibrated stereo, <strong>HALCON</strong> offers the so-called uncalibrated stereo vision.<br />

Here, the relation between the cameras is determined from the scene itself, i.e., without needing a special<br />

calibration object. Please refer to section 7.5 on page 108 for more information about this method.<br />

7.1 The Principle of Stereo Vision<br />

The basic principle of binocular stereo vision is very easy to understand. Assume the simplified configuration<br />

of two parallel looking <strong>1D</strong> cameras with identical interior parameters as shown in figure 60.<br />

Furthermore, the basis, i.e., the straight line connecting the two optical centers of the two cameras, is<br />

assumed to be coincident with the x-axis of the first camera.<br />

Then, the image plane coordinates of the projections of the point P (x c , z c ) into the two images can be<br />

expressed by<br />

u1 = f xc<br />

z c<br />

u2 = f xc − b<br />

z c<br />

where f is the focal length and b the length of the basis.<br />

(38)<br />

(39)<br />

Stereo Vision


90 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

✏<br />

✏<br />

✏<br />

✏<br />

✏<br />

✏✮<br />

� ������<br />

��✐<br />

���<br />

� ������<br />

✏<br />

✏<br />

✏<br />

✏<br />

✏<br />

✏✮<br />

Figure 59: Top: Stereo camera system; Center: Stereo image pair; Bottom: Height map.


z c<br />

f<br />

u 1<br />

xc<br />

P<br />

b<br />

u 2<br />

7.1 The Principle of Stereo Vision 91<br />

Image 1 u u Image 2<br />

Figure 60: Vertical section of a binocular stereo camera system.<br />

The pair of image points that results from the projection of one object point into the two images is often<br />

referred to as conjugate points or homologous points.<br />

The difference between the two image locations of the conjugate points is called the disparity d:<br />

d = (u1 − u2) =<br />

Given the camera parameters and the image coordinates of two conjugate points, the z c coordinate of the<br />

corresponding object point P , i.e., its distance from the stereo camera system, can be computed by<br />

z c =<br />

f · b<br />

d<br />

<strong>Note</strong> that the interior camera parameters of both cameras and the relative pose of the second camera in<br />

relation to the first camera are necessary to determine the distance of P from the stereo camera system.<br />

f · b<br />

z c<br />

f<br />

(40)<br />

(41)<br />

Stereo Vision


92 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Thus, the tasks to be solved for stereo vision are:<br />

1. Determination of the camera parameters<br />

2. Determination of conjugate points<br />

The first task is achieved by the calibration of the binocular stereo camera system, which is described in<br />

section 7.3. This calibration is quite similar to the calibration of a single camera, described in section 3.1<br />

on page 29.<br />

The second task is the so-called stereo matching process, which in <strong>HALCON</strong> is just a call of the operator<br />

binocular_disparity or binocular_distance, respectively. These operators are described in<br />

section 7.4, together with the operators doing all the necessary calculations to obtain world coordinates<br />

from the stereo images.<br />

7.2 The Setup of a Stereo Camera System<br />

The stereo camera system consists of two cameras looking at the same object from different positions<br />

(see figure 61).<br />

It is very important to ensure that neither the interior camera parameters (e.g., the focal length) nor<br />

the relative pose (e.g., the distance between the two cameras) of the two cameras changes during the<br />

calibration process or between the calibration process and the ensuing application of the calibrated stereo<br />

camera system. Therefore, it is advisable to mount the two cameras on a stable platform.<br />

The manner in which the cameras are placed influences the accuracy of the results that is achievable with<br />

the stereo camera system.<br />

The distance resolution ∆z, i.e., the accuracy with which the distance z of the object surface from the<br />

stereo camera system can be determined, can be expressed by<br />

∆z = z2<br />

· ∆d (42)<br />

f · b<br />

To achieve a high distance resolution, the setup should be chosen such that the length b of the basis as<br />

well as the focal length f are large, and that the stereo camera system is placed as close as possible<br />

to the object. In addition, the distance resolution depends directly on the accuracy ∆d with which the<br />

disparities can be determined. Typically, the disparities can be determined with an accuracy of 1/5 up to<br />

1/10 pixel, which corresponds to approximately 1 µm for a camera with 7.4 µm pixel size.<br />

In figure 62, the distance resolutions that are achievable in the ideal case are plotted as a function of the<br />

distance for four different configurations of focal lengths and base lines, assuming ∆d to be 1 µm.<br />

<strong>Note</strong> that if the ratio between b and z is very large, problems during the stereo matching process may<br />

occur, because the two images of the stereo pair differ too much. The maximum reasonable ratio b/z<br />

depends on the surface characteristics of the object. In general, objects with little height differences can<br />

be imaged with a higher ratio b/z, whereas objects with larger height differences should be imaged with<br />

a smaller ratio b/z.<br />

In any case, to ensure a stable calibration the overlapping area of the two stereo images should be as<br />

large as possible and the cameras should be approximately aligned, i.e., the rotation around the optical<br />

axis should not differ too much between the two cameras.


Cameras with<br />

optical centers<br />

Virtual image planes<br />

Object point<br />

r<br />

y c<br />

f<br />

z c<br />

v<br />

x c<br />

u<br />

P’<br />

Figure 61: Stereo camera system.<br />

7.3 Calibrating the Stereo Camera System<br />

c<br />

7.3 Calibrating the Stereo Camera System 93<br />

As mentioned above, the calibration of the binocular stereo camera system is very similar to the calibration<br />

of a single camera (section 3.1 on page 29). The major differences are that the calibration plate<br />

must be placed such that it lies completely within both images of each stereo image pair and that the<br />

calibration of both images is carried out simultaneously within the operator binocular_calibration.<br />

Finally, the stereo images must be rectified in order to facilitate all further calculations.<br />

In this section only a brief description of the calibration process is given. More details can be found in<br />

section 3.1 on page 29. Only the stereo-specific parts of the calibration process are described in depth.<br />

b<br />

r<br />

P<br />

v<br />

y c<br />

P’<br />

z c<br />

u<br />

x c<br />

c<br />

Stereo Vision


94 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Distance resolution [mm]<br />

1.4<br />

1.2<br />

1<br />

0.8<br />

0.6<br />

0.4<br />

0.2<br />

b = 10cm, f = 8mm<br />

b = 10cm, f = 12.5mm<br />

b = 20cm, f = 8mm<br />

b = 20cm, f = 12.5mm<br />

0<br />

0 0.2 0.4 0.6 0.8 1<br />

Distance [m]<br />

Figure 62: Distance resolution plotted over the distance.<br />

7.3.1 Rules for Taking Calibration Images<br />

For the calibration of the stereo camera system, multiple stereo images of the calibration plate are necessary,<br />

where the calibration plate must be completely visible in both images of each stereo image pair.<br />

A typical sequence of stereo calibration image pairs is displayed in figure 63.<br />

The rules for taking the calibration images for the single camera calibration (see section 3.1.2 on page<br />

31) apply accordingly.<br />

In general, the overlapping area of the two stereo images is smaller than the field of view of each individual<br />

camera. Therefore, it is not possible to place the calibration plate in all areas of the field of view<br />

of each camera. Nevertheless, it is very important to place the calibration plate in the multiple images<br />

such that the whole overlapping area is covered as well as possible.<br />

7.3.2 Camera Calibration Input<br />

As in the case of the single camera calibration, the input parameters for the camera calibration can be<br />

grouped into two categories:


Figure 63: A sequence of eleven stereo calibration image pairs.<br />

7.3.3 Determining the Camera Parameters 95<br />

1. Corresponding points, given in world coordinates as well as in image coordinates of both images<br />

2. Initial values for the camera parameters of both cameras<br />

The corresponding points as well as the initial values for the camera parameters are determined similar<br />

to the single camera calibration by the use of the operators find_caltab and find_marks_and_pose.<br />

Both operators are described in detail in section 3.1.1 on page 30. The only difference is that the operators<br />

must be applied to both stereo images separately.<br />

The initial values for the interior camera parameters can be determined as explained in section 3.1.3 on<br />

page 32.<br />

7.3.3 Determining the Camera Parameters<br />

The actual calibration of the stereo camera system is carried out with the operator<br />

binocular_calibration.<br />

binocular_calibration (X, Y, Z, RowsL, ColsL, RowsR, ColsR, StartCamParL,<br />

StartCamParR, StartPosesL, StartPosesR, ’all’,<br />

CamParamL, CamParamR, NFinalPoseL, NFinalPoseR,<br />

cLPcR, Errors)<br />

The only differences to the operator camera_calibration, described in section 3.1.4 on page 36 are<br />

that the operator binocular_calibration needs the image coordinates of the calibration marks from<br />

both images of each stereo pair, that it needs the initial values for the camera parameters of both cameras,<br />

and that it also returns the relative pose of the second camera in relation to the first camera.<br />

<strong>Note</strong> that it is assumed that the parameters of the first image stem from the left image and the parameters<br />

of the second image stem from the right image, whereas the notations ’left’ and ’right’ refer to the line<br />

Stereo Vision


96 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

of sight of the two cameras. If the images are used in the reverse order, they will appear upside down<br />

after the rectification (see section 7.3.4 for an explanation of the rectification step).<br />

Once the stereo camera system is calibrated, it should be left unchanged. If, however, the focus of one<br />

camera was modified, it is necessary to determine the interior camera parameters of that camera again<br />

(binocular_calibration with EstimateParams set to ’cam_par1’ or ’cam_par2’, respectively).<br />

In case one camera has been shifted or rotated with respect to the other camera, the relative pose of<br />

the second camera in relation to the first camera must be determined again (binocular_calibration<br />

with EstimateParams set to ’pose_rel’). Further, if the point of view of the camera allows only<br />

stereo images with marginal overlaps or the acquisition of an insufficient number of calibration images,<br />

binocular_calibration can be applied also to already calibrated cameras (with EstimateParams<br />

set to ’pose_rel’).<br />

7.3.4 Rectifying the Stereo Images<br />

After the rectification of stereo images, conjugate points lie on the same row in both rectified images. In<br />

figure 64 the original images of a stereo pair are shown, where the two cameras are rotated heavily with<br />

respect to each other. The corresponding rectified images are displayed in figure 65.<br />

Figure 64: Original stereo images.<br />

The rectification itself is carried out using the operators gen_binocular_rectification_map and<br />

map_image.<br />

gen_binocular_rectification_map (MapL, MapR, CamParamL, CamParamR, cLPcR,<br />

1, ’geometric’, ’bilinear’, RectCamParL,<br />

RectCamParR, CamPoseRectL, CamPoseRectR,<br />

RectLPosRectR)<br />

The operator gen_binocular_rectification_map requires the interior camera parameters of both<br />

cameras and the relative pose of the second camera in relation to the first camera. This data is returned<br />

by the operator binocular_calibration.<br />

The parameter SubSampling can be used to change the size and resolution of the rectified images with<br />

respect to the original images. A value of 1 indicates that the rectified images will have the same size as


Figure 65: Rectified stereo images.<br />

7.3.4 Rectifying the Stereo Images 97<br />

the original images. Larger values lead to smaller images with a resolution reduced by the given factor,<br />

smaller values lead to larger images.<br />

Reducing the image size has the effect that the following stereo matching process runs faster, but also<br />

that less details are visible in the result. In general, it is proposed not to used values below 0.5 or above<br />

2. Otherwise, smoothing or aliasing effects occur, which may disturb the matching process.<br />

The rectification process can be described as projecting the original images onto a common rectified<br />

image plane. The method to define this plane can be selected by the parameter Method. So far, only<br />

the method ’geometric’ can be selected, in which the orientation of the common rectified image plane is<br />

defined by the cross product of the base line and the line of intersection of the two original image planes.<br />

The rectified images can be thought of as being acquired by a virtual stereo camera system, called<br />

rectified stereo camera system, as displayed in figure 66. The optical centers of the rectified cameras<br />

are the same as for the real cameras, but the rectified cameras are rotated such that they are looking<br />

parallel and that their x-axes are collinear. In addition, both rectified cameras have the same focal length.<br />

Therefore, the two image planes coincide. <strong>Note</strong> that the principal point of the rectified images, which is<br />

the origin of the image plane coordinate system, may lie outside the image.<br />

The parameter Interpolation specifies whether bilinear interpolation (’bilinear’) should be applied<br />

between the pixels of the input images or whether the gray value of the nearest pixel (’none’) should be<br />

used. Bilinear interpolation yields smoother rectified images, whereas the use of the nearest neighbor is<br />

faster.<br />

The operator returns the rectification maps and the camera parameters of the virtual, rectified cameras.<br />

Finally, the operator map_image can be applied to both stereo images using the respective rectification<br />

map generated by the operator gen_binocular_rectification_map.<br />

map_image (ImageL, MapL, ImageRectifiedL)<br />

map_image (ImageR, MapR, ImageRectifiedR)<br />

If the calibration was erroneous, the rectification will produce wrong results. This can be checked very<br />

Stereo Vision


98 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Rectified cameras with<br />

optical centers<br />

Rectified images<br />

Object point<br />

y c<br />

r<br />

v<br />

z c<br />

f<br />

x c<br />

u<br />

P’<br />

Figure 66: Rectified stereo camera system.<br />

easily by comparing the row coordinates of conjugate points selected from the two rectified images. If the<br />

row coordinates of conjugate points are different within the two rectified images, they are not correctly<br />

rectified. In this case, you should check the calibration process carefully.<br />

An incorrectly rectified image pair may look like the one displayed in figure 67.<br />

7.4 Obtaining 3D Information from Images<br />

There are many possibilities to derive 3D information from rectified stereo images. If only non-metrical<br />

information about the surface of an object is needed, it may suffice to determine the disparities within<br />

the overlapping area of the stereo image pair by using the operator binocular_disparity.<br />

If metrical information is required, the operator binocular_distance can be used to extract the distance<br />

of the object surface from the stereo camera system (see section 7.4.3 on page 104 for the definition<br />

c<br />

b<br />

r<br />

P<br />

P’<br />

v<br />

f<br />

c<br />

u


of the distance).<br />

Figure 67: Incorrectly rectified stereo images.<br />

7.4.1 Rules for Taking Stereo Image Pairs 99<br />

To derive metrical information for selected points only, the operators disparity_to_distance or<br />

disparity_to_point_3d can be used. The first of these two operators calculates the distance z of<br />

points from the stereo camera system based on their disparity. The second operator calculates the x, y,<br />

and z coordinates from the row and column position of a point in the first rectified image and from its<br />

disparity.<br />

Alternatively, the operator intersect_lines_of_sight can be used to calculate the x, y, and z<br />

coordinates of selected points. It does not require to determine the disparities in advance. Only the<br />

image coordinates of the conjugate points need to be given, together with the camera parameters. This<br />

operator can also handle image coordinates of the original stereo images. Thus, the rectification can be<br />

omitted. Admittedly, the conjugate points must be determined by yourself.<br />

<strong>Note</strong> that all operators, which deal with disparities or distances require all inputs to be based on the<br />

rectified images. This holds for the image coordinates as well as for the camera parameters.<br />

7.4.1 Rules for Taking Stereo Image Pairs<br />

The 3D coordinates of each object point are derived by intersecting the lines of sight of the respective<br />

conjugate image points. The conjugate points are determined by an automatic matching process. This<br />

matching process has some properties that should be accounted for during the image acquisition.<br />

For each point of the first image, the conjugate point in the second image must be determined. This point<br />

matching relies on the availability of texture. The conjugate points cannot be determined correctly in<br />

areas without sufficient texture (figure 68).<br />

If the images contain repetitive patterns, the matching process may be confused, since in this case many<br />

points look alike. In order to make the matching process fast and reliable, the stereo images are rectified<br />

such that pairs of conjugate points always have identical row coordinates in the rectified images, i.e.,<br />

that the search space in the second rectified image is reduced to a line. With this, repetitive patterns can<br />

disturb the matching process only if they are parallel to the rows of the rectified images (figure 69).<br />

The following rules for the acquisition of the stereo image pairs should be considered:<br />

Stereo Vision


100 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

❅<br />

❅ ❅❘<br />

�<br />

�<br />

�✠<br />

Figure 68: Rectified stereo images and matching result in a poorly textured area (regions where the<br />

matching process failed are displayed white).<br />

• Do not change the camera setup between the acquisition of the calibration images and the acquisition<br />

of the stereo images of the object to be investigated.<br />

• Ensure a proper illumination of the object, avoid reflections.<br />

• If the object shows no texture, consider to project texture onto it.<br />

• Place the object such that repetitive patterns are not aligned with the rows of the rectified images.<br />

7.4.2 Determining Disparities<br />

Disparities are an indicator for the distance z of object points from the stereo camera system, since points<br />

with equal disparities also have equal distances z (equation 41 on page 91).<br />

Therefore, in case it is only necessary to know whether there are locally high objects it suffices to derive<br />

the disparities. This is done by using the operator binocular_disparity.


❅<br />

❅ ❅❘<br />

�<br />

�<br />

�✠<br />

7.4.2 Determining Disparities 101<br />

Figure 69: Rectified stereo images with repetitive patterns aligned to the image rows and cutout of the<br />

matching result (regions where the matching process failed are displayed white).<br />

binocular_disparity (ImageRectifiedL, ImageRectifiedR, DisparityImage,<br />

ScoreImageDisparity, ’ncc’, MaskWidth, MaskHeight,<br />

TextureThresh, MinDisparity, MaxDisparity,<br />

NumLevels, ScoreThresh, ’left_right_check’,<br />

’interpolation’)<br />

The operator requires the two rectified images as input. The disparities are only derived for those conjugate<br />

points that lie within the respective image domain in both images. With this, it is possible to speed<br />

up the calculation of the disparities if the image domain of at least one of the two rectified images is<br />

reduced to a region of interest, e.g., by using the operator reduce_domain.<br />

Several parameters can be used to control the behavior of the matching process that is performed by the<br />

operator binocular_disparity to determine the conjugate points:<br />

With the parameter Method, the matching function is selected. The methods ’sad’ (summed absolute<br />

differences) and ’ssd’ (summed squared differences) compare the gray values of the pixels within a<br />

matching window directly, whereas the method ’ncc’ (normalized cross correlation) compensates for the<br />

mean gray value and its variance within the matching window. Therefore, if the two images differ in<br />

brightness and contrast, the method ’ncc’ should be preferred. However, since the internal computations<br />

are less complex for the methods ’sad’ and ’ssd’, they are faster than the method ’ncc’.<br />

The width and height of the matching window can be set independently with the parameters MaskWidth<br />

and MaskHeight. The values should be odd numbers. Otherwise they will be increased by one. A larger<br />

matching window will lead to a smoother disparity image, but may result in the loss of small details. In<br />

contrary, the results of a smaller matching window tend to be noisy but they show more spatial details.<br />

Because the matching process relies on the availability of texture, low-textured areas can be excluded<br />

Stereo Vision


102 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

from the matching process. The parameter TextureThresh defines the minimum allowed variance<br />

within the matching window. For areas where the texture is too low no disparities will be determined.<br />

The parameters MinDisparity and MaxDisparity define the minimum and maximum disparity values.<br />

They are used to restrict the search space for the matching process. If the specified disparity range<br />

does not contain the actual range of the disparities, the conjugate points cannot be found correctly;<br />

therefore, the disparities will be incomplete and erroneous. On the other hand, if the disparity range is<br />

specified too large, the matching process will be slower and the probability of mismatches rises.<br />

Therefore, it is important to set the parameters MinDisparity and MaxDisparity carefully. There are<br />

several possibilities to determine the appropriate values:<br />

• If you know the minimum and maximum distance of the object from the stereo camera system<br />

(section 7.4.3 on page 104), you can use the operator distance_to_disparity to determine the<br />

respective disparity values.<br />

• You can also determine these values directly from the rectified images. For this, you should display<br />

the two rectified images and measure the approximate column coordinates of the point N, which<br />

is nearest to the stereo camera system (N image1<br />

col and N image2<br />

col ) and of the point F , which is the<br />

farthest away (F image1<br />

col and F image2<br />

col ), each in both rectified images.<br />

Now, the values for the definition of the disparity range can be calculated as follows:<br />

MinDisparity = N image2<br />

col<br />

MaxDisparity = F image2<br />

col<br />

− N image1<br />

col<br />

− F image1<br />

col<br />

The operator binocular_disparity uses image pyramids to improve the matching speed. The disparity<br />

range specified by the parameters MinDisparity and MaxDisparity is only used on the uppermost<br />

pyramid level, indicated by the parameter NumLevels. Based on the matching results on that level, the<br />

disparity range for the matching on the next lower pyramid levels is adapted automatically.<br />

The benefits with respect to the execution time are greatest if the objects have different regions between<br />

which the appropriate disparity range varies strongly. However, take care that the value for NumLevels is<br />

not set too large, as otherwise the matching process may fail because of lack of texture on the uppermost<br />

pyramid level.<br />

The parameter ScoreThresh specifies which matching scores are acceptable. Points for which the<br />

matching score is not acceptable are excluded from the results, i.e., the resulting disparity image has a<br />

reduced domain that comprises only the accepted points.<br />

<strong>Note</strong> that the value for ScoreThresh must be set according to the matching function selected via<br />

Method. The two methods ’sad’ (0 ≤ score ≤ 255) and ’ssd’ (0 ≤ score ≤ 65025) return lower matching<br />

scores for better matches. In contrast, the method ’ncc’ (-1 ≤ score ≤ 1) returns higher values for better<br />

matches, where a score of zero indicates that the two matching windows are totally different and a score<br />

of minus one denotes that the second matching window is exactly inverse to the first matching window.<br />

The parameter Filter can be used to activate a downstream filter by which the reliability of the resulting<br />

disparities is increased. Currently, it is possible to select the method ’left_right_check’, which verifies<br />

the matching results based on a second matching in the reverse direction. Only if both matching results<br />

correspond to each other, the resulting conjugate points are accepted. In some cases, this may lead to<br />

gaps in the disparity image, even in well textured areas, as this verification is very strict. If you do not<br />

want to verify the matching results based on the ’left_right_check’, set the parameter Filter to ’none’.<br />

(43)<br />

(44)


7.4.2 Determining Disparities 103<br />

The subpixel refinement of the disparities is switched on by setting the parameter SubDisparity to<br />

’interpolation’. It is switched off by setting the parameter to ’none’.<br />

The results of the operator binocular_disparity are the two images Disparity and Score, which<br />

contain the disparities and the matching score, respectively. In figure 70, a rectified stereo image pair is<br />

displayed, from which the disparity and score images, displayed in figure 71 were derived.<br />

Figure 70: Rectified stereo images.<br />

Both resulting images refer to the image geometry of the first rectified image, i.e., the disparity for the<br />

point (r,c) of the first rectified image is the gray value at the position (r,c) of the disparity image. The<br />

disparity image can, e.g., be used to extract the components of the board, which would be more difficult<br />

in the original images, i.e., without the use of 3D information.<br />

Figure 71: Disparity image (left) and score image (right).<br />

In figure 71, areas where the matching did not succeed, i.e., undefined regions of the images, are displayed<br />

white in the disparity image and black in the score image.<br />

Stereo Vision


104 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

7.4.3 Determining Distances<br />

The distance of an object point from the stereo camera system is defined as its distance from the xy-plane<br />

of the coordinate system of the first rectified camera. It can be determined by the operator<br />

binocular_distance, which is used analogously to the operator binocular_disparity described<br />

in the previous section.<br />

binocular_distance (ImageRectifiedL, ImageRectifiedR, DistanceImage,<br />

ScoreImageDistance, RectCamParL, RectCamParR,<br />

RectLPosRectR, ’ncc’, MaskWidth, MaskHeight,<br />

TextureThresh, MinDisparity, MaxDisparity,<br />

NumLevels, ScoreThresh, ’left_right_check’,<br />

’interpolation’)<br />

The three additional parameters, namely the camera parameters of the rectified cameras as well as the<br />

relative pose of the second rectified camera in relation to the first rectified camera can be taken directly<br />

from the output of the operator gen_binocular_rectification_map.<br />

Figure 72 shows the distance image and the respective score image for the rectified stereo pair of figure<br />

70 on page 103. Because the distance is calculated directly from the disparities and from the camera<br />

parameters, the distance image looks similar to the disparity image (figure 71). What is more, the score<br />

images are identical, since the underlying matching process is identical.<br />

Figure 72: Distance image (left) and score image (right).<br />

It can be seen from figure 72 that the distance of the board changes continuously from left to right. The<br />

reason is that, in general, the x-y-plane of the coordinate system of the first rectified camera will be tilted<br />

with respect to the object surface (see figure 73).<br />

If it is necessary that one reference plane of the object surface has a constant distance value of, e.g.,<br />

zero, the tilt can be compensated easily: First, at least three points that lie on the reference plane must be<br />

defined. These points are used to determine the orientation of the (tilted) reference plane in the distance<br />

image. Therefore, they should be selected such that they enclose the region of interest in the distance<br />

image. Then, a distance image of the (tilted) reference plane can be simulated and subtracted from the<br />

distance image of the object. Finally, the distance values themselves must be adapted by scaling them<br />

with the cosine of the angle between the tilted and the corrected reference plane.


Rectified cameras<br />

Object surface<br />

y c<br />

c<br />

z<br />

x c<br />

x−y−plane of the rectified camera<br />

Distance<br />

7.4.3 Determining Distances 105<br />

Figure 73: Distances of the object surface from the x-y-plane of the coordinate system of the first rectified<br />

camera.<br />

These calculations are carried out in the procedure<br />

procedure tilt_correction (DistanceImage, RegionDefiningReferencePlane:<br />

DistanceImageCorrected: : )<br />

which is part of the example program hdevelop\height_above_reference_plane_from_stereo.dev<br />

(appendix B.4 on page 140). In principle, this procedure can also be used to correct the disparity image,<br />

but note that you must not use the corrected disparity values as input to any operators that derive metric<br />

information.<br />

If the reference plane is the ground plane of the object, an inversion of the distance image generates an<br />

image that encodes the heights above the ground plane. Such an image is displayed on the left hand side<br />

in figure 74.<br />

Objects of different height above or below the ground plane can be segmented easily using a simple<br />

threshold with the minimal and maximal values given directly in units of the world coordinate system,<br />

e.g., meters. The image on the right hand side of figure 74 shows the results of such a segmentation,<br />

which can be carried out based on the corrected distance image or the image of the heights above the<br />

ground plane.<br />

Stereo Vision


106 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Figure 74: Left: Height above the reference plane; Right: Segmentation of high objects (white: 0-0.4 mm,<br />

light gray: 0.4-1.5 mm, dark gray: 1.5-2.5 mm, black: 2.5-5 mm).<br />

7.4.4 Determining Distances or 3D Coordinates for Selected Points<br />

If only the distances or the 3D coordinates of selected points should be determined, the operators<br />

disparity_to_distance, disparity_to_point_3d, or intersect_lines_of_sight can be<br />

used.<br />

The operator disparity_to_distance simply transforms given disparity values into the respective<br />

distance values. For example, if you want to know the minimum and maximum distance of the object<br />

from the stereo camera system you can determine the minimum and maximum disparity values from the<br />

disparity image and transform them into distances.<br />

min_max_gray (CaltabL, Disparity, 0, MinDisparity, MaxDisparity, _)<br />

disparity_to_distance (RectCamParL, RectCamParR, RectLPosRectR,<br />

[MinDisparity,MaxDisparity], MinMaxDistance)<br />

This transformation is constant for the entire rectified image, i.e., all points having the same disparity<br />

have the same distance from the x-y-plane of the coordinate system of the first rectified camera. Therefore,<br />

besides the camera parameters of the rectified cameras, only the disparity values need to be given.<br />

To calculate the x, y, and z coordinates of points, two different operators are available: The operator<br />

disparity_to_point_3d derives the 3D coordinates from image coordinates and the respective disparities,<br />

whereas the operator intersect_lines_of_sight uses the image coordinates from the two<br />

stereo images to determine the 3D position of points.<br />

The operator disparity_to_point_3d requires the camera parameters of the two rectified cameras as<br />

well as the image coordinates and the disparities of the selected points.<br />

disparity_to_point_3d (RectCamParL, RectCamParR, RectLPosRectR, RL, CL,<br />

DisparityOfSelectedPoints, X_CCS_FromDisparity,<br />

Y_CCS_FromDisparity, Z_CCS_FromDisparity)<br />

The x, y, and z coordinates are returned in the coordinate system of the first rectified camera.


7.4.4 Determining Distances or 3D Coordinates for Selected Points 107<br />

The operator intersect_lines_of_sight determines the x, y, and z coordinates of points from the<br />

image coordinates of the respective conjugate points. <strong>Note</strong> that you must determine the image coordinates<br />

of the conjugate points yourself.<br />

intersect_lines_of_sight (RectCamParL, RectCamParR, RectLPosRectR, RL, CL,<br />

RR, CR, X_CCS_FromIntersect, Y_CCS_FromIntersect,<br />

Z_CCS_FromIntersect, Dist)<br />

The x, y, and z coordinates are returned in the coordinate system of the first (rectified) camera.<br />

The operator can also handle image coordinates of the original stereo images. Thus, the rectification can<br />

be omitted. In this case, the camera parameters of the original stereo cameras have to be given instead of<br />

the parameters of the rectified cameras.<br />

It is possible to transform the x, y, and z coordinates determined by the latter two operators from the<br />

coordinate system of the first (rectified) camera into a given coordinate system WCS, e.g., a coordinate<br />

system with respect to the building plan of, say, a factory building. For this, a homogeneous transformation<br />

matrix, which describes the transformation between the two coordinate systems is needed.<br />

This homogeneous transformation matrix can be determined in various ways. The easiest way is to take<br />

an image of a <strong>HALCON</strong> calibration plate with the first camera only. If the 3D coordinates refer to the<br />

rectified camera coordinate system, the image must be rectified as well. Then, the pose of the calibration<br />

plate in relation to the first (rectified) camera can be determined using the operators find_caltab,<br />

find_marks_and_pose, and camera_calibration.<br />

find_caltab (ImageRectifiedL, CaltabL, ’caltab_30mm.descr’, SizeGauss,<br />

MarkThresh, MinDiamMarks)<br />

find_marks_and_pose (ImageRectifiedL, CaltabL, ’caltab_30mm.descr’,<br />

RectCamParL, StartThresh, DeltaThresh, MinThresh,<br />

Alpha, MinContLength, MaxDiamMarks, RCoordL, CCoordL,<br />

StartPoseL)<br />

camera_calibration (X, Y, Z, RCoordL, CCoordL, RectCamParL, StartPoseL,<br />

’pose’, _, PoseOfCalibrationPlate, Errors)<br />

The resulting pose can be converted into a homogeneous transformation matrix.<br />

pose_to_hom_mat3d (PoseOfCalibrationPlate, HomMat3d_WCS_to_RectCCS)<br />

If necessary, the transformation matrix can be modified with the operators hom_mat3d_rotate_local,<br />

hom_mat3d_translate_local, and hom_mat3d_scale_local.<br />

hom_mat3d_translate_local (HomMat3d_WCS_to_RectCCS, 0.01125, -0.01125,<br />

0, HomMat3DTranslate)<br />

hom_mat3d_rotate_local (HomMat3DTranslate, rad(180), ’y’,<br />

HomMat3d_WCS_to_RectCCS)<br />

The homogeneous transformation matrix must be inverted in order to represent the transformation from<br />

the (rectified) camera coordinate system into the WCS.<br />

hom_mat3d_invert (HomMat3d_WCS_to_RectCCS, HomMat3d_RectCCS_to_WCS)<br />

Finally, the 3D coordinates can be transformed using the operator affine_trans_point_3d.<br />

Stereo Vision


108 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

affine_trans_point_3d (HomMat3d_RectCCS_to_WCS, X_CCS_FromIntersect,<br />

Y_CCS_FromIntersect, Z_CCS_FromIntersect, X_WCS,<br />

Y_WCS, Z_WCS)<br />

The homogeneous transformation matrix can also be determined from three specific points. If the origin<br />

of the WCS, a point on its x-axis, and a third point that lies in the x-y-plane, e.g., directly on the y-axis,<br />

are given, the transformation matrix can be determined using the procedure<br />

procedure gen_hom_mat3d_from_three_points (: : Origin, PointOnXAxis,<br />

PointInXYPlane: HomMat3d)<br />

which is part of the example program hdevelop\3d_information_for_selected_points.dev.<br />

The resulting homogeneous transformation matrix can be used as input for the operator<br />

affine_trans_point_3d, as shown above.<br />

7.5 Uncalibrated Stereo Vision<br />

Similar to uncalibrated mosaicking (see section 5 on page 69), <strong>HALCON</strong> also provides an “uncalibrated”<br />

version of stereo vision, which derives information about the cameras from the scene itself by matching<br />

characteristic points. The main advantage of this method is that you need no special calibration object.<br />

The main disadvantage of this method is that, without a precisely known calibration object, the accuracy<br />

of the results is highly dependent on the content of the scene, i.e., the accuracy of the results degrades<br />

if the scene does not contain enough 3D information or if the extracted characteristic points in the two<br />

images do not precisely correspond to the same world points, e.g., due to occlusion.<br />

In fact, <strong>HALCON</strong> provides two versions of uncalibrated stereo: Without any knowledge about<br />

the cameras and about the scene, you can rectify the stereo images and perform a segmentation<br />

similar to the method described in section 7.4.3 on page 104. For this, you first use the operator<br />

match_fundamental_matrix_ransac, which determines the so-called fundamental matrix. This matrix<br />

models the cameras and their relation; but in contrast to the model described in section 7.1 on page<br />

89, interior and exterior parameters are not available separately, thus no metric information can be derived.<br />

The fundamental matrix is then passed on to the operator gen_binocular_proj_rectification,<br />

which is the “uncalibrated” version of the operator gen_binocular_rectification_map. With the<br />

output of this operator, i.e., the rectification maps, you can then proceed to rectify the images as described<br />

in section 7.3.4 on page 96. Because the relative pose of the cameras is not known, you cannot<br />

generate the distance image and segment it as described in section 7.4.3 on page 104. The HDevelop example<br />

program hdevelop\<strong>Application</strong>s\Stereo\board_segmentation_uncalib.dev shows an<br />

alternative approach that can be used if the reference plane appears dominant in the images, i.e., if many<br />

correspondences are found on it.<br />

Because no calibration object is needed, this method can be used to perform stereo vision with a single<br />

camera. <strong>Note</strong>, however, that the method assumes that there are no radial distortions in the images.<br />

Therefore, the accuracy of the results degrades if the lens has significant radial distortions.<br />

If the interior parameters of the camera are known, you can determine the relative pose between<br />

the cameras using the operator match_rel_pose_ransac and then use all the stereo methods described<br />

for the fully calibrated case. There is, however, a limitation: The determined pose is relative<br />

in a second sense, because it can be determined only up to a scale factor. The reason for this


8 Robot Vision 109<br />

is that without any knowledge about the scene, the algorithm cannot know whether the points in the<br />

scene are further away or whether the cameras are further apart because the effect in the image is the<br />

same in both cases. If you have additional information about the scene, you can solve this ambiguity<br />

and determine the “real” relative pose. This method is shown in the HDevelop example program<br />

hdevelop\Tools\Stereo\uncalib_stereo_boxes.dev.<br />

8 Robot Vision<br />

A typical application area for 3D machine vision is robot vision, i.e., whenever robots are equipped with<br />

cameras that supply information about the parts to manufacture. Such systems are also called “hand-eye<br />

systems” because the robotic “hand” is guided by mechanical “eyes”.<br />

In order to use the information extracted by the camera, it must be transformed into the coordinate system<br />

of the robot. Thus, besides calibrating the camera(s) you must also calibrate the hand-eye system, i.e.,<br />

determine the transformation between camera and robot coordinates. The following sections explain<br />

how to perform this hand-eye calibration with <strong>HALCON</strong>.<br />

a) b)<br />

Figure 75: Robot vision scenarios: (a) moving camera, (b) stationary camera.<br />

Please note that in order to use <strong>HALCON</strong>’s hand-eye calibration, the camera must observe the !<br />

workspace of the robot. Figure 75 depicts the two possible scenarios: The camera can either be<br />

mounted on the robot and is moved to different positions by it, or it can be stationary. If the camera<br />

does not observe the workspace of the robot, e.g., if the camera observes parts on a conveyor belt, which<br />

are then handled by a robot further down the line, you must determine the relative pose of robot and<br />

camera with different means.<br />

The calibration result can be used for different tasks. Typically, the results of machine vision, e.g., the<br />

position of a part, are to be transformed from camera into robot coordinates to create the appropriate<br />

robot commands, e.g., to grasp the part. Section 8.4 on page 119 describes such an application. Another<br />

possible application for hand-eye systems with a moving camera is to transform the information extracted<br />

from different camera poses into a common coordinate system.<br />

<strong>Note</strong> that <strong>HALCON</strong>’s hand-eye calibration is not restricted to systems with a “hand”, i.e., a manipulator.<br />

You can also use it to calibrate cameras mounted on a pan-tilt head or surveillance cameras that rotate<br />

to observe a large area. Both systems correspond to a camera mounted on a robot; the calibration then<br />

allows you to accumulate visual information from different camera poses.<br />

Further note that, although in the following only systems with a single camera are described, you can of<br />

course also use a stereo camera system. In this case, you typically calibrate only the relation of the robot<br />

Robot Vision


110 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

!<br />

tool<br />

H base<br />

base<br />

z<br />

y<br />

x<br />

camera<br />

cam<br />

y<br />

y<br />

z<br />

x<br />

base<br />

H cal<br />

tool<br />

z<br />

cal. object<br />

cam<br />

H tool<br />

H cal<br />

y<br />

x<br />

z<br />

x<br />

cam<br />

H tool<br />

Figure 76: Chain of transformations for a moving camera system.<br />

base<br />

H tool<br />

base<br />

z<br />

y<br />

x<br />

tool<br />

cal. object<br />

cam<br />

H base<br />

cam<br />

H cal<br />

z<br />

camera<br />

y<br />

x<br />

y<br />

z<br />

tool<br />

H cal<br />

Figure 77: Chain of transformations for a stationary camera system.<br />

to one of the cameras, because the relation between the cameras is determined by the stereo calibration<br />

(see section 7.3.3 on page 95).<br />

8.1 The Principle of Hand-Eye Calibration<br />

Like the camera calibration (see section 3.1 on page 29), the hand-eye calibration is based on providing<br />

multiple images of a known calibration object. But in contrast to the camera calibration, here the calibration<br />

object is not moved manually but by the robot, which moves either the calibration object in front<br />

of a stationary camera or the camera over a stationary calibration object. The pose, i.e., the position and<br />

orientation, of the robot in each calibration image must be known with high accuracy!<br />

This results in a chain of coordinate transformations (see figure 76 and figure 77). In this chain, two<br />

transformations (poses) are known: the robot pose base Htool and the pose of the calibration object in<br />

camera coordinates cam Hcal, which is determined from the calibration images before starting the hand-<br />

x<br />

z<br />

x<br />

y


8.1 The Principle of Hand-Eye Calibration 111<br />

eye calibration. The hand-eye calibration then estimates the other two poses, i.e., the relation between<br />

the robot and the camera and between the robot and the calibration object, respectively.<br />

<strong>Note</strong> that the chain consists of different poses depending on the used scenario. For a moving camera,<br />

the pose of the robot tool in camera coordinates and the pose of the calibration object in robot base<br />

coordinates are determined (see figure 76 on page 110):<br />

cam Hcal = cam Htool · tool Hbase · base Hcal<br />

Please beware that in this chain the inverse robot pose, i.e., the pose of the robot base in tool coordinates,<br />

is used.<br />

For a stationary camera, the pose of the robot base in camera coordinates and of the calibration object<br />

in robot tool coordinates are determined (see figure 77 on page 110):<br />

cam Hcal = cam Hbase · base Htool · tool Hcal<br />

The hand-eye calibration is performed with a single call to the operator hand_eye_calibration:<br />

hand_eye_calibration (NX, NY, NZ, NRow, NCol, MPointsOfImage, MRelPoses,<br />

BaseStartPose, CamStartPose, CamParam, ’all’,<br />

’CountIterations’, 100, 0.0005, BaseFinalPose,<br />

CamFinalPose, NumErrors)<br />

Let’s have a brief look at the parameters; the referenced sections contain more detailed information:<br />

• NX, NY, NZ, NRow, NCol, MPointsOfImage (see section 8.2.1)<br />

As for the camera calibration, you must supply 3D model points and their corresponding image<br />

points. <strong>Note</strong>, however, that for the hand-eye calibration the 3D point coordinates must be sup- !<br />

plied for each image, together with the number of 3D points visible in each image. This requirement<br />

might seem tedious if you use the standard calibration plate, because then the same points<br />

are visible in each image, but it offers more flexibility for users of other calibration objects.<br />

• MRelPoses (see section 8.2.2 on page 113)<br />

This parameter contains the poses of the robot in each calibration image.<br />

• BaseStartPose, CamStartPose (see section 8.2.3 on page 114)<br />

For the poses that are to be calibrated, you must provide start values.<br />

• CamParam<br />

In this parameter you pass the interior camera parameters. In the HDevelop<br />

example programs hdevelop\handeye_movingcam_calibration.dev and<br />

hdevelop\handeye_stationarycam_calibration.dev, the camera is calibrated using<br />

the calibration images acquired for the hand-eye calibration. For detailed information about<br />

obtaining the interior camera parameters please refer to section 3.1.4 on page 36.<br />

• ToEstimate<br />

This parameter allows you to choose which pose parameters are to be calibrated and which are to<br />

stay the same as in the start values.<br />

(45)<br />

(46)<br />

Robot Vision


112 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

!<br />

• StopCriterion, MaxIterations, MinError<br />

With these parameters you can specify when the calibration algorithm should stop.<br />

• BaseFinalPose, CamFinalPose, NumErrors<br />

These are the calibration results. How to use them in robot vision applications is described in<br />

section 8.4 on page 119.<br />

Besides the coordinate systems described above, two others may be of interest in a robot vision application:<br />

First, sometimes results must be transformed into a reference (world) coordinate system. You can<br />

define such a coordinate system easily based on a calibration image. Secondly, especially if the robot<br />

system uses different tools, it might be useful to place the tool coordinate system used in the calibration<br />

at the mounting point of the tools and introduce additional coordinate systems at the respective tool<br />

center points. The example application in section 8.4 on page 119 shows how to handle both cases.<br />

8.2 Determining Suitable Input Parameters<br />

Below, we show how to determine values for the input parameters<br />

of hand_eye_calibration. The code examples stem from the HDevelop<br />

programs hdevelop\handeye_movingcam_calibration.dev and<br />

hdevelop\handeye_stationarycam_calibration.dev, which perform the calibration of hand-eye<br />

systems with a moving and stationary camera, respectively. The programs stop after processing each<br />

calibration image; press Run to continue.<br />

Section 8.2.4 on page 116 explains how to check the input parameters before performing the calibration.<br />

8.2.1 Corresponding World and Image Points<br />

As for the camera calibration, you must supply 3D model points and their corresponding image points<br />

(compare section 3.1.1 on page 30). First, we create empty tuples to accumulate data from all calibration<br />

images:<br />

NRow := []<br />

NCol := []<br />

NX := []<br />

NY := []<br />

NZ := []<br />

MPointsOfImage := []<br />

When using the standard calibration plate, the 3D model points, i.e., the 3D coordinates of the calibration<br />

marks, can be read from the description file:<br />

caltab_points (CalTabFile, X, Y, Z)<br />

In each calibration image, we then locate the calibration plate and extract the image coordinates of the<br />

calibration marks. Please note that for the hand-eye calibration we strongly recommend to use the<br />

asymmetric calibration plate introduced with <strong>HALCON</strong> 7.1 (see section 3.1.6 on page 43). If even<br />

only in a single calibration image the pose of the old, symmetric calibration plate is estimated wrongly<br />

because it is rotated by more than 90 degrees, the calibration will fail!


for i := 0 to NumImages-1 by 1<br />

read_image (Image, ImageNameStart+i$’02d’)<br />

find_caltab (Image, Caltab, CalTabFile, SizeGauss, MarkThresh,<br />

MinDiamMarks)<br />

find_marks_and_pose (Image, Caltab, CalTabFile, StartCamParam,<br />

StartThresh, DeltaThresh, MinThresh, Alpha,<br />

MinContLength, MaxDiamMarks, RCoord, CCoord,<br />

StartPose)<br />

Finally, the corresponding coordinates are accumulated in the tuples:<br />

NRow := [NRow,RCoord]<br />

NCol := [NCol,CCoord]<br />

NX := [NX,X]<br />

NY := [NY,Y]<br />

NZ := [NZ,Z]<br />

MPointsOfImage := [MPointsOfImage,49]<br />

endfor<br />

8.2.2 Robot Poses 113<br />

<strong>Note</strong> that the 3D coordinates and number of marks per image are accumulated even if they don’t change<br />

betweeen images. As already explained, the possibility to use different model points in each image is<br />

not necessary when using the standard calibration plate, but can be very useful if you use your own<br />

calibration object, especially if it is a three-dimensional one.<br />

8.2.2 Robot Poses<br />

For each of the calibration images, you must specify the corresponding pose of the robot. <strong>Note</strong> that the !<br />

accuracy of the poses is critical to obtain an accurate hand-eye calibration. There are two ways<br />

to “feed” the poses into <strong>HALCON</strong>: In many cases, you will simply read them from the robot control<br />

unit and then enter them into your <strong>HALCON</strong> program manually. For this, you can use the HDevelop<br />

example program hdevelop\handeye_create_robot_poses.dev, which lets you input the poses in<br />

a text window and writes them into files.<br />

As an alternative, if the robot has a serial interface, you can also send them via this connection to your<br />

<strong>HALCON</strong> program (see the section “System ⊲ Serial” in the Reference Manual for information about<br />

communicating via the serial interface).<br />

In both cases, you then convert the data into <strong>HALCON</strong> 3D poses using the operator create_pose. As<br />

described in section 2.1.5 on page 17 (and in the Reference Manual entry for create_pose), you can<br />

specify a pose in more than one way, because the orientation can be described by different sequences of<br />

rotations. Therefore, you must first check which sequence is used by your robot system. In many cases,<br />

it will correspond to<br />

Rabg = Rz(RotZ) · Ry(RotY) · Rx(RotX) (47)<br />

If this is the case, select the value ’abg’ for the parameter OrderOfRotation of create_pose. For the<br />

inverse order, select ’gba’.<br />

If your robot system uses yet another sequence, you cannot use create_pose but must create a corresponding<br />

homogeneous transformation matrix and convert it into a pose using hom_mat3d_to_pose. If,<br />

Robot Vision


114 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

e.g., your robot system uses the following sequence of rotations where the rotations are perfomed around<br />

the z-axis, then around the y-axis, and finally again around the z-axis<br />

the pose can be created with the following code:<br />

Rzyz = Rz(Rl) · Ry(Rm) · Rz(Rr) (48)<br />

hom_mat3d_identity (HomMat3DIdentity)<br />

hom_mat3d_translate (HomMat3DIdentity, Tx, Ty, Tz,<br />

HomMat3DTranslate)<br />

hom_mat3d_rotate_local (HomMat3DTranslate, rad(Rl), ’z’,<br />

HomMat3DT_Rl)<br />

hom_mat3d_rotate_local (HomMat3DT_Rl, rad(Rm), ’y’,<br />

HomMat3DT_Rl_Rm)<br />

hom_mat3d_rotate_local (HomMat3DT_Rl_Rm, rad(Rr), ’z’,<br />

HomMat3D)<br />

hom_mat3d_to_pose (HomMat3D, Pose)<br />

<strong>Note</strong> that the rotation operators expect angles to be given in radians, whereas create_pose expects<br />

them in degrees!<br />

The example program hdevelop\handeye_create_robot_poses.dev allows you to enter poses of<br />

the three types described above. If your robot system uses yet another sequence of rotations, you can<br />

easily extend the program by modifying (or copying and adapting) the code for ZYZ poses.<br />

The HDevelop example programs hdevelop\handeye_movingcam_calibration.dev and<br />

hdevelop\handeye_stationarycam_calibration.dev read the robot pose files in the loop<br />

of processing the calibration images. Before this, an empty tuple is created to accumulate the poses:<br />

MRelPoses := []<br />

For each calibration image, the pose of the robot is read from file using read_pose and accumulated in<br />

the tuple:<br />

read_pose (DataNameStart+’robot_pose_’+i$’02d’+’.dat’, TmpRobotPose)<br />

MRelPoses := [MRelPoses,TmpRobotPose]<br />

If you are using a hand-eye system with a moving camera, you must invert the pose (compare the chain<br />

of transformations in figure 76 on page 110):<br />

hom_mat3d_invert (base_H_tool, tool_H_base)<br />

hom_mat3d_to_pose (tool_H_base, RobotPoseInverse)<br />

MRelPoses := [MRelPoses,RobotPoseInverse]<br />

8.2.3 Start Values BaseStartPose and CamStartPose<br />

Depending on the used hand-eye configuration, the starting values BaseStartPose and CamStartPose<br />

correspond to the following poses:


Moving camera (see figure 76 on page 110)<br />

8.2.3 Start Values for the Poses to Calibrate 115<br />

BaseStartPose = pose of the calibration object in robot base coordinates ( base Hcal)<br />

CamStartPose = pose of the robot tool in camera coordinates ( cam Htool)<br />

Stationary camera (see figure 77 on page 110)<br />

BaseStartPose = pose of the calibration object in robot tool coordinates ( tool Hcal)<br />

CamStartPose = pose of the robot base in camera coordinates ( cam Hbase)<br />

Please note that the parameter names are misleading for stationary cameras! !<br />

We recommend to create these poses using create_pose and save them in files using write_pose, so<br />

that the calibration program can read them in later.<br />

In fact, you need a starting value only for one of the two poses. The other can be computed from<br />

one of the calibration images. This means that you can pick the pose that is easier to determine and<br />

let <strong>HALCON</strong> compute the other one for you. More precisely, we recommend to pick the pose whose<br />

orientation is easier to determine, because the hand-eye calibration may fail if there are large errors in<br />

the start values for the orientation.<br />

The main idea is to exploit the fact that the two poses for which we need starting values are connected<br />

via the already described chain of transformations (see equation 45 and equation 46 on page 111).<br />

If the camera is stationary, typically the pose of the calibration object in tool coordinates ( tool Hcal,<br />

BaseStartPose) is easier to determine, especially if the camera is oriented at an angle as in the hand-eye<br />

system depicted in figure 78: Here, the relation between tool and calibration plate is a pure translation.<br />

To determine cam Hbase, we rewrite equation 46 as follows:<br />

cam Hbase = cam Hcal ·( base Htool · tool Hcal) -1 = cam Hcal · cal Htool · tool Hbase<br />

In the example program hdevelop\handeye_stationarycam_calibration.dev, this computation<br />

is performed by the following HDevelop procedure<br />

procedure calc_cam_start_pose_stationarycam (: : CalplatePose, BaseStartPose,<br />

RobotPose: CamStartPose)<br />

pose_to_hom_mat3d (BaseStartPose, tool_H_calplate)<br />

hom_mat3d_invert (tool_H_calplate, calplate_H_tool)<br />

pose_to_hom_mat3d (RobotPose, base_H_tool)<br />

hom_mat3d_invert (base_H_tool, tool_H_base)<br />

pose_to_hom_mat3d (CalplatePose, cam_H_calplate)<br />

hom_mat3d_compose (cam_H_calplate, calplate_H_tool, cam_H_tool)<br />

hom_mat3d_compose (cam_H_tool, tool_H_base, cam_H_base)<br />

hom_mat3d_to_pose (cam_H_base, CamStartPose)<br />

return ()<br />

In the example programs, the pose of the calibration plate in camera coordinates ( cam Hcal) is determined<br />

when calibrating the camera itself using the operator camera_calibration. If you performed<br />

the camera calibration separately with other calibration images, you can use the poses determined by<br />

find_marks_and_pose (see section 8.2.1 on page 112) instead.<br />

If the camera is mounted on the robot, it is typically easy to determine a starting value for the pose of the<br />

calibration plate in robot base coordinates, i.e., BaseStartPose. Thus, we “solve” equation 45 for the<br />

(49)<br />

Robot Vision


116 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

a)<br />

z<br />

base<br />

y<br />

x<br />

y<br />

tool<br />

z<br />

y z<br />

x<br />

gripper<br />

z<br />

y<br />

camera<br />

x<br />

x<br />

b)<br />

y<br />

z<br />

x<br />

camera<br />

y x<br />

tool<br />

z<br />

y x<br />

calibration plate<br />

z<br />

Figure 78: Example hand-eye system with a stationary camera: coordinate systems (a) of robot and<br />

camera, (b) with calibration plate.<br />

other pose ( cam Htool):<br />

cam Htool = cam Hcal ·( tool Hbase · base Hcal) -1 = cam Hcal · cal Hbase · base Htool<br />

In the example program hdevelop\handeye_movingcam_calibration.dev, this computation is performed<br />

by the HDevelop procedure<br />

procedure calc_cam_start_pose_movingcam (: : CalplatePose, BaseStartPose,<br />

RobotPoseInverse: CamStartPose)<br />

pose_to_hom_mat3d (BaseStartPose, base_H_calplate)<br />

hom_mat3d_invert (base_H_calplate, calplate_H_base)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_invert (tool_H_base, base_H_tool)<br />

pose_to_hom_mat3d (CalplatePose, cam_H_calplate)<br />

hom_mat3d_compose (cam_H_calplate, calplate_H_base, cam_H_base)<br />

hom_mat3d_compose (cam_H_base, base_H_tool, cam_H_tool)<br />

hom_mat3d_to_pose (cam_H_tool, CamStartPose)<br />

return ()<br />

Both example programs also contain procedures for determining a start value for the other pose to calibrate.<br />

8.2.4 Checking the Input Parameters<br />

Before performing the hand-eye calibration as described in the following section, we recommend to (let<br />

<strong>HALCON</strong>) check the input parameters.<br />

(50)


Figure 79: <strong>HALCON</strong> calibration plate and its coordinate system.<br />

8.2.4 Checking the Input Parameters 117<br />

You can check the point correspondences determined in section 8.2.1 on page 112 by displaying them<br />

overlaid on the calibration images. If you use the <strong>HALCON</strong> calibration plate, you can call the procedure<br />

visualize_results_of_find_marks_and_pose (see appendix B.5 on page 140) as shown in the<br />

example programs. This procedure displays the center of the calibration marks and the coordinate system<br />

corresponding to the estimated pose of the calibration plate. As already noted, it is very important to<br />

check that the coordinate system is oriented correctly. Figure 79 shows a correctly found asymmetric<br />

calibration plate.<br />

The robot poses can be checked by computing the start values for the poses to calibrate in all calibration<br />

images as described in the previous section. The pose parameters, especially the rotation parameters,<br />

should not change noticeably from image to image. If they do, we recommend to check whether you<br />

used the correct pose type, i.e., the correct sequence of rotations.<br />

The following code stems from the example hdevelop\handeye_movingcam_calibration.dev.<br />

First, we open inspection windows using dev_open_inspect_ctrl to view the computed start values<br />

for the poses we want to calibrate:<br />

dev_inspect_ctrl (TmpCamStartPose)<br />

dev_inspect_ctrl (TmpBaseStartPose)<br />

For each calibration image, we then extract the corresponding input parameters from the tuples where<br />

they have been accumulated using a procedure (see appendix B.8 on page 142). With this data, the start<br />

values for the poses are calculated as described in section 8.2.3 on page 114. The poses are automatically<br />

displayed in the inspection windows. Finally, the coordinate system of the calibration plate is displayed<br />

by a procedure shown in appendix B.6 on page 141:<br />

z<br />

y<br />

x<br />

Robot Vision


118 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

select_values_for_ith_image (NRow, NCol, NX, NY, NZ, NFinalPose,<br />

MRelPoses, i, TmpRows, TmpCols, TmpX,<br />

TmpY, TmpZ, TmpFinalPose, TmpRobotPose)<br />

calc_base_start_pose_movingcam (TmpFinalPose, CamStartPose,<br />

TmpRobotPose, TmpBaseStartPose)<br />

calc_cam_start_pose_movingcam (TmpFinalPose, BaseStartPose,<br />

TmpRobotPose, TmpCamStartPose)<br />

display_calplate_coordinate_system (CalTabFile, TmpFinalPose, CamParam,<br />

WindowHandle)<br />

After the last image, the inspection windows are closed again using dev_close_inspect_ctrl:<br />

dev_close_inspect_ctrl (TmpCamStartPose)<br />

dev_close_inspect_ctrl (TmpBaseStartPose)<br />

8.3 Performing the Calibration<br />

Similar to the camera calibration, the main effort lies in collecting the input data. The calibration itself<br />

is performed with a single operator call:<br />

hand_eye_calibration (NX, NY, NZ, NRow, NCol, MPointsOfImage, MRelPoses,<br />

BaseStartPose, CamStartPose, CamParam, ’all’,<br />

’CountIterations’, 100, 0.0005, BaseFinalPose,<br />

CamFinalPose, NumErrors)<br />

Typically, you then save the calibrated poses in files so that your robot vision application can read them<br />

at a later time. The following code does so for a system with a moving camera:<br />

write_pose (CamFinalPose, DataNameStart+’final_pose_cam_tool.dat’)<br />

write_pose (BaseFinalPose, DataNameStart+’final_pose_base_calplate.dat’)<br />

Of course, you should check whether the calibration was successful by looking at the output parameter<br />

NumErrors, which is a measure for the accuracy of the pose parameters. It contains the deviation of<br />

the model points in meters for each iteration. In the example programs, the parameter is displayed in an<br />

inspection window with the following line. You can scroll down to the last entry to get the final error.<br />

dev_inspect_ctrl (NumErrors)<br />

Similarly to checking the input parameters (see section 8.2.4 on page 116), the example programs then<br />

visualize the calibrated poses by displaying the coordinate system of the calibration plate in each calibration<br />

image. But now we compute the pose of the calibration plate in camera coordinates based on<br />

the calibrated poses. For a moving camera system, this corresponds to the following code (compare<br />

equation 45 on page 111):


* CalplatePose = cam_H_calplate = cam_H_tool * tool_H_base * base_H_calplate<br />

pose_to_hom_mat3d (BaseFinalPose, base_H_calplate)<br />

pose_to_hom_mat3d (CamFinalPose, cam_H_tool)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_compose (cam_H_tool, tool_H_base, cam_H_base)<br />

hom_mat3d_compose (cam_H_base, base_H_calplate, cam_H_calplate)<br />

hom_mat3d_to_pose (cam_H_calplate, CalplatePose)<br />

This code is encapsulated in a procedure, which is called in a loop over all images:<br />

for i := 0 to NumImages-1 by 1<br />

read_image (Image, ImageNameStart+i$’02d’)<br />

TmpRobotPoseInverse := MRelPoses[i*7:i*7+6]<br />

calc_calplate_pose_movingcam (BaseFinalPose, CamFinalPose,<br />

TmpRobotPoseInverse, TmpCalplatePose)<br />

display_calplate_coordinate_system (CalTabFile, TmpCalplatePose,<br />

CamParam, WindowHandle)<br />

endfor<br />

8.4 Using the Calibration Data 119<br />

The corresponding procedure for a stationary camera system please is listed in appendix B.14 on page<br />

144.<br />

8.4 Using the Calibration Data<br />

Typically, you use the result of the hand-eye calibration to transform the results of machine vision from<br />

camera coordinates into robot coordinates to generate the appropriate robot commands, e.g., to grasp an<br />

object whose position has been determined in an image as in the application described in section 8.4.1.<br />

For a stationary camera, this transformation corresponds to the following equation (compare figure 77<br />

on page 110):<br />

base Hobj = base Hcam · cam Hobj = (CamStartPose) -1 · cam Hobj<br />

For a moving camera system, the equation also contains the pose of the robot (compare figure 76 on page<br />

110):<br />

base Hobj = base Htool · tool Hcam · cam Hobj = base Htool ·(CamStartPose) -1 · cam Hobj<br />

The 3D pose of the object in camera coordinates can stem from different sources:<br />

• With a binocular stereo system, you can determine the 3D pose of unknown objects directly (see<br />

section 7 on page 88).<br />

• With only a single camera, you can use pose estimation to determine the 3D pose of known objects<br />

(see section 8.4.1 for an example application and section 6 on page 84 for more details on pose<br />

estimation).<br />

• With a single camera, you can determine the 3D coordinates of unknown objects if you know that<br />

object points lie in a known plane (see section 8.4.1 for an example application and section 3.2 on<br />

page 44 for more details on determining 3D points in a known plane).<br />

(51)<br />

(52)<br />

Robot Vision


120 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

a)<br />

C1 − C4: corner points<br />

G1 & G2: grasping points<br />

grasping pose<br />

reference coordinate system<br />

b)<br />

Figure 80: (a) Determining the 3D pose for grasping a nut; (b) robot at grasping pose.<br />

8.4.1 Example <strong>Application</strong> with a Stationary Camera: Grasping a Nut<br />

This section describes an example application realized with the hand-eye system depicted in figure 78<br />

on page 116. The task is to localize a nut and determine a suitable grasping pose for the robot (see<br />

figure 80). The HDevelop example program hdevelop\handeye_stationarycam_grasp_nut.dev<br />

performs the machine vision part and transforms the resulting pose into robot coordinates using the calibration<br />

data determined with hdevelop\handeye_stationarycam_calibration.dev as described<br />

in the previous sections. As you will see, using the calibration data is the shortest part of the program,<br />

its main part is devoted to machine vision.<br />

First, the calibration data is read from files; for later computations, the poses are converted into homogeneous<br />

transformation matrices:<br />

read_cam_par (DataNameStart+’final_campar.dat’, CamParam)<br />

read_pose (DataNameStart+’final_pose_cam_base.dat’, PoseCamBase)<br />

pose_to_hom_mat3d (PoseCamBase, cam_H_base)<br />

read_pose (DataNameStart+’final_pose_tool_calplate.dat’, PoseToolCalplate)<br />

pose_to_hom_mat3d (PoseToolCalplate, tool_H_calplate)<br />

In the used hand-eye system, the tool coordinate system used in the calibration process is located at the<br />

mounting point of the tool; therefore, an additional coordinate system is needed between the fingers of<br />

the gripper (see figure 78a on page 116). Its pose in tool coordinates is also read from file:<br />

read_pose (DataNameStart+’pose_tool_gripper.dat’, PoseToolGripper)<br />

pose_to_hom_mat3d (PoseToolGripper, tool_H_gripper)<br />

Now, a reference coordinate system is defined based on one of the calibration images. In this image,<br />

the calibration plate has been placed into the plane on top of the nut. This allows to determine the<br />

3D coordinates of extracted image points on the nut with a single camera and without knowing the<br />

dimensions of the nut. The code for defining the reference coordinate system is contained in a procedure,<br />

which is listed in appendix B.15 on page 144:


8.4.1 Example <strong>Application</strong> with a Stationary Camera: Grasping a Nut 121<br />

define_reference_coord_system (ImageNameStart+’calib3cm_00’, CamParam,<br />

CalplateFile, WindowHandle, PoseRef)<br />

pose_to_hom_mat3d (PoseRef, cam_H_ref)<br />

The following code extracts grasping points on two opposite sides of the nut. The nut is found with<br />

simple blob analysis; its boundary is converted into XLD contours:<br />

threshold (Image, BrightRegion, 60, 255)<br />

connection (BrightRegion, BrightRegions)<br />

select_shape (BrightRegions, Nut, ’area’, ’and’, 500, 99999)<br />

fill_up (Nut, NutFilled)<br />

gen_contour_region_xld (NutFilled, NutContours, ’border’)<br />

The contours are then processed to find long, parallel straight line segments; their corners are accumulated<br />

in tuples:<br />

segment_contours_xld (NutContours, LineSegments, ’lines’, 5, 4, 2)<br />

fit_line_contour_xld (LineSegments, ’tukey’, -1, 0, 5, 2, RowBegin,<br />

ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)<br />

Lines := []<br />

for i := 0 to |RowBegin| -1 by 1<br />

gen_contour_polygon_xld (Contour, [RowBegin[i],RowEnd[i]],<br />

[ColBegin[i],ColEnd[i]])<br />

Lines := [Lines,Contour]<br />

endfor<br />

gen_polygons_xld (Lines, Polygon, ’ramer’, 2)<br />

gen_parallels_xld (Polygon, ParallelLines, 50, 100, rad(10), ’true’)<br />

get_parallels_xld (ParallelLines, Row1, Col1, Length1, Phi1, Row2, Col2,<br />

Length2, Phi2)<br />

CornersRow := [Row1[0], Row1[1], Row2[0], Row2[1]]<br />

CornersCol := [Col1[0], Col1[1], Col2[0], Col2[1]]<br />

The grasping pose is calculated in 3D coordinates. For this, the 3D coordinates of the corner points in<br />

the reference coordinate system are determined using the operator image_points_to_world_plane.<br />

The origin of the grasping pose lies in the middle of the corners:<br />

image_points_to_world_plane (CamParam, PoseRef, CornersRow, CornersCol,<br />

’m’, CornersX_ref, CornersY_ref)<br />

CenterPointX_ref := sum(CornersX_ref)*0.25<br />

CenterPointY_ref := sum(CornersY_ref)*0.25<br />

The grasping pose is oriented almost like the reference coordinate system, only rotated around the z-axis<br />

so that the gripper “fingers” are parallel to the sides of the nut. To calculate the rotation angle, first the<br />

grasping points in the middle of the sides are determined. Their angle can directly be used as the rotation<br />

angle:<br />

Robot Vision


122 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

GraspPointsX_ref := [(CornersX_ref[0]+CornersX_ref[1])*0.5,<br />

(CornersX_ref[2]+CornersX_ref[3])*0.5]<br />

GraspPointsY_ref := [(CornersY_ref[0]+CornersY_ref[1])*0.5,<br />

(CornersY_ref[2]+CornersY_ref[3])*0.5]<br />

GraspPhiZ_ref := atan((GraspPointsY_ref[1]-GraspPointsY_ref[0])/<br />

(GraspPointsX_ref[1]-GraspPointsX_ref[0]))<br />

With the origin and rotation angle, the grasping pose is first determined in the reference coordinate<br />

system and then transformed into camera coordinates:<br />

hom_mat3d_identity (HomMat3DIdentity)<br />

hom_mat3d_rotate (HomMat3DIdentity, GraspPhiZ_ref, ’z’, 0, 0, 0,<br />

HomMat3D_RZ_Phi)<br />

hom_mat3d_translate (HomMat3D_RZ_Phi, CenterPointX_ref, CenterPointY_ref,<br />

0, ref_H_grasp)<br />

hom_mat3d_compose (cam_H_ref, ref_H_grasp, cam_H_grasp)<br />

Alternatively, the example also shows how to calculate the grasping pose using pose estimation (see<br />

section 6 on page 84 for a detailed description). This method can be used when points on the object are<br />

known. In the example, we specify the 3D coordinates of the corners of the nut:<br />

NX := [0.009, -0.009, -0.009, 0.009]<br />

NY := [0.009, 0.009, -0.009, -0.009]<br />

The grasping pose is then calculated by simply calling the operator camera_calibration, using the<br />

reference coordinate system as the start pose. Before, however, the image coordinates of the corners must<br />

be sorted such that the first one lies close to the x-axis of the reference cooridinate system. Otherwise,<br />

the orientation of the reference coordinate system would differ to much from the grasping pose and the<br />

pose estimation would fail.<br />

sort_corner_points (CornersRow, CornersCol, WindowHandle, NRow, NCol)<br />

camera_calibration (NX, NY, NZ, NRow, NCol, CamParam, PoseRef, ’pose’,<br />

CamParam, PoseCamNut, Errors)<br />

display_3d_coordinate_system (PoseCamGripper, CamParam, 0.01, WindowHandle,<br />

The result of both methods is displayed in figure 80a on page 120.<br />

Now comes the moment to use the results of the hand-eye calibration: The grasping pose is transformed<br />

into robot coordinates with the formula shown in equation 51 on page 119:<br />

hom_mat3d_invert (cam_H_base, base_H_cam)<br />

hom_mat3d_compose (base_H_cam, cam_H_grasp, base_H_grasp)<br />

As already mentioned, the tool coordinate system used in the calibration process is placed at the mounting<br />

point of the tool, not between the fingers of the gripper. Thus, the pose of the tool in gripper coordinates<br />

must be added to the chain of transformations to obtain the pose of the tool in base coordinates:<br />

hom_mat3d_invert (tool_H_gripper, gripper_H_tool)<br />

hom_mat3d_compose (base_H_grasp, gripper_H_tool, base_H_tool)<br />

Finally, the pose is converted into the type used by the robot controller:


hom_mat3d_to_pose (base_H_tool, PoseRobotGrasp)<br />

convert_pose_type (PoseRobotGrasp, ’Rp+T’, ’abg’, ’point’,<br />

PoseRobotGrasp_ZYX)<br />

Figure 80b on page 120 shows the robot at the grasping pose.<br />

9 Rectification of Arbitrary Distortions<br />

9 Rectification of Arbitrary Distortions 123<br />

For many applications like OCR or bar code reading, distorted images must be rectified prior to the<br />

extraction of information. The distortions may be caused by the perspective projection and the radial<br />

lens distortions as well as by non-radial lens distortions, a non-flat object surface, or by any other reason.<br />

In the first two cases, i.e., if the object surface is flat and the camera shows only radial distortions, the<br />

rectification can be carried out very precisely as described in section 3.3.1 on page 49. For the remaining<br />

cases, a piecewise bilinear rectification can be carried out. In <strong>HALCON</strong>, this kind of rectification is<br />

called grid rectification.<br />

The following example (hdevelop\grid_rectification_ruled_surface.dev) shows how the grid<br />

rectification can be used to rectify the image of a cylindrically shaped object (figure 81). In the rectified<br />

image (figure 81b), the bar code could be read correctly, which was not possible in the original image<br />

(figure 81a).<br />

a) b)<br />

Figure 81: Cylindrical object: a) Original image; b) rectified image.<br />

The main idea of the grid rectification is that the mapping for the rectification is determined from an<br />

image of the object, where the object is covered by a known pattern.<br />

First, this pattern, which is called rectification grid, must be created with the operator<br />

create_rectification_grid.<br />

Rectification


124 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

create_rectification_grid (WidthOfGrid, NumSquares,<br />

’rectification_grid.ps’)<br />

The resulting PostScript file must be printed. An example for such a rectification grid is shown in<br />

figure 82a.<br />

a) b)<br />

Figure 82: a) Example of a rectification grid. b) Cylindrical object wrapped with the rectification grid.<br />

Now, the object must be wrapped with the rectification grid and an image of the wrapped object must be<br />

taken (figure 82b).<br />

From this image, the mapping that describes the transformation from the distorted image into the rectified<br />

image can be derived. For this, first, the rectification grid must be extracted. Then, the rectification map<br />

is derived from the distorted grid. This can be achieved by the following lines of code:<br />

find_rectification_grid (Image, GridRegion, MinContrast, Radius)<br />

reduce_domain (Image, GridRegion, ImageReduced)<br />

saddle_points_sub_pix (ImageReduced, ’facet’, SigmaSaddlePoints, Threshold,<br />

Row, Col)<br />

connect_grid_points (ImageReduced, ConnectingLines, Row, Col,<br />

SigmaConnectGridPoints, MaxDist)<br />

gen_grid_rectification_map (ImageReduced, ConnectingLines, Map, Meshes,<br />

GridSpacing, 0, Row, Col)<br />

Using the derived map, any image that shows the same distortions can be rectified such that the parts<br />

that were covered by the rectification grid appear undistorted in the rectified image (figure 81b). This<br />

mapping is performed by the operator map_image.<br />

map_image (ImageReduced, Map, ImageMapped)<br />

In the following section, the basic principle of the grid rectification is described. Then, some hints for<br />

taking images of the rectification grid are given. In section 9.3 on page 127, the use of the involved<br />

<strong>HALCON</strong> operators is described in more detail based on the above example application. Finally, it is<br />

described briefly how to use self-defined grids for the generation of rectification maps.


9.1 Basic Principle<br />

9.1 Basic Principle 125<br />

The basic principle of the grid rectification is that a mapping from the distorted image into the rectified<br />

image is determined from a distorted image of the rectification grid whose undistorted geometry is well<br />

known: The black and white fields of the printed rectification grid are squares (figure 83).<br />

Figure 83: Rectification grid.<br />

In the distorted image, the black and white fields do not appear as squares (figure 84a) because of the<br />

non-planar object surface, the perspective distortions, and the lens distortions.<br />

To determine the mapping for the rectification of the distorted image, the distorted rectification grid must<br />

be extracted. For this, first, the corners of the black and white fields must be extracted with the operator<br />

saddle_points_sub_pix (figure 84b). These corners must be connected along the borders of the<br />

black and white fields with the operator connect_grid_points (figure 84c). Finally, the connecting<br />

lines must be combined into meshes (figure 84d) with the operator gen_grid_rectification_map,<br />

which also determines the mapping for the rectification of the distorted image.<br />

If you want to use a self-defined grid, the grid points must be defined by yourself. Then, the operator<br />

gen_arbitrary_distortion_map can be used to determine the mapping (see section 9.4 on page 130<br />

for an example).<br />

The mapping is determined such that the distorted rectification grid will be mapped into its original<br />

undistorted geometry (figure 85). With this mapping, any image that shows the same distortions can<br />

be rectified easily with the operator map_image. <strong>Note</strong> that within the meshes a bilinear interpolation<br />

is carried out. Therefore, it is important to use a rectification grid with an appropriate grid size (see<br />

section 9.2 for details).<br />

9.2 Rules for Taking Images of the Rectification Grid<br />

If you want to achieve accurate results, please follow the rules given in this section:<br />

Rectification


126 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

a) b)<br />

c) d)<br />

Figure 84: Distorted rectification grid: a) Image; b) extracted corners of the black and white fields; c) lines<br />

that connect the corners; d) extracted rectification grid.<br />

→<br />

a) b)<br />

Figure 85: Mapping of the distorted rectification grid (a) into the undistorted rectification grid (b).


9.3 Machine Vision on Ruled Surfaces 127<br />

• The image must not be overexposed or underexposed: otherwise, the extraction of the corners of<br />

the black and white fields of the rectification grid may fail.<br />

• The contrast between the bright and the dark fields of the rectification grid should be as high as<br />

possible.<br />

• Ensure that the rectification grid is homogeneously illuminated.<br />

• The images should contain as little noise as possible.<br />

• The border length of the black and white fields should be at least 10 pixels.<br />

In addition to these few rules for the taking of the images of the rectification grid, it is very important<br />

to use a rectification grid with an appropriate grid size because the mapping is determined such that<br />

within the meshes of the rectification grid a bilinear interpolation is applied. Because of this, non-linear<br />

distortions within the meshes cannot be eliminated.<br />

The use of a rectification grid that is too coarse (figure 86a), i.e., whose grid size is too large, leads to<br />

errors in the rectified image (figure 86b).<br />

a) b)<br />

Figure 86: Cylindrical object covered with a very coarse rectification grid: a) Distorted image; b) rectified<br />

image.<br />

If it is necessary to fold the rectification grid, it should be folded along the borders of the black and white<br />

fields. Otherwise, i.e., if the fold crosses these fields (figure 87a), the rectified image (figure 87b) will<br />

contain distortions because of the bilinear interpolation within the meshes.<br />

9.3 Machine Vision on Ruled Surfaces<br />

In this section, the rectification of images of ruled surfaces is described in detail. Again, the example<br />

of the cylindrically shaped object (hdevelop\grid_rectification_ruled_surface.dev) is used to<br />

explain the involved operators.<br />

First, the operator create_rectification_grid is used to create a suitable rectification grid.<br />

Rectification


128 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

a) b)<br />

Figure 87: Rectification grid folded across the borders of the black and white fields: a) Distorted image;<br />

b) rectified image.<br />

create_rectification_grid (WidthOfGrid, NumSquares,<br />

’rectification_grid.ps’)<br />

The parameter WidthOfGrid defines the effectively usable size of the rectification grid in meters and<br />

the parameter NumSquares sets the number of squares (black and white fields) per row. The rectification<br />

grid is written to the PostScript file that is specified by the parameter GridFile.<br />

To determine the mapping, an image of the rectification grid, wrapped around the object, must be taken<br />

as described in section 9.2 on page 125. Figure 88a shows an image of a cylindrical object and figure 88b<br />

shows the same object wrapped by the rectification grid.<br />

Then, the rectification grid is searched in this image with the operator find_rectification_grid.<br />

find_rectification_grid (Image, GridRegion, MinContrast, Radius)<br />

The operator find_rectification_grid extracts image areas with a contrast of at least<br />

MinContrast and fills up the holes in these areas. <strong>Note</strong> that in this case, contrast is defined as the<br />

gray value difference of neighboring pixels in a slightly smoothed copy of the image (Gaussian smoothing<br />

with σ = 1.0). Therefore, the value for the parameter MinContrast must be set significantly lower<br />

than the gray value difference between the black and white fields of the rectification grid. Small areas of<br />

high contrast are then eliminated by an opening with the radius Radius. The resulting region is used to<br />

restrict the search space for the following steps with the operator reduce_domain (see figure 89a).<br />

reduce_domain (Image, GridRegion, ImageReduced)<br />

The corners of the black and white fields appear as saddle points in the image. They can be extracted<br />

with the operator saddle_points_sub_pix (see figure 89b).<br />

saddle_points_sub_pix (ImageReduced, ’facet’, SigmaSaddlePoints, Threshold,<br />

Row, Col)<br />

The parameter Sigma controls the amount of Gaussian smoothing that is carried out before the actual<br />

extraction of the saddle points. Which point is accepted as a saddle point is based on the value of the


a) b)<br />

Figure 88: Cylindrical object: a) Without and b) with rectification grid.<br />

9.3 Machine Vision on Ruled Surfaces 129<br />

parameter Threshold. If Threshold is set to higher values, fewer but more distinct saddle points are<br />

returned than if Threshold is set to lower values. The filter method that is used for the extraction of the<br />

saddle points can be selected by the parameter Filter. It can be set to ’facet’ or ’gauss’. The method<br />

’facet’ is slightly faster. The method ’gauss’ is slightly more accurate but tends to be more sensitive to<br />

noise.<br />

a) b) c)<br />

Figure 89: Distorted rectification grid: a) Image reduced to the extracted area of the rectification grid; b)<br />

extracted corners of the black and white fields; c) lines that connect the corners.<br />

To generate a representation of the distorted rectification grid, the extracted saddle points must be connected<br />

along the borders of the black and white fields (figure 89c). This is done with the operator<br />

connect_grid_points.<br />

connect_grid_points (ImageReduced, ConnectingLines, Row, Col,<br />

SigmaConnectGridPoints, MaxDist)<br />

Again, the parameter Sigma controls the amount of Gaussian smoothing that is carried out before<br />

the extraction of the borders of the black and white fields. When a tuple of three values [sigma_min,<br />

sigma_max, sigma_step] is passed instead of only one value, the operator connect_grid_points tests<br />

every sigma within the given range from sigma_min to sigma_max with a step size of sigma_step and<br />

Rectification


130 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

chooses the sigma that causes the largest number of connecting lines. The same happens when a tuple<br />

of only two values sigma_min and sigma_max is passed. However, in this case a fixed step size of 0.05<br />

is used. The parameter MaxDist defines the maximum distance with which an edge may be linked to<br />

the respectively closest saddle point. This helps to overcome the problem that edge detectors typically<br />

return inaccurate results in the proximity of edge junctions. Figure 90 shows the connecting lines if the<br />

parameter MaxDist has been selected inappropriately: In figure 90a, MaxDist has been selected to<br />

small, whereas in figure 90b, it has been selected too large.<br />

a) b)<br />

Figure 90: Connecting lines: Parameter MaxDist selected a) too small and b) too large.<br />

Then, the rectification map is determined from the distorted grid with the operator<br />

gen_grid_rectification_map.<br />

gen_grid_rectification_map (ImageReduced, ConnectingLines, Map, Meshes,<br />

GridSpacing, 0, Row, Col)<br />

The parameter GridSpacing defines the size of the grid meshes in the rectified image. Each of the black<br />

and white fields is projected onto a square of GridSpacing × GridSpacing pixels. The parameter<br />

Rotation controls the orientation of the rectified image. The rectified image can be rotated by 0, 90,<br />

180, or 270 degrees, or it is rotated such that the black circular mark is left of the white circular mark if<br />

Rotation is set to ’auto’.<br />

Using the derived rectification map, any image that shows the same distortions can be rectified very fast<br />

with the operator map_image (see figure 91). <strong>Note</strong> that the objects must appears at exactly the same<br />

position in the distorted images.<br />

map_image (ImageReduced, Map, ImageMapped)<br />

9.4 Using Self-Defined Rectification Grids<br />

Up to now, we have used the predefined rectification grid together with the appropriate operators for its<br />

segmentation. In this section, an alternative to this approach is presented. You can arbitrarily define<br />

the rectification grid by yourself, but note that in this case you must also carry out the segmentation by<br />

yourself.


a) b)<br />

Figure 91: Rectified images: a) Rectification grid; b) object.<br />

9.4 Using Self-Defined Rectification Grids 131<br />

This example shows how the grid rectification can be used to generate arbitrary distortion maps based on<br />

self-defined grids.<br />

The example application is a print inspection. It is assumed that some parts are missing and that smudges<br />

are present. In addition, lines may be vertically shifted, e.g., due to an inaccurate paper transport, i.e.,<br />

distortions in the vertical direction of the printed document may be present. These distortions should not<br />

result in a rejection of the tested document. Therefore, it is not possible to simply compute the difference<br />

image between a reference image and the image that must be checked.<br />

Figure 92a shows the reference image and figure 92b the test image that must be checked.<br />

In a first step, the displacements between the lines in the reference document and the test document are<br />

determined. With this, the rectification grid is defined. The resulting rectification map is applied to the<br />

reference image to transform it into the geometry of the test image. Now, the difference image of the<br />

mapped reference image and the test image can be computed.<br />

The example program (hdevelop\grid_rectification_arbitrary_distortion.dev) uses the<br />

component-based matching to determine corresponding points in the reference image and the test image.<br />

First, the component model is generated with the operator create_component_model. Then, the<br />

corresponding points are searched in the test image with the operator find_component_model.<br />

Based on the corresponding points of the reference and the test image (RowRef, ColRef, RowTest, and<br />

ColTest), the coordinates of the grid points of the distorted grid are determined. In this example, the<br />

row and column coordinates can be determined independently from each other because only the row<br />

coordinates are distorted. <strong>Note</strong> that the upper left grid point of the undistorted grid is assumed to have<br />

Rectification


132 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

a) b)<br />

smudges<br />

displaced lines<br />

missing line<br />

Figure 92: Images of one page of a document: a) Reference image; b) test image that must be checked.<br />

the coordinates (-0.5, -0.5). This means that the corresponding grid point of the distorted grid will be<br />

mapped to the point (-0.5, -0.5). Because there are only vertical distortions in this example, the column<br />

coordinates of the distorted grid are equidistant, starting at the value -0.5.<br />

GridSpacing := 10<br />

ColShift := mean(ColTest-ColRef)<br />

RefGridColValues := []<br />

for HelpCol := -0.5 to WidthTest+GridSpacing by GridSpacing<br />

RefGridColValues := [RefGridColValues, HelpCol+ColShift]<br />

endfor<br />

The row coordinates of the distorted grid are determined by a linear interpolation between the above<br />

determined pairs of corresponding row coordinates.<br />

MinValue := 0<br />

MaxValue := HeightTest+GridSpacing<br />

sample_corresponding_values (RowTest, RowRef-0.5, MinValue, MaxValue,<br />

GridSpacing, RefGridRowValues)<br />

The interpolation is performed within the procedure


procedure sample_corresponding_values (: : Values, CorrespondingValues,<br />

MinValue, MaxValue,<br />

InterpolationInterval:<br />

SampledCorrespondingValues)<br />

9.4 Using Self-Defined Rectification Grids 133<br />

which is part of the example program hdevelop\grid_rectification_arbitrary_distortion.dev.<br />

Now, the distorted grid is generated row by row.<br />

RefGridRow := []<br />

RefGridCol := []<br />

Ones := gen_tuple_const(|RefGridColValues|, 1)<br />

for r := 0 to |RefGridRowValues|-1 by 1<br />

RefGridRow := [RefGridRow, RefGridRowValues[r]*Ones]<br />

RefGridCol := [RefGridCol, RefGridColValues]<br />

endfor<br />

The operator gen_arbitrary_distortion_map uses this distorted grid to derive the rectification map<br />

that maps the reference image into the geometry of the test image 2 .<br />

gen_arbitrary_distortion_map (Map, GridSpacing, RefGridRow, RefGridCol,<br />

|RefGridColValues|, WidthRef, HeightRef)<br />

With this rectification map, the reference image can be transformed into the geometry of the test image.<br />

<strong>Note</strong> that the size of the mapped image depends on the number of grid cells and on the size of one grid<br />

cell, which must be defined by the parameter GridSpacing. Possibly, the size of the mapped reference<br />

image must be adapted to the size of the test image.<br />

map_image (ImageRef, Map, ImageMapped)<br />

crop_part (ImageMapped, ImagePart, 0, 0, WidthTest, HeightTest)<br />

Finally, the test image can be subtracted from the mapped reference image.<br />

sub_image (ImagePart, ImageTest, ImageSub, 1, 128)<br />

Figure 93 shows the resulting difference image. In this case, missing parts appear dark while the smudges<br />

appear bright.<br />

The differences between the test image and the reference image can now be extracted easily from the<br />

difference image with the operator threshold. If the difference image is not needed, e.g., for visualization<br />

purposes, the differences can be derived directly from the test image and the reference image with<br />

the operator dyn_threshold.<br />

Figure 94 shows the differences in a cut-out of the reference image (figure 94a) and of the test image (figure<br />

94b). The markers near the left border of figure 94b indicate the vertical position of the components<br />

that were used for the determination of the corresponding points. Vertical shifts of the components with<br />

respect to the reference image are indicated by a vertical line of the respective length that is attached<br />

to the respective marker. All other differences that could be detected between the test image and the<br />

reference image are encircled.<br />

2 In this case, the reference image is mapped into the geometry of the test image to facilitate the marking of the differences in<br />

the test image. Obviously, the rectification grid can also be defined such that the test image is mapped into the geometry of the<br />

reference image.<br />

Rectification


134 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

a) b)<br />

Figure 93: Difference image: a) The entire image overlaid with a rectangle that indicates the position of<br />

the cut-out. b) A cut-out.


a) b)<br />

9.4 Using Self-Defined Rectification Grids 135<br />

Figure 94: Cut-out of the reference and the checked test image with the differences marked in the test<br />

image: a) Reference image; b) checked test image.<br />

Rectification


136 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

Appendix<br />

A The <strong>HALCON</strong> Calibration Plate<br />

Figure 95a shows a <strong>HALCON</strong> calibration plate. <strong>Note</strong> that it has an asymmetric pattern in the upper left<br />

corner. This pattern ensures that the pose of the calibration plate can be determined uniquely.<br />

Old calibration plates do not have this pattern (see figure 95b). This may lead to problems if, e.g., a<br />

stereo camera or hand-eye system must be calibrated because the poses must be determined uniquely<br />

for this. To overcome this problem, you can make an asymmetric calibration plate out of your old<br />

calibration plate by marking one corner. Pay attention that the asymmetric pattern is not too close to the<br />

circular calibration marks because otherwise it could have an influence on the geometric accuracy of the<br />

calibration result.<br />

(a) (b)<br />

Figure 95: (a) The <strong>HALCON</strong> calibration plate with the asymmetric pattern in the upper left corner; (b) an<br />

old calibration plate that does not have the asymmetric pattern.<br />

There are two different types of calibration plate description files, which typically lie in the subdirectory<br />

calib of the folder where you installed <strong>HALCON</strong>: The standard description files for calibration plates<br />

that have the asymmetric pattern and the old description files for calibration plates without the asymmetric<br />

pattern. The old description files are indicated with the suffix old (orientation-less description).<br />

The behavior of the operator find_marks_and_pose depends on the combination of the used calibration<br />

plate and the specified calibration plate description file:<br />

Calibration plate Description file Behavior of find_marks_and_pose<br />

asymmetric asymmetric The pose will be determined uniquely.<br />

asymmetric old The pose will be determined such that the x-axis<br />

points to the right and the y-axis points downwards.<br />

old asymmetric The operator find_marks_and_pose returns an error<br />

because it cannot find the asymmetric pattern.<br />

old old The pose will be determined such that the x-axis<br />

points to the right and the y-axis points downwards.


B HDevelop Procedures Used in this <strong>Application</strong> <strong>Note</strong> 137<br />

B HDevelop Procedures Used in this <strong>Application</strong> <strong>Note</strong><br />

B.1 gen_hom_mat3d_from_three_points<br />

procedure gen_hom_mat3d_from_three_points (: : Origin, PointOnXAxis,<br />

PointInXYPlane: HomMat3d)<br />

XAxis := [PointOnXAxis[0]-Origin[0],PointOnXAxis[1]-Origin[1],<br />

PointOnXAxis[2]-Origin[2]]<br />

XAxisNorm := XAxis/sqrt(sum(XAxis*XAxis))<br />

VectorInXYPlane := [PointInXYPlane[0]-Origin[0],<br />

PointInXYPlane[1]-Origin[1],<br />

PointInXYPlane[2]-Origin[2]]<br />

cross_product (XAxisNorm, VectorInXYPlane, ZAxis)<br />

ZAxisNorm := ZAxis/sqrt(sum(ZAxis*ZAxis))<br />

cross_product (ZAxisNorm, XAxisNorm, YAxisNorm)<br />

HomMat3d_WCS_to_RectCCS := [XAxisNorm[0],YAxisNorm[0],ZAxisNorm[0],<br />

Origin[0],XAxisNorm[1],YAxisNorm[1],<br />

ZAxisNorm[1],Origin[1],XAxisNorm[2],<br />

YAxisNorm[2],ZAxisNorm[2],Origin[2]]<br />

hom_mat3d_invert (HomMat3d_WCS_to_RectCCS, HomMat3d)<br />

return ()<br />

end<br />

This procedure uses the procedure<br />

procedure cross_product (: : V1, V2: CrossProduct)<br />

CrossProduct := [V1[1]*V2[2]-V1[2]*V2[1],V1[2]*V2[0]-V1[0]*V2[2],<br />

V1[0]*V2[1]-V1[1]*V2[0]]<br />

return ()<br />

end<br />

Procedures


138 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

B.2 parameters_image_to_world_plane_centered<br />

procedure parameters_image_to_world_plane_centered (: : CamParam, Pose,<br />

CenterRow, CenterCol,<br />

WidthMappedImage,<br />

HeightMappedImage:<br />

ScaleForCenteredImage,<br />

PoseForCenteredImage)<br />

* Determine the scale for the mapping<br />

* (here, the scale is determined such that in the<br />

* surroundings of the given point the image scale of the<br />

* mapped image is similar to the image scale of the original image)<br />

Dist_ICS := 1<br />

image_points_to_world_plane (CamParam, Pose, CenterRow, CenterCol, 1,<br />

CenterX, CenterY)<br />

image_points_to_world_plane (CamParam, Pose, CenterRow+Dist_ICS,<br />

CenterCol, 1, BelowCenterX, BelowCenterY)<br />

image_points_to_world_plane (CamParam, Pose, CenterRow,<br />

CenterCol+Dist_ICS, 1, RightOfCenterX,<br />

RightOfCenterY)<br />

distance_pp (CenterY, CenterX, BelowCenterY, BelowCenterX,<br />

Dist_WCS_Vertical)<br />

distance_pp (CenterY, CenterX, RightOfCenterY, RightOfCenterX,<br />

Dist_WCS_Horizontal)<br />

ScaleVertical := Dist_WCS_Vertical/Dist_ICS<br />

ScaleHorizontal := Dist_WCS_Horizontal/Dist_ICS<br />

ScaleForCenteredImage := (ScaleVertical+ScaleHorizontal)/2.0<br />

* Determine the parameters for set_origin_pose such<br />

* that the point given via get_mbutton will be in the center of the<br />

* mapped image<br />

DX := CenterX-ScaleForCenteredImage*WidthMappedImage/2.0<br />

DY := CenterY-ScaleForCenteredImage*HeightMappedImage/2.0<br />

DZ := 0<br />

set_origin_pose (Pose, DX, DY, DZ, PoseForCenteredImage)<br />

return ()<br />

end


B.3 parameters_image_to_world_plane_entire<br />

B.3 parameters_image_to_world_plane_entire 139<br />

procedure parameters_image_to_world_plane_entire (Image: : CamParam, Pose,<br />

WidthMappedImage,<br />

HeightMappedImage:<br />

ScaleForEntireImage,<br />

PoseForEntireImage)<br />

* Transform the image border into the WCS (scale = 1)<br />

full_domain (Image, ImageFull)<br />

get_domain (ImageFull, Domain)<br />

gen_contour_region_xld (Domain, ImageBorder, ’border’)<br />

contour_to_world_plane_xld (ImageBorder, ImageBorderWCS, CamParam,<br />

Pose, 1)<br />

smallest_rectangle1_xld (ImageBorderWCS, MinY, MinX, MaxY, MaxX)<br />

* Determine the scale of the mapping<br />

ExtentX := MaxX-MinX<br />

ExtentY := MaxY-MinY<br />

ScaleX := ExtentX/WidthMappedImage<br />

ScaleY := ExtentY/HeightMappedImage<br />

ScaleForEntireImage := max([ScaleX,ScaleY])<br />

* Shift the pose by the minimum X and Y coordinates<br />

set_origin_pose (Pose, MinX, MinY, 0, PoseForEntireImage)<br />

return ()<br />

end<br />

Procedures


140 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

B.4 tilt_correction<br />

procedure tilt_correction (DistanceImage, RegionDefiningReferencePlane:<br />

DistanceImageCorrected: : )<br />

* Reduce the given region, which defines the reference plane<br />

* to the domain of the distance image<br />

get_domain (DistanceImage, Domain)<br />

intersection (RegionDefiningReferencePlane, Domain,<br />

RegionDefiningReferencePlane)<br />

* Determine the parameters of the reference plane<br />

moments_gray_plane (RegionDefiningReferencePlane, DistanceImage, MRow,<br />

MCol, Alpha, Beta, Mean)<br />

* Generate a distance image of the reference plane<br />

get_image_pointer1 (DistanceImage, _, Type, Width, Height)<br />

area_center (RegionDefiningReferencePlane, _, Row, Column)<br />

gen_image_surface_first_order (ReferencePlaneDistance, Type, Alpha,<br />

Beta, Mean, Row, Column, Width, Height)<br />

* Subtract the distance image of the reference plane<br />

* from the distance image of the object<br />

sub_image (DistanceImage, ReferencePlaneDistance,<br />

DistanceImageWithoutTilt, 1, 0)<br />

* Determine the scale factor for the reduction of the distance values<br />

CosGamma := 1.0/sqrt(Alpha*Alpha+Beta*Beta+1)<br />

* Reduce the distance values<br />

scale_image (DistanceImageWithoutTilt, DistanceImageCorrected,<br />

CosGamma, 0)<br />

return ()<br />

end<br />

B.5 visualize_results_of_find_marks_and_pose<br />

procedure visualize_results_of_find_marks_and_pose (Image: : WindowHandle,<br />

RCoord, CCoord, Pose,<br />

CamPar, CalTabFile: )<br />

dev_set_window (WindowHandle)<br />

dev_display (Image)<br />

dev_set_color (’yellow’)<br />

gen_cross_contour_xld (Cross, RCoord, CCoord, 6, 0)<br />

dev_display (Cross)<br />

display_calplate_coordinate_system (CalTabFile, Pose, CamPar,<br />

WindowHandle)<br />

return ()<br />

end


B.6 display_calplate_coordinate_system<br />

B.6 display_calplate_coordinate_system 141<br />

procedure display_calplate_coordinate_system (: : CalTabFile, Pose, CamPar,<br />

WindowHandle: )<br />

caltab_points (CalTabFile, X, Y, Z)<br />

* arrow should point to farthest marks<br />

ArrowLength := abs(X[0])<br />

display_3d_coordinate_system (Pose, CamPar, ArrowLength, WindowHandle,<br />

’blue’)<br />

return ()<br />

end<br />

B.7 display_3d_coordinate_system<br />

procedure display_3d_coordinate_system (: : Pose, CamPar, ArrowLength,<br />

WindowHandle, Color: )<br />

pose_to_hom_mat3d (Pose, HomMat3D)<br />

* store coordinates of the arrows in tuples<br />

* sequence: origin, x-axis, y-axis, z-axis<br />

ArrowsXCoords := [0,ArrowLength,0,0]<br />

ArrowsYCoords := [0,0,ArrowLength,0]<br />

ArrowsZCoords := [0,0,0,ArrowLength]<br />

* transform arrow points into camera coordinates<br />

affine_trans_point_3d (HomMat3D, ArrowsXCoords, ArrowsYCoords,<br />

ArrowsZCoords, ArrowsXCoords_cam,<br />

ArrowsYCoords_cam, ArrowsZCoords_cam)<br />

* get the image coordinates<br />

project_3d_point (ArrowsXCoords_cam, ArrowsYCoords_cam,<br />

ArrowsZCoords_cam, CamPar, ArrowsRows, ArrowsCols)<br />

* display the coordinate system<br />

dev_set_color (Color)<br />

gen_contour_polygon_xld (XAxis, [ArrowsRows[0], ArrowsRows[1]],<br />

[ArrowsCols[0], ArrowsCols[1]])<br />

dev_display (XAxis)<br />

set_tposition (WindowHandle, ArrowsRows[1], ArrowsCols[1])<br />

write_string (WindowHandle, ’x’)<br />

gen_contour_polygon_xld (YAxis, [ArrowsRows[0], ArrowsRows[2]],<br />

[ArrowsCols[0], ArrowsCols[2]])<br />

dev_display (YAxis)<br />

set_tposition (WindowHandle, ArrowsRows[2], ArrowsCols[2])<br />

write_string (WindowHandle, ’y’)<br />

gen_contour_polygon_xld (ZAxis, [ArrowsRows[0], ArrowsRows[3]],<br />

[ArrowsCols[0], ArrowsCols[3]])<br />

dev_display (ZAxis)<br />

set_tposition (WindowHandle, ArrowsRows[3], ArrowsCols[3])<br />

write_string (WindowHandle, ’z’)<br />

return ()<br />

end<br />

Procedures


142 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

B.8 select_values_for_ith_image<br />

procedure select_values_for_ith_image (: : NRow, NCol, NX, NY, NZ,<br />

NFinalPose, MRelPoses, i: Rows, Cols,<br />

X, Y, Z, CalplatePose, RobotPose)<br />

Rows := NRow[i*49:i*49+48]<br />

Cols := NCol[i*49:i*49+48]<br />

X := NX[i*49:i*49+48]<br />

Y := NY[i*49:i*49+48]<br />

Z := NZ[i*49:i*49+48]<br />

CalplatePose := NFinalPose[i*7:i*7+6]<br />

RobotPose := MRelPoses[i*7:i*7+6]<br />

return ()<br />

end<br />

B.9 calc_base_start_pose_movingcam<br />

procedure calc_base_start_pose_movingcam (: : CalplatePose, CamStartPose,<br />

RobotPoseInverse: BaseStartPose)<br />

* BaseStartPose = base_H_calplate = base_H_tool * tool_H_cam * cam_H_calplate<br />

pose_to_hom_mat3d (CamStartPose, cam_H_tool)<br />

hom_mat3d_invert (cam_H_tool, tool_H_cam)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_invert (tool_H_base, base_H_tool)<br />

pose_to_hom_mat3d (CalplatePose, cam_H_calplate)<br />

hom_mat3d_compose (tool_H_cam, cam_H_calplate, tool_H_calplate)<br />

hom_mat3d_compose (base_H_tool, tool_H_calplate, base_H_calplate)<br />

hom_mat3d_to_pose (base_H_calplate, BaseStartPose)<br />

return ()<br />

end<br />

B.10 calc_cam_start_pose_movingcam<br />

procedure calc_cam_start_pose_movingcam (: : CalplatePose, BaseStartPose,<br />

RobotPoseInverse: CamStartPose)<br />

* CamStartPose = cam_H_tool = cam_H_calplate * calplate_H_base * base_H_tool<br />

pose_to_hom_mat3d (BaseStartPose, base_H_calplate)<br />

hom_mat3d_invert (base_H_calplate, calplate_H_base)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_invert (tool_H_base, base_H_tool)<br />

pose_to_hom_mat3d (CalplatePose, cam_H_calplate)<br />

hom_mat3d_compose (cam_H_calplate, calplate_H_base, cam_H_base)<br />

hom_mat3d_compose (cam_H_base, base_H_tool, cam_H_tool)<br />

hom_mat3d_to_pose (cam_H_tool, CamStartPose)<br />

return ()<br />

end


B.11 calc_calplate_pose_movingcam<br />

B.11 calc_calplate_pose_movingcam 143<br />

procedure calc_calplate_pose_movingcam (: : BaseFinalPose, CamFinalPose,<br />

RobotPoseInverse: CalplatePose)<br />

* CalplatePose = cam_H_calplate = cam_H_tool * tool_H_base * base_H_calplate<br />

pose_to_hom_mat3d (BaseFinalPose, base_H_calplate)<br />

pose_to_hom_mat3d (CamFinalPose, cam_H_tool)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_compose (cam_H_tool, tool_H_base, cam_H_base)<br />

hom_mat3d_compose (cam_H_base, base_H_calplate, cam_H_calplate)<br />

hom_mat3d_to_pose (cam_H_calplate, CalplatePose)<br />

return ()<br />

end<br />

B.12 calc_base_start_pose_stationarycam<br />

procedure calc_base_start_pose_movingcam (: : CalplatePose, CamStartPose,<br />

RobotPoseInverse: BaseStartPose)<br />

* BaseStartPose = base_H_calplate = base_H_tool * tool_H_cam * cam_H_calplate<br />

pose_to_hom_mat3d (CamStartPose, cam_H_tool)<br />

hom_mat3d_invert (cam_H_tool, tool_H_cam)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_invert (tool_H_base, base_H_tool)<br />

pose_to_hom_mat3d (CalplatePose, cam_H_calplate)<br />

hom_mat3d_compose (tool_H_cam, cam_H_calplate, tool_H_calplate)<br />

hom_mat3d_compose (base_H_tool, tool_H_calplate, base_H_calplate)<br />

hom_mat3d_to_pose (base_H_calplate, BaseStartPose)<br />

return ()<br />

end<br />

B.13 calc_cam_start_pose_stationarycam<br />

procedure calc_cam_start_pose_movingcam (: : CalplatePose, BaseStartPose,<br />

RobotPoseInverse: CamStartPose)<br />

* CamStartPose = cam_H_tool = cam_H_calplate * calplate_H_base * base_H_tool<br />

pose_to_hom_mat3d (BaseStartPose, base_H_calplate)<br />

hom_mat3d_invert (base_H_calplate, calplate_H_base)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_invert (tool_H_base, base_H_tool)<br />

pose_to_hom_mat3d (CalplatePose, cam_H_calplate)<br />

hom_mat3d_compose (cam_H_calplate, calplate_H_base, cam_H_base)<br />

hom_mat3d_compose (cam_H_base, base_H_tool, cam_H_tool)<br />

hom_mat3d_to_pose (cam_H_tool, CamStartPose)<br />

return ()<br />

end<br />

Procedures


144 <strong>Application</strong> <strong>Note</strong> on 3D Machine Vision<br />

B.14 calc_calplate_pose_stationarycam<br />

procedure calc_calplate_pose_movingcam (: : BaseFinalPose, CamFinalPose,<br />

RobotPoseInverse: CalplatePose)<br />

* CalplatePose = cam_H_calplate = cam_H_tool * tool_H_base * base_H_calplate<br />

pose_to_hom_mat3d (BaseFinalPose, base_H_calplate)<br />

pose_to_hom_mat3d (CamFinalPose, cam_H_tool)<br />

pose_to_hom_mat3d (RobotPoseInverse, tool_H_base)<br />

hom_mat3d_compose (cam_H_tool, tool_H_base, cam_H_base)<br />

hom_mat3d_compose (cam_H_base, base_H_calplate, cam_H_calplate)<br />

hom_mat3d_to_pose (cam_H_calplate, CalplatePose)<br />

return ()<br />

end<br />

B.15 define_reference_coord_system<br />

procedure define_reference_coord_system (: : ImageName, CamParam,<br />

CalplateFile, WindowHandle:<br />

PoseCamRef)<br />

read_image (RefImage, ImageName)<br />

dev_display (RefImage)<br />

caltab_points (CalplateFile, X, Y, Z)<br />

* parameter settings for find_caltab and find_marks_and_pose<br />

SizeGauss := 3<br />

MarkThresh := 100<br />

MinDiamMarks := 5<br />

StartThresh := 128<br />

DeltaThresh := 3<br />

MinThresh := 18<br />

Alpha := 0.5<br />

MinContLength := 15<br />

MaxDiamMarks := 100<br />

find_caltab (RefImage, Caltab, CalplateFile, SizeGauss, MarkThresh,<br />

MinDiamMarks)<br />

find_marks_and_pose (RefImage, Caltab, CalplateFile, CamParam,<br />

StartThresh, DeltaThresh, MinThresh, Alpha,<br />

MinContLength, MaxDiamMarks, RCoord, CCoord,<br />

StartPose)<br />

camera_calibration (X, Y, Z, RCoord, CCoord, CamParam, StartPose,<br />

’pose’, CamParam, PoseCamRef, Errors)<br />

display_3d_coordinate_system (PoseCamRef, CamParam, 0.01, WindowHandle,<br />

’cyan’)<br />

return ()<br />

end

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!