リモートコントローラの測定
このトピックでは、テレビリモートコントローラをサンプルオブジェクトとして扱う完全な3D処理ワークフローを紹介します。
レーザー三角測量取得セットアップ上のリモートコントローラ
2D画像上の3D処理および投影後のリモートコントローラ
提案されたプロセスは、以下の操作のシーケンスです。
1回のキャリブレーションプロセス:
| 1. | キャリブレーションオブジェクトを表す深度マップをロードします。 |
| 2. | キャリブレーションモデルの計算を実行します。 |
| 3. | キャリブレーションモデルを保存します。 |
各オブジェクトについて:
| 1. | オブジェクトの深度マップをロードします。 |
| 2. | キャリブレーションモデルを適用してワールドポイントクラウドを取得します。 |
| 3. | (オプション)ポイントクラウドをPCDファイルに保存します。 |
| 4. | 次のいずれかの方法で基準平面を検索します。 |
| □ | 平面を計算するために使用される遠隔深度マップ上の3つの点の選択。 |
| □ | 3DPlaneFitter関数の使用。 |
| 5. | 方向を定義するには2点を選択します。 |
| 6. | 参照平面と方向ベクトルを使用してZMapを構築します。 |
| 7. | (オプション)ZMapを画像として保存します。 |
| 8. | ZMapにクエリしてワールドスペース測定を取得します。 |
| 9. | 2D画像機能でZMapを処理します。 |
読み取りやすくするために、この例のコードスニペットでは、例外キャッチおよびエラーチェックは表示されません。
キャリブレーションプロセスは、深度マップから実世界、メトリック、座標系への正確な変換を見つけるためには必須です。
Open eVisionはオブジェクトに基づくキャリブレーションプロセスを特徴とします。既知のジオメトリの基準オブジェクトのスキャンがキャリブレーション計算に使用されます。
推奨されるキャリブレーションオブジェクトは、切頭錐体です。

