ZMap

ZMaps are another representation for 3D data. They are generated by capturing the orthogonal projection of a point cloud or a mesh onto an arbitrary 3D reference plane.

  • They contain an image in which each pixel value represents a positive distance from the reference plane.

  • They are grayscale images like depth maps but represent metric and corrected 3D points.

  • They are convenient representations for measurement and matching.

  • They are compatible with most 2D processing functions.

../../../_images/zmap_01.webp

An EDepthMap .NET Python and the corresponding EZMap .NET Python. The ZMap is captured from a different reference plane.

A ZMap also contains the following information:

  • The transformation from the World coordinates to the ZMap coordinates.

  • The size of a pixel, called the resolution.

Hint

Generating a ZMap

The EPointCloudToZMapConverter .NET Python class implements the conversion from a point cloud to a ZMap (EMeshToZMapConverter .NET Python converts a mesh to a ZMap). With all parameters at default value, the EPointCloudToZMapConverter::Convert .NET Python method automatically chooses the projection plane, the orientation, the map size and the resolution.

Several methods are available to further control the conversion:

The methods EPointCloudToZMapConverter::SetReferencePlane .NET Python, EPointCloudToZMapConverter::SetOrientationVector .NET Python and EPointCloudToZMapConverter::SetOrigin .NET Python are used to set up the transformation between the world space and the ZMap space. This transformation is rigid (distances are kept).

Alternatively, it is possible to directly set that transformation with the method EPointCloudToZMapConverter::SetWorldToZMapTransform .NET Python using a rigid matrix as parameter. In that case, the reference plane, the orientation vector and the origin parameters are ignored.

../../../_images/zmap_02.webp

The projection of a point cloud on a ZMap, showing three coordinate systems: the world space, the ZMap space and the pixel space.

The EPointCloudToZMapConverter::Convert .NET Python method performs the effective projection of a point cloud (EPointCloud .NET Python) or a 3D object (EMesh .NET Python) to the 8, 16 or 32 bits ZMap.

When generating a ZMap from a point cloud, only individual points are projected on the ZMap. Depending on the point cloud density and the ZMap resolution, some regions of the ZMap may remain “undefined”. To get around this problem, adjust the resolution of the ZMap (EPointCloudToZMapConverter::SetMapXYResolution .NET Python method) to remove “holes” on the ZMap.

By default, the point cloud to ZMap converter performs a filling algorithm. This process tries to replace undefined pixels with locally interpolated values.

High-resolution ZMap with the pixel scale exceeding the point cloud density. High-resolution ZMap with the pixel scale exceeding the point cloud density.
High-resolution ZMap generated using the same parameters, with filling enabled. High-resolution ZMap generated using the same parameters, with filling enabled.
A reduced ZMap scale/resolution, without filling. A reduced ZMap scale/resolution, without filling.

As a mesh defines a surface, its triangles are projected onto the ZMap plane. Thus, the generated image shows better continuity and less undefined pixels. However, the generation of a ZMap from an EMesh .NET Python is slower than from an EPointCloud .NET Python.

Creating a Point Cloud from a ZMap

To generate a point cloud from a ZMap, use the EZMapToPointCloudConverter .NET Python class.

The EZMapToPointCloudConverter::Convert .NET Pythonmethod takes:

  • A ZMap source

  • A EPointCloud .NET Python destination.

  • 4 optional parameters:

    • An ERegion .NET Python that defines the domain of the ZMap to convert. By default, uses all the defined pixels of the ZMap generate the point cloud.

    • A parameter to select the world space (by default) or the ZMap space to store the resulting positions in the point cloud.

    • Whether to compute the normals of the points of the point cloud during the conversion. This is not done by default.

    • A black and white or color image (with the same size as the ZMap) that is used to generate the intensity or color attribute of the point cloud.

Managing Coordinates

Coordinate Systems on a ZMap

A ZMap has multiple coordinate systems:

  • The world space system is the original, metric space from which the ZMap has been generated. Point clouds and meshes are expressed in the world coordinate system.

  • The ZMap space is defined by a rigid transformation of the world space. The basis linked to this transformation is attached to the lower left corner of the ZMap.

  • The image space is the system attached to the image representation of the ZMap. Its origin is the upper left corner of the ZMap and its unit length is one pixel along the X and Y axis.

The transformations between:

  • The image space and the ZMap space include a scale factor.

  • The ZMap space and the world space are solid transformations.

../../../_images/coordinates_1.webp

Transformation from the ZMap coordinate system to the image coordinate system, and vice versa.

