# Useful code snippets for CVB 3D image processing

**URL:** <https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929>\
**Category:** .Net API\
**Tags:** transformation, net, calibration, intrinsic, extrinsic\
**Created:** [October 24, 2019, 3:48pm UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929 "2019-10-24T15:48:13Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Moli](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/moli/32/553_2.png) [@Moli](https://forum.commonvisionblox.com/u/Moli)\
**Post date:** [October 24, 2019, 3:48pm UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/1 "2019-10-24T15:48:13Z")

</div>

Intrinsically & extrinsically calibrate point clouds using a laser triangulation sensor

The following describes an example workflow in `CVB.Net` to:

- reconstruct an intrinsically calibrated point cloud from a range map and an intrinsic calibration file
- extrinsically calibrate a system using an AQS12 calibration target
- create a rectified range map from the calibrated point cloud

```auto
using Stemmer.Cvb;
using Stemmer.Cvb.Foundation;

namespace cvbNet_ExtrinsicCalibration_Console
{

  class Program
  {
    static void Main(string[] args)
    {
      // load range map
      var rangemap = Image.FromFile(@"%CVB%\Tutorial\Metric\Images\RangeMap_CalibrationPattern.tif");

      // load intrinsic calibration (e.g. from an AT compact sensor)
      var calibrator = Calibrator3D.FromFile(Environment.ExpandEnvironmentVariables(@"%cvb%\Tutorial\Metric\Images\Test.xml"));

      // reconstruct point cloud without extrinsic calibration
      PointCloud pointCloud = calibrator.CreatePointCloud(rangemap, PointCloudFlags.Double);
      pointCloud.Save(Environment.ExpandEnvironmentVariables(@"%cvb%\Tutorial\Metric\Images\PointCloud.ply"));

      // set pattern points
      AQS12Piece aqs12 = new AQS12Piece();
      aqs12.TopBasePlaneDistance = 60;
      aqs12.ReferencePoints[0] = new Point3Dd(0, 40, 60);
      aqs12.ReferencePoints[1] = new Point3Dd(10, 53, 60);
      aqs12.ReferencePoints[2] = new Point3Dd(10, 96, 60);
      aqs12.ReferencePoints[3] = new Point3Dd(0, 110, 60);
      aqs12.ReferencePoints[4] = new Point3Dd(-10, 96, 60);
      aqs12.ReferencePoints[5] = new Point3Dd(-10, 53, 60);
      aqs12.ReferencePoints[6] = new Point3Dd(0, 0, 30);
      aqs12.ReferencePoints[7] = new Point3Dd(30, 40, 30);
      aqs12.ReferencePoints[8] = new Point3Dd(30, 110, 30);
      aqs12.ReferencePoints[9] = new Point3Dd(0, 150, 30);
      aqs12.ReferencePoints[10] = new Point3Dd(-30, 110, 30);
      aqs12.ReferencePoints[11] = new Point3Dd(-30, 40, 30);
           
      // perform calibration
      Point3Dd[] residuals = new Point3Dd[12];
      calibrator.ExtrinsicMatrix = Metric.ExtrinsicTransformationFromPiece(rangemap.Planes[0], aqs12, calibrator, out residuals);
      calibrator.Save(Environment.ExpandEnvironmentVariables(@"%cvb%\Tutorial\Metric\Images\TestOut.json"));
      
      // reconstruct point cloud with extrinsic calibration
      PointCloud calibratedPointCloud = calibrator.CreatePointCloud(rangemap, PointCloudFlags.Double);
      calibratedPointCloud.Save(Environment.ExpandEnvironmentVariables(@"%cvb%\Tutorial\Metric\Images\calibratedPointCloud.ply"));
      
      //create rectified range map 
      //(parameters for rectification can be set differently)
      var boundingBox = calibratedPointCloud.CalculateBoundingBox();
      ValueRange<double> xRange = new ValueRange<double>(double.MinValue, double.MaxValue);
      ValueRange<double> yRange = new ValueRange<double>(double.MinValue, double.MaxValue);
      xRange.Min = boundingBox.X.Min;
      xRange.Max = boundingBox.X.Max;
      yRange.Min = boundingBox.Y.Min;
      yRange.Max = boundingBox.Y.Max;
      int targetWidth = rangemap.Width;
      int targetHeight = rangemap.Height;
      double bgValue = boundingBox.Z.Min - 10;
      var rectifiedRangemap = calibratedPointCloud.ToRangeMap(xRange, yRange, targetWidth, targetHeight, bgValue);
      rectifiedRangemap.Save(Environment.ExpandEnvironmentVariables(@"%cvb%\Tutorial\Metric\Images\rectifiedRangemap.tiff"));
    }
  }
}
```

---

<div class="post-metadata">

**Author:** ![Moli](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/moli/32/553_2.png) [@Moli](https://forum.commonvisionblox.com/u/Moli)\
**Post date:** [October 29, 2019, 4:14pm UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/2 "2019-10-29T16:14:31Z")

</div>

Aligning a point cloud using a plane fit

In many cases it is necessary to transform 3D point clouds in a post processing. It is e.g. much easier to detect surface defects on flat objects, when the surface is aligned to the xy-plane of the coordinate system. Espacially when working with rectified range maps (2.5D images) it gets handy to do these kind of alignments before analyzing.

The following example demonstrates how to fit a plane into a subset of points of a point cloud and how to transform the point cloud with the resulting normal vector of the plane. The result will be a point cloud where the z-axis points into the same direction as the normal vector of the plane/surface.

First, we load an example point cloud:

```auto
var pc = PointCloud.FromFile(@"D:\MyPointCloud.ply");

```

For verification we can display it in an activeX control (Common Vision Blox 3D Viewer):

```auto
axCVCore3DViewer1.AddPointCloudVariable(pc.Handle.ToInt64(), 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0);

```

 ![PointCloud](https://canada1.discourse-cdn.com/flex027/uploads/commonvisionblox/original/1X/e34a7509b516132f22c343f654d1e8388b5671ba.jpeg)

The sample point cloud is an AQS12 calibration target, already aligned to its base plane. In this example workflow we will fit a plane into one of the side planes.

For the plane fit we define a certain 3D region of interest (cuboid) within the point cloud:

```auto
var range = new ValueRange<double>(double.MinValue, double.MaxValue);
      var planeCuboid = new Cuboid(range, range, range);
      planeCuboid.X.Min = 700;
      planeCuboid.X.Max = 860;
      planeCuboid.Y.Min = 1035;
      planeCuboid.Y.Max = 1540;
      planeCuboid.Z.Min = 1080;
      planeCuboid.Z.Max = 1240;
      var plane = pc.FitPlane(planeCuboid);

```

Again, for verification, we can display the points of the cuboid used for the plane fit in the 3D viewer.

```auto
axCVCore3DViewer1.AddPointCloudSolid(pc.Crop(planeCuboid).Handle.ToInt64(), 0xFFFFFF, 1,1,1,2);

```

 ![PointCloud_Cuboid](https://canada1.discourse-cdn.com/flex027/uploads/commonvisionblox/original/1X/4a9f85ea57f5cece5de9930153f65aec4e744d76.jpeg)

For the transformation of the point cloud we need to set up a rotation matrix first with the entries of the normal vector:

```auto
var roll = new Angle();
var pitch = new Angle();
var yaw = new Angle();

roll.Rad = Math.Atan(plane.Normal.Y/plane.Normal.Z);
pitch.Rad = Math.Atan(plane.Normal.X/plane.Normal.Z);
yaw.Rad = 0; // not necessary for an alignment into the xy-plane

var rotAngles = new RotationAngles3D(roll, pitch, yaw);
var rotMatrix = new Matrix3D(rotAngles);

```

Afterwards we can fill the transformation matrix with our calculated rotation matrix and a translation vector, that can be set to (0,0,0) in this case:

```auto
var translation = new Point3Dd(0, 0, 0);
var trafoMatrix = new AffineMatrix3D(rotMatrix, translation);

```

The transformation itself is done with the following method:

```auto
var pc_transformed = pc.Transform(trafoMatrix);

```

The transformed point cloud is now aligned to the fitted plane and can be visualized:

```auto
axCVCore3DViewer1.AddPointCloudVariable(pc_transformed.Handle.ToInt64(), 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1);
axCVCore3DViewer1.ResetCamera();

```

 ![PointCloud_Aligned](https://canada1.discourse-cdn.com/flex027/uploads/commonvisionblox/original/1X/24ff997b49f2b431f9374bab7833ba08aa17a928.jpeg)

This is how rectified range maps look like when being calculated from the original point cloud (left) and transformed point cloud (right):

 ![RectRangemaps](https://canada1.discourse-cdn.com/flex027/uploads/commonvisionblox/original/1X/266a44b48eb35a385cc906c37bce862d6c0b7a7f.jpeg)

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 1, 2022, 7:09am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/3 "2022-09-01T07:09:12Z")

</div>

Hi，help me, I’m trouble. About your tutorial , my vs2017 editor make error where ‘Metric’ does not contain the definition of ‘ExternalicTransformationFromPiece’. CVB version is 13.04.

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [September 6, 2022, 8:39am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/4 "2022-09-06T08:39:45Z")

</div>

Hi @wugx

Sorry for the late response du to the vacation season.  
In order to reproduce the error we need to know:

- which tutorial are you using?
- In which line the error happens?
- What is exactly the error?

A minimal executable code that only contains the required lines to reproduce the error is appreciated!

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 6, 2022, 8:57am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/5 "2022-09-06T08:57:02Z")

</div>

About this topic content, eg. picture,

 ![image](https://canada1.discourse-cdn.com/flex027/uploads/commonvisionblox/original/2X/3/3143c11aa367067e31b379f1bc3834e5f5a010ce.png)

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [September 6, 2022, 11:06am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/6 "2022-09-06T11:06:24Z")

</div>

Hi @wugx

The name of the function is changed to Metric.CalculateRigidBodyTransformationFromAqs12Piece(). For more details please refer to %cvb%Doc/Cvb.Net.chm, in Stemmer.Cvb.Foundation\>Metric Class

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 6, 2022, 1:29pm UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/7 "2022-09-06T13:29:16Z")

</div>

Thanks for your patience. But have a new question, about aqs12 calibration related function, Is valid that this function are applied in other calibrate target？what’s boundary condition that I can’t find this in the api doc？

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [September 6, 2022, 4:31pm UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/8 "2022-09-06T16:31:18Z")

</div>

Hi @wugx

The extrinsic calibration in CVB only supports aqs12 as calibration target.  
I do not know exactly what you mean with “Boundary condition”, but in one of the override function of Metric.CalculateRigidBodyTransformationFromAqs12Piece(), there is an argument “rect aoi” which is the region of interest.

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 6, 2022, 11:29pm UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/9 "2022-09-06T23:29:45Z")

</div>

Thank you. If my calibration target is of other styles, are there other existing classes or functions？ eg. the  
section

 ![image](https://canada1.discourse-cdn.com/flex027/uploads/commonvisionblox/original/2X/d/d35d2010f2e5cf68513e59fb1fb939a31828f4ee.png)  
Multi cylinder calibration target where parameter is (Center.x,Center.y,Radius) .

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [September 7, 2022, 5:24am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/10 "2022-09-07T05:24:11Z")

</div>

No, CVB does not support other calibration targets.

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 7, 2022, 5:40am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/11 "2022-09-07T05:40:52Z")

</div>

ok,thank you. it’s unreasonable.

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 7, 2022, 5:51am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/12 "2022-09-07T05:51:07Z")

</div>

But , Has’t support that we can independent develop the calibration function to caculate affine matixs by CVB. I can’t find the optimization solver for Multivariate linar equations.

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [September 7, 2022, 7:16am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/13 "2022-09-07T07:16:15Z")

</div>

We do not offer such a functionality in our SDK, we use of course optimizations method internally in CVB which are not offered in our SDK. If you plan to write your own calibration, you may find useful methods in Blob and edge modules. %cvb%Doc/blob.chm, %cvb%Doc/edge.chm.

3Dpoint, 3DMatrix and matrix multiplication and point cloud conversions can be found under the namespace Stemmer.Cvb.

---

<div class="post-metadata">

**Author:** ![wugx](https://avatars.discourse-cdn.com/v4/letter/w/9fc29f/32.png) [@wugx](https://forum.commonvisionblox.com/u/wugx)\
**Post date:** [September 7, 2022, 8:21am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/14 "2022-09-07T08:21:38Z")

</div>

Thank you for your kindness，Happy life.

---

<div class="post-metadata">

**Author:** ![MarSch](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/marsch/32/23_2.png) [@MarSch](https://forum.commonvisionblox.com/u/MarSch)\
**Post date:** [October 27, 2022, 10:07am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/15 "2022-10-27T10:07:04Z")

</div>

Hi, is this code still valid as of 10/2022? I seem to fail to find the Calibrator3D class actually. Thank you.

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [October 27, 2022, 11:50am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/16 "2022-10-27T11:50:12Z")

</div>

@MarSch

There were some changes and lots of developments in CVB 3D module since starting this thread, but the Calibrator3D class still exists. Please take a look at the CVB 14 online documentation:  
[https://help.commonvisionblox.com/NextGen/14.0/cvbnet/db/d65/class\_stemmer\_1\_1\_cvb\_1\_1\_calibrator3\_d.html](https://help.commonvisionblox.com/NextGen/14.0/cvbnet/db/d65/class_stemmer_1_1_cvb_1_1_calibrator3_d.html)

---

<div class="post-metadata">

**Author:** ![MarSch](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/marsch/32/23_2.png) [@MarSch](https://forum.commonvisionblox.com/u/MarSch)\
**Post date:** [October 28, 2022, 10:44am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/17 "2022-10-28T10:44:28Z")

</div>

Hi Mandana, thank you very much.

I see that this is a protected class: [https://help.commonvisionblox.com/NextGen/14.0/cvbnet/db/d65/class\_stemmer\_1\_1\_cvb\_1\_1\_calibrator3\_d.html#details](https://help.commonvisionblox.com/NextGen/14.0/cvbnet/db/d65/class_stemmer_1_1_cvb_1_1_calibrator3_d.html#details)

Is this intentional?

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [October 28, 2022, 11:28am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/18 "2022-10-28T11:28:02Z")

</div>

Hi @MarSch

Yes, it is intentional. This class is inherited by LaserPlaneCalibrator3D, MatrixCalibrator3D, and PinholeCameraCalibrator3D.

---

<div class="post-metadata">

**Author:** ![MarSch](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/marsch/32/23_2.png) [@MarSch](https://forum.commonvisionblox.com/u/MarSch)\
**Post date:** [November 3, 2022, 8:59am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/19 "2022-11-03T08:59:44Z")

</div>

Thank you. However I can’t get around the fact that regardless of what I do, I’m able to access any ImageManager subclasses in the Net-API, however PointCloud and Calibration3D are not accessible with CVB 14.

As far as I can see in the object browser, I could do it unmanaged, but I would prefer not to do this.

---

<div class="post-metadata">

**Author:** ![MandanaS](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/mandanas/32/1211_2.png) [@MandanaS](https://forum.commonvisionblox.com/u/MandanaS)\
**Post date:** [November 11, 2022, 7:43am UTC](https://forum.commonvisionblox.com/t/useful-code-snippets-for-cvb-3d-image-processing/929/20 "2022-11-11T07:43:27Z")

</div>

@MarSch I noticed that you sent a same request to our support mailing account. As soon as this matter gets clear for you in our support case, we will update this post accordingly.