二重ピラミッドおよびキャリブレーションオブジェクトのCADモデルはスキャンされました。
Euresys Coaxlink 3D LLEフレームグラバを使用すると、キャプチャされた画像は直接深度マップになります。深度マップは、レーザプロファイルの高さを表すピクセル値を有する8ビットまたは16ビットグレースケール画像です。
キャリブレーションオブジェクトとして使用される二重ピラミッドの深度マップ(グレースケール画像)
以下のコードスニペットは、ダブルピラミッドオブジェクトを表す深度マップをロードし、それを使用してキャリブレーションモデルを計算し、後で使用できるように結果を保存する方法を示しています。
// Load the depthmap used for the calibration process EDepthMap16 calibration_depthmap; calibration_depthmap.Load("calibration.tiff"); // Set the Z resolution from the number of bits for the fractional part, depends on the depth map acquisition calibration_depthmap.SetZResolution(1.f / (1<<5)); // Declare the object based calibration generator EObjectBasedCalibrationGenerator calibrator; // set the real world scale of the scanned object calibrator.SetCalibrationObjectType(EObjectBasedCalibrationType_DoublePyramid); calibrator.SetCalibrationObjectScale(10.f); // Declare an object based calibration model EObjectBasedCalibrationModel calibration_model; // Perform the calibration process (can take some time, like 10 seconds) calibration_model = calibrator.Compute(calibration_depthmap); // Check the calibration result if(calibration_model.IsInitialized()) { printf("Calibration succeeded with score: %g\n", calibration_model.GetCalibrationError()); // Save the model for later use ESerializer* serializer = ESerializer::CreateFileWriter("calibration.model"); calibration_model.Save(serializer); delete serializer; } else { printf("Calibration failed\n"); }
このセクションでは、ソースの深度マップからメトリック測定までの3Dワークフローを公開しています。
先に計算されたキャリブレーションモデルは、深度マップデータを実世界の3Dポイントクラウドに変換するために使用されます。
TVリモコンの深度マップ
(黒いピクセルは未定義の領域を表していますが、オブジェクトが歪んだりスケーリングされています。つまり、カメラでは見えない、またはレーザーで点灯したオブジェクトの部分です)
以下のコードスニペット:
| 10. | キャリブレーションモデルを読み込みます。 |
| 11. | 深度マップを3Dポイントクラウドに変換します。 |
| 12. | ポイントクラウドをPCDファイルに保存します。 |
// Read an abstract calibration model from file ECalibrationModel* calibration_model; ESerializer* serializer = ESerializer::CreateFileReader("calibration.model"); // must be desallocated later calibration_model = ECalibrationModel::Create(serializer); delete serializer; // Declare a depth map to point cloud converter EDepthMapToPointCloudConverter dm2pc; // attach a calibration model to the converter dm2pc.SetCalibrationModel(*calibration_model); // Generate the point cloud EPointCloud point_cloud; dm2pc.Convert(object_depthmap, point_cloud); printf("Point cloud size : %d\n", point_cloud.GetNumPoints()); // Save to point cloud to a PCD file point_cloud.SavePCD("point_cloud.pcd");
PCDファイルは、PCLフレームワーク(www.pointclouds.org)で使用される単純な3Dポイントコンテナです。このようなファイルは、Cloud Compare(www.cloudcompare.org)のような他のツールのPCLビューアにロードすることができます。
以下のスクリーンショットに示すように、ポイントクラウドのデータはワールド座標系にあり、キャリブレーションオブジェクト単位で表されます。距離と角度は正しいので、メトリック測定が可能です。しかし、ポイントクラウドでの処理は困難でコストがかかる場合があり、ZMap表現はメトリックワールド空間での2D処理を可能にする代替手段です。
結果のポイントクラウドは、クラウド比較アプリケーションで表示されます
結果として生じるPCLビューア内のポイントクラウドです。カラーランプは、リモコンの本体平面が軸と整列していないことを示します
測定および処理を実行するには、通常、データを参照フレームに変換することが必須です。リモートコントローラでは、キーをサポートするメインプレーンまで水平にし、リモートエッジに沿ってポイントを向ける必要があります。
深度マップが事前に登録されている場合(一貫した取得プロセスまたは基準マーカーの検出によって)、3つの選択された点(基準平面の一部として知られる点)から基準平面を構築することができます。
// Use 3 known points to build the reference plane E3DPoint p1(600.5, 450.5, object_depthmap.GetZValue(600, 450)); E3DPoint p2(1700.5, 470.5, object_depthmap.GetZValue(1700, 470)); E3DPoint p3(840.5, 2300.5, object_depthmap.GetZValue(840, 2300)); // convert these points from depth map space to world space, using the calibration model E3DPoint w1, w2, w3; w1 = calibration_model.Apply(p1); w2 = calibration_model.Apply(p2); w3 = calibration_model.Apply(p3); // build the world plane using 3 points E3DPlane reference_plane(w1, w2, w3);
元のオブジェクトの深度マップおよび基準平面の計算に使用された3点の位置
深度マップが登録されていない場合は、E3DPlaneFitterクラスを使用することもできます。この関数は、確率論的手法を用いてポイントクラウドから主平面を見つけることを試みます。これは、ユーザが定義した閾値公差を考慮して、平面上にあるポイントクラウドの部分集合を求めます。
距離公差はE3DPlaneFitterのパラメータであり、ポイントクラウドの平面のスケール、ノイズ、曲率に応じて調整する必要があります。
// Use a E3DPlaneFinder with a distance tolerance of 0.1 (world space coordinate) float distance_tolerance=0.1f; EPlaneFinder plane_finder(distance_tolerance); E3DPlane reference_plane=plane_finder.Find(point_cloud);
主平面(緑色)は、E3DPlaneFinderクラスによってポイントクラウドから抽出されました。
ZMapは、グレースケール2D画像であり、3D点の基準平面への投影を表します。ZMapのピクセルの値は、3D点および基準平面との距離であり、固定小数点表示でコード化されています。
ピクセル上に点が投影されておらず、その位置に有効な値が存在しない場合、ZMapは「未定義ピクセル」の特定の値もサポートします。
以下に示すように、ポイントクラウドからZMapへの変換は、すべてのパラメータのデフォルト値を使用して行うことができます。ZMapの解像度およびスケール、基準平面、方向、原点はすべて自動的に選択されます。
// Create the converter EPointCloudToZMapConverter pc2zmap; // Create a 16 bits ZMap and fill it with point cloud points EZMap16 zmap; pc2zmap.Convert(point_cloud, zmap); // Save the ZMap as a PNG image zmap.SaveImage("zmap.png");
生成された深度マップおよびデフォルトパラメータ
リモコンの本体が水平にならず、オブジェクトが整列していません。それでも、深度マップと比較すると、ZMapはオブジェクトのキャリブレーションされた表現です。メトリックの距離はZMapで評価できます。
ZMapコンバータの現在の実装は、単にZMap画像上に3D点を投影します。したがって、点密度および投影パラメータに応じて、未定義のピクセルおよび領域がZMapに現れることがあります。
ZMapコンバータは、未定義のピクセルに対して自動的に塗りつぶしアルゴリズムを実行します。EnableFillMode(false)で無効にします。

EnableFillMode(false)およびEnableFillMode(true)
未定義のピクセルを避けるには、ZMapのターゲットスケールを選択します。SetScale()メソッドは、ターゲットXおよびYの解像度をピクセル単位で変えます。
デフォルト設定では、ZMapジェネレータは水平基準平面を使用します。SetReferencePlane()メソッドを使用してオブジェクトを「レベル化」し、本体を基準平面として使用します。SetOrientationVector()は、ZMapのX(幅)軸の方向を指定します。方向ベクトルは、基準平面ノーマルの周囲でオブジェクトを「回転」させることができます。
// level the object by defining a reference plane pc2zmap.SetReferencePlane(reference_plane); // align to the world Y axis pc2zmap.SetOrientationVector(E3DPoint(-0.07501, 0.9964, -0.03761)); // choose a resolution of 0.2mm per pixel pc2zmap.SetMapXYResolution(0.2f); // generate the ZMap pc2zmap.Convert(point_cloud, zmap);
先に計算された基準平面、オブジェクトを整列させるための向き、および縮小された解像度を有するZマップ
Zmapのクエリを使用してメトリック座標を取得します(たとえば、フィーチャのサイズや高さを測定するなど)。便利な関数はGetWorldPositionFromPixelPosition(x,y)および GetZValue(x,y)です。
float h1 = zmap.GetZValue(638, 128); // get “height” at position P1 float h2 = zmap.GetZValue(595, 128); // get “height” at position P2 E3DPoint p3 = zmap.GetWorldPositionFromPixelPosition(437, 98); // get world position at p3 E3DPoint p4 = zmap.GetWorldPositionFromPixelPosition(437, 288); // get world position at p4 float d = p3.DistanceTo(p4); // world distance between p3 and p4
| ● | h1(1.15601)およびh2(1.83618)はZMap基準平面より上の距離です。これらはミリメートル単位の値で、その差はキーの「曲率」を評価します。 |
| ● | P1(58.843,84.7838,32.1084)およびP2(20.9479,81.9271,32.0041)は元の3Dワールド空間内の位置です。 |
| ● | 距離d(38.0028)はリモートキーボードの幅をミリメートル単位で表します。 |
基準平面を移動(平行移動)して、リモコン本体を取り外し、ZMap内のキーのみを保持することができます。他のOpen eVision2Dライブラリと互換性を持たせるには、8ビットのZMapを使用する必要があります。
// shift the plane by 1mm in the normal direction float d = reference_plane.GetSignedDistanceFromOrigin(); reference_plane.SetSignedDistanceFromOrigin(d + 1.f); pc2zmap.SetReferencePlane(reference_plane); // choose the scale for the Z axis (2mm for 256 grey scale values) pc2zmap.SetMapZResolution(2.f / 256); // convert the point cloud to a 8 bits ZMap EZMap8 zmap8; pc2zmap.Convert(point_cloud, zmap8);
シフトされた基準平面を持つZMap:キーのみが表示されたままで、他のピクセルは0(未定義の値)に設定されます。
この画像は、EasyImage、EasyObject、EasyGaugeなどの2Dライブラリで使用できます。
ZMapでは、ピクセルのグレーの値は基準平面の上の距離(高さ)です。閾値、フィルター、形態学やその他の画像演算子を直接使用することができます。
EasyObjectを使用した領域セグメンテーションの例を次に示します。
// segment the objects of the ZMap (default is Minimum Residue segmentation method) ECodedImage2 coded_image; EImageEncoder image_encoder; image_encoder.Encode(zmap8.AsEImage(), coded_image); // filter the object by area EObjectSelection object_selection; object_selection.AddObjects(coded_image); object_selection.RemoveUsingUnsignedIntegerFeature(EFeature_Area, 100, ESingleThresholdMode_Less);
ZMap画像上のEasyObjectを有する抽出されたオブジェクト
ZMapには、EasyGauge測定に使用できるEWorldShapeオブジェクトが含まれています。EWorldShapeクラスは、画像空間およびワールド空間の間のスケールを表します。
// get the world shape from the ZMap const EWorldShape& world_shape = zmap8.GetWorldShape(); // setup a point gauge using that world shape EPointGauge pointGauge; pointGauge.Attach(&world_shape); // set gauge center point and tolerances in world space (mm) pointGauge.SetCenterXY(128.f, 25.f); // 128mm and 25mm from the upper left corner pointGauge.SetTolerances(15.f, 0.f); // 15mm, half gauge size // perform the measurement on the ZMap pointGauge.Measure(&zmap8.AsEImage()); // get the 2 points and calculate the length of the key, values are in millimeters EPoint p1 = pointGauge.GetMeasuredPoint(0); EPoint p2 = pointGauge.GetMeasuredPoint(1); float length = p1.Distance(p2);// return 21.619mm
Open eVision Studio内のZMapのポイントゲージ:パラメータは上記のコードスニペットと同じです