Note

To perform 2D processing in metric units on a ZMap, for example measurements with EasyGauge, you can retrieve an EFrame .NET Python converting image coordinates to ZMap coordinates using the method EZMap::GetZMapPositionFrame .NET Python.

EZMap

The EZMap .NET Python object exposes a set of methods to convert coordinates between world, ZMap and image spaces:

An overload of EZMap::ImageToWorld .NET Python computes the world point corresponding to a 2D image point without specifying its \(z\) coordinate.

  • The \(z\) coordinate is taken as the median or mean of the \(z\) coordinates of the pixels in the vicinity of the 2D image point. This is useful to align an object based on features found on the ZMap with 2D operators.

  • The \(z\) coordinate is computed on the vicinity because the feature itself may not have a defined \(z\) coordinate, for example if it is the center of a hole.

The functions that access the pixel values are:

  • EZMap::GetWorldPositionFromPixelPosition .NET Python is a method transforming the actual pixel value at integer position (u, v) to the original world space. This method queries the ZMap internal representation to get the pixel value w and transform the pixel space (u, v, w) coordinates to a world space position.

  • EZMap16::GetPixelPositionFromWorldPosition .NET Python is a method to get a pixel value from a world position. The world position is projected on the ZMap and the pixel value is returned. If the world position is outside the ZMap domain, the method returns FALSE.

  • EZMap::GetWorldPositionFromMapPosition .NET Python is a method to get a 3D world position corresponding to a ZMap 2D coordinate. The world position is in the original point cloud space. If the 2D coordinate is undefined, an exception is thrown.

Leveling a ZMap

Sometimes, the reference plane of the ZMap is not set correctly.

To solve this problem, use the method EZMapLeveler::Level .NET Python of the class EZMapLeveler .NET Python to reproject the ZMap on a new reference plane.

To specify the new reference plane, you can either:

  • Give an ERegion of points contained in the plane to the method EZMapLeveler::Level .NET Python. The plane might be shifted so that the leveled ZMap contains all the points of the original one.

../../../_images/zmap_leveler_2.webp

An ERegion (composed of 2 ERectangle regions) highlighting the new reference plane

  • Give the normal of the new plane to the ZMap (with argument projectionDirection). The ZMap plane is computed from the normal and shifted so that the new ZMap contains all the points of the old one.

Hint

A typical way to find the projectionDirection is to use an EPlaneFinder .NET Python to find the biggest plane in the ZMap.

Note

See code snippet: “Performing ZMap Leveling”.

  • To set the angle of the X and Y axes of the leveled ZMap, use the argument rotationAngle.

../../../_images/zmap_leveler_1.webp

Illustration of EZMapLeveler .NET Python showing the default \(0°\) rotation and the correct \(-23°\) rotation.

Size and XYZ Resolution Settings

There are several options to handle the size and X, Y or Z resolution of the leveled ZMap:

  • EPreservationMode .NET Python (through methods EZMapLeveler::GetPreservationModes .NET Python and EZMapLeveler::SetPreservationModes .NET Python) determines whether the XY resolution, size and/or Z resolution of the input ZMap are preserved.

    • When the XY resolution is preserved, the size of the leveled ZMap is adjusted.

    • When the size of the ZMap is preserved, the resolution is adjusted.

    Note

    Note that this may introduce holes in the leveled ZMap.

    • When both are preserved, the visible contents of the ZMap are adjusted, meaning that some undefined pixels may appear on the edges of the ZMap or the extremities of the object may be cropped.

    • When the Z resolution is preserved, some data may be impossible to represent if the Z range of the leveled ZMap is bigger than the one of the source ZMap (see next point). Otherwise, the Z resolution is recomputed to use the whole range of the ZMap.

    • To avoid undesired side-effects, only the XY resolution is preserved by default.

  • Use EZMapLeveler::SetPreserveZResolutionFailureHandler .NET Python to choose how to handle data falling outside of the representable range of the ZMap when EPreservationMode .NET Python is set to EPreservationMode_ZResolution .NET Python. The data may be cropped (the corresponding pixel is undefined), Saturated (the corresponding pixel is white) or an exception is thrown when the problem occurs.

3D Position Settings

  • By default, the leveling does not change the underlying 3D data of the ZMap. The goal is to use the leveling to ease some 2D processing while maintaining the link with the real-world positions of the data.

  • Alternatively, you can use the method EZMapLeveler::SetPreserve3DPosition .NET Python to alter that behavior and modify the 3D data of the leveled ZMap. In this mode, the z = 0 plane is either: