From f32a91837438dedd91c0224ca538740af6b4eb87 Mon Sep 17 00:00:00 2001 From: wangpeng2-mechmind Date: Wed, 24 Jun 2026 10:51:47 +0800 Subject: [PATCH] samples: update mecheye_csharp_samples to SDK 2.6.0 --- .../CaptureDepthSource2DImage/App.config | 6 + .../CaptureDepthSource2DImage.cs | 51 ++ .../CaptureDepthSource2DImage.csproj | 107 +++ .../CaptureDepthSource2DImage/README.md | 7 + .../CapturePeriodically.csproj | 2 +- .../CaptureStereo2DImages.csproj | 2 +- .../ConvertDepthMapToPointCloud.csproj | 2 +- .../Mapping2DImageToDepthMap.csproj | 2 +- .../MultipleCamerasCaptureSequentially.csproj | 2 +- ...ultipleCamerasCaptureSimultaneously.csproj | 2 +- .../RegisterCameraEvent.csproj | 2 +- .../RenderDepthMap/RenderDepthMap.csproj | 2 +- .../SetParametersOfLaserCameras.csproj | 2 +- .../SetParametersOfUHPCameras.csproj | 2 +- .../TransformPointCloud.csproj | 2 +- .../Capture2DImage/Capture2DImage.csproj | 2 +- .../CaptureDepthMap/CaptureDepthMap.csproj | 2 +- .../CapturePointCloud.csproj | 2 +- .../CapturePointCloudHDR.csproj | 2 +- .../CapturePointCloudWithNormals.csproj | 2 +- .../ConnectAndCaptureImages.csproj | 2 +- .../ConnectToCamera/ConnectToCamera.csproj | 2 +- .../SaveVirtualDevice.csproj | 2 +- .../HandEyeCalibration/HandEyeCalibration.cs | 9 + .../HandEyeCalibration.csproj | 2 +- area_scan_3d_camera/MechEyeCSharpSamples.sln | 11 + area_scan_3d_camera/README.md | 7 + .../GetCameraIntrinsics.csproj | 2 +- .../Util/ManageUserSets/ManageUserSets.csproj | 2 +- .../PrintCameraInfo/PrintCameraInfo.csproj | 2 +- .../SaveAndLoadUserSet.csproj | 2 +- .../Util/SetDepthRange/SetDepthRange.csproj | 2 +- .../SetPointCloudProcessingParameters.cs | 38 +- .../SetPointCloudProcessingParameters.csproj | 2 +- .../SetScanningParameters.cs | 71 ++ .../SetScanningParameters.csproj | 2 +- .../BlindSpotFiltering.csproj | 2 +- .../Advanced/NoiseRemoval/NoiseRemoval.csproj | 2 +- .../ProfileAlignment/ProfileAlignment.csproj | 2 +- .../RegisterProfilerEvent.csproj | 2 +- .../TransformPointCloud.cs | 12 + .../TransformPointCloud.csproj | 2 +- .../TriggerMultipleProfilersSimultaneously.cs | 4 + ...ggerMultipleProfilersSimultaneously.csproj | 2 +- .../UseVirtualDevice/UseVirtualDevice.csproj | 2 +- .../TriggerNonStopAcquisition.csproj | 2 +- .../TriggerWithExternalDeviceAndEncoder.cs | 9 +- ...TriggerWithExternalDeviceAndEncoder.csproj | 2 +- .../TriggerWithExternalDeviceAndFixedRate.cs | 4 + ...iggerWithExternalDeviceAndFixedRate.csproj | 2 +- .../TriggerWithSoftwareAndEncoder.cs | 9 +- .../TriggerWithSoftwareAndEncoder.csproj | 2 +- .../TriggerWithSoftwareAndFixedRate.cs | 4 + .../TriggerWithSoftwareAndFixedRate.csproj | 2 +- .../MoveDirVecCalibration/App.config | 6 + .../MoveDirVecCalibration.cs | 591 +++++++++++++++++ .../MoveDirVecCalibration.csproj | 91 +++ .../MoveDirVecCalibration/README.md | 5 + .../MultipleProfilersCalibration.cs | 16 +- .../MultipleProfilersCalibration.csproj | 4 +- .../WidthExpansionCalibration/App.config | 6 + .../WidthExpansionCalibration/README.md | 5 + .../WidthExpansionCalibration.cs | 617 ++++++++++++++++++ .../WidthExpansionCalibration.csproj | 91 +++ profiler/MechEyeCSharpSamples.sln | 20 + profiler/README.md | 18 +- .../HandleNanAndNegativeInDepth.csproj | 2 +- .../Util/ManageUserSets/ManageUserSets.csproj | 2 +- .../PrintProfilerStatus.csproj | 2 +- .../Util/RenderDepthMap/RenderDepthMap.csproj | 2 +- 70 files changed, 1841 insertions(+), 64 deletions(-) create mode 100644 area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/App.config create mode 100644 area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.cs create mode 100644 area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.csproj create mode 100644 area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/README.md create mode 100644 profiler/Calibration/MoveDirVecCalibration/App.config create mode 100644 profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.cs create mode 100644 profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.csproj create mode 100644 profiler/Calibration/MoveDirVecCalibration/README.md create mode 100644 profiler/Calibration/WidthExpansionCalibration/App.config create mode 100644 profiler/Calibration/WidthExpansionCalibration/README.md create mode 100644 profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.cs create mode 100644 profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.csproj diff --git a/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/App.config b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/App.config new file mode 100644 index 0000000..033746a --- /dev/null +++ b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.cs b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.cs new file mode 100644 index 0000000..a09a6b9 --- /dev/null +++ b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.cs @@ -0,0 +1,51 @@ +/* +With this sample, you can obtain and save the depth-source 2D image. +*/ + +using System; +using MMind.Eye; + +class CaptureDepthSource2DImage +{ + static int Main() + { + var camera = new Camera(); + if (!Utils.FindAndConnect(ref camera)) + return -1; + + Frame2D frame = new Frame2D(); + var errorStatus = camera.CaptureDepthSource2D(ref frame); + if (!errorStatus.IsOK()) + { + Utils.ShowError(errorStatus); + Console.WriteLine("Press any key to exit ..."); + Console.ReadKey(); + return -1; + } + + switch (frame.GetColorType()) + { + case Frame2D.ColorTypeOf2DCamera.Monochrome: + var gray = frame.GetGrayScaleImage(); + string grayScaleFile = "DepthSourceGrayScale2DImage.png"; + gray.Save(grayScaleFile); + Console.WriteLine("Capture and save the depth-source gray scale 2D image: {0}", grayScaleFile); + break; + case Frame2D.ColorTypeOf2DCamera.Color: + var color = frame.GetColorImage(); + string colorFile = "DepthSourceColor2DImage.png"; + color.Save(colorFile); + Console.WriteLine("Capture and save the depth-source color 2D image: {0}", colorFile); + break; + default: + Console.WriteLine("The acquired depth-source 2D image has an unsupported color type."); + break; + } + + camera.Disconnect(); + Console.WriteLine("Disconnected from the camera successfully."); + Console.WriteLine("Press any key to exit ..."); + Console.ReadKey(); + return 0; + } +} \ No newline at end of file diff --git a/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.csproj b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.csproj new file mode 100644 index 0000000..6d5ea07 --- /dev/null +++ b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/CaptureDepthSource2DImage.csproj @@ -0,0 +1,107 @@ + + + + + Debug + AnyCPU + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1} + Exe + CaptureDepthSource2DImage + CaptureDepthSource2DImage + v4.8 + 512 + true + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + x64 + true + full + false + $(SolutionDir)/Build_debug/$(AssemblyName) + DEBUG;TRACE + prompt + 4 + false + + + x64 + pdbonly + true + $(SolutionDir)/Build/$(AssemblyName) + TRACE + prompt + 4 + + + true + $(SolutionDir)/Build_debug/$(AssemblyName) + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + $(SolutionDir)/Build/$(AssemblyName) + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.6.0 + + + + \ No newline at end of file diff --git a/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/README.md b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/README.md new file mode 100644 index 0000000..1816e40 --- /dev/null +++ b/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage/README.md @@ -0,0 +1,7 @@ +# CaptureDepthSource2DImage Sample + +With this sample, you can obtain and save the depth-source 2D image. + +This sample is only applicable to camera models that provide the depth-source 2D image, such as Mech-Eye ULTRA M. + +If you have any questions or have anything to share, feel free to post on the [Mech-Mind Online Community](https://community.mech-mind.com/). The community also contains a [specific category for development with Mech-Eye SDK](https://community.mech-mind.com/c/mech-eye-sdk-development/19). \ No newline at end of file diff --git a/area_scan_3d_camera/Advanced/CapturePeriodically/CapturePeriodically.csproj b/area_scan_3d_camera/Advanced/CapturePeriodically/CapturePeriodically.csproj index 6612d7a..4b39b60 100644 --- a/area_scan_3d_camera/Advanced/CapturePeriodically/CapturePeriodically.csproj +++ b/area_scan_3d_camera/Advanced/CapturePeriodically/CapturePeriodically.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/CaptureStereo2DImages/CaptureStereo2DImages.csproj b/area_scan_3d_camera/Advanced/CaptureStereo2DImages/CaptureStereo2DImages.csproj index 63d6efa..1339468 100644 --- a/area_scan_3d_camera/Advanced/CaptureStereo2DImages/CaptureStereo2DImages.csproj +++ b/area_scan_3d_camera/Advanced/CaptureStereo2DImages/CaptureStereo2DImages.csproj @@ -100,7 +100,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/ConvertDepthMapToPointCloud/ConvertDepthMapToPointCloud.csproj b/area_scan_3d_camera/Advanced/ConvertDepthMapToPointCloud/ConvertDepthMapToPointCloud.csproj index c90b76d..3a2f16a 100644 --- a/area_scan_3d_camera/Advanced/ConvertDepthMapToPointCloud/ConvertDepthMapToPointCloud.csproj +++ b/area_scan_3d_camera/Advanced/ConvertDepthMapToPointCloud/ConvertDepthMapToPointCloud.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/Mapping2DImageToDepthMap/Mapping2DImageToDepthMap.csproj b/area_scan_3d_camera/Advanced/Mapping2DImageToDepthMap/Mapping2DImageToDepthMap.csproj index da682d8..54570d8 100644 --- a/area_scan_3d_camera/Advanced/Mapping2DImageToDepthMap/Mapping2DImageToDepthMap.csproj +++ b/area_scan_3d_camera/Advanced/Mapping2DImageToDepthMap/Mapping2DImageToDepthMap.csproj @@ -90,7 +90,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSequentially/MultipleCamerasCaptureSequentially.csproj b/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSequentially/MultipleCamerasCaptureSequentially.csproj index 8fb9476..263f643 100644 --- a/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSequentially/MultipleCamerasCaptureSequentially.csproj +++ b/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSequentially/MultipleCamerasCaptureSequentially.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSimultaneously/MultipleCamerasCaptureSimultaneously.csproj b/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSimultaneously/MultipleCamerasCaptureSimultaneously.csproj index df909f0..e1d79ad 100644 --- a/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSimultaneously/MultipleCamerasCaptureSimultaneously.csproj +++ b/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSimultaneously/MultipleCamerasCaptureSimultaneously.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/RegisterCameraEvent/RegisterCameraEvent.csproj b/area_scan_3d_camera/Advanced/RegisterCameraEvent/RegisterCameraEvent.csproj index 167caee..b9a185f 100644 --- a/area_scan_3d_camera/Advanced/RegisterCameraEvent/RegisterCameraEvent.csproj +++ b/area_scan_3d_camera/Advanced/RegisterCameraEvent/RegisterCameraEvent.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/RenderDepthMap/RenderDepthMap.csproj b/area_scan_3d_camera/Advanced/RenderDepthMap/RenderDepthMap.csproj index f88948f..33c0875 100644 --- a/area_scan_3d_camera/Advanced/RenderDepthMap/RenderDepthMap.csproj +++ b/area_scan_3d_camera/Advanced/RenderDepthMap/RenderDepthMap.csproj @@ -97,7 +97,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/SetParametersOfLaserCameras/SetParametersOfLaserCameras.csproj b/area_scan_3d_camera/Advanced/SetParametersOfLaserCameras/SetParametersOfLaserCameras.csproj index c3bb822..de81513 100644 --- a/area_scan_3d_camera/Advanced/SetParametersOfLaserCameras/SetParametersOfLaserCameras.csproj +++ b/area_scan_3d_camera/Advanced/SetParametersOfLaserCameras/SetParametersOfLaserCameras.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/SetParametersOfUHPCameras/SetParametersOfUHPCameras.csproj b/area_scan_3d_camera/Advanced/SetParametersOfUHPCameras/SetParametersOfUHPCameras.csproj index 16eea7c..0c5f009 100644 --- a/area_scan_3d_camera/Advanced/SetParametersOfUHPCameras/SetParametersOfUHPCameras.csproj +++ b/area_scan_3d_camera/Advanced/SetParametersOfUHPCameras/SetParametersOfUHPCameras.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Advanced/TransformPointCloud/TransformPointCloud.csproj b/area_scan_3d_camera/Advanced/TransformPointCloud/TransformPointCloud.csproj index 49913e0..0480eac 100644 --- a/area_scan_3d_camera/Advanced/TransformPointCloud/TransformPointCloud.csproj +++ b/area_scan_3d_camera/Advanced/TransformPointCloud/TransformPointCloud.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/Capture2DImage/Capture2DImage.csproj b/area_scan_3d_camera/Basic/Capture2DImage/Capture2DImage.csproj index 3c242e8..8c2a228 100644 --- a/area_scan_3d_camera/Basic/Capture2DImage/Capture2DImage.csproj +++ b/area_scan_3d_camera/Basic/Capture2DImage/Capture2DImage.csproj @@ -100,7 +100,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/CaptureDepthMap/CaptureDepthMap.csproj b/area_scan_3d_camera/Basic/CaptureDepthMap/CaptureDepthMap.csproj index b1bac26..3760916 100644 --- a/area_scan_3d_camera/Basic/CaptureDepthMap/CaptureDepthMap.csproj +++ b/area_scan_3d_camera/Basic/CaptureDepthMap/CaptureDepthMap.csproj @@ -100,7 +100,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/CapturePointCloud/CapturePointCloud.csproj b/area_scan_3d_camera/Basic/CapturePointCloud/CapturePointCloud.csproj index 5caa831..38512b5 100644 --- a/area_scan_3d_camera/Basic/CapturePointCloud/CapturePointCloud.csproj +++ b/area_scan_3d_camera/Basic/CapturePointCloud/CapturePointCloud.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/CapturePointCloudHDR/CapturePointCloudHDR.csproj b/area_scan_3d_camera/Basic/CapturePointCloudHDR/CapturePointCloudHDR.csproj index d48dbec..dd09190 100644 --- a/area_scan_3d_camera/Basic/CapturePointCloudHDR/CapturePointCloudHDR.csproj +++ b/area_scan_3d_camera/Basic/CapturePointCloudHDR/CapturePointCloudHDR.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/CapturePointCloudWithNormals/CapturePointCloudWithNormals.csproj b/area_scan_3d_camera/Basic/CapturePointCloudWithNormals/CapturePointCloudWithNormals.csproj index 9d685ca..4e7320c 100644 --- a/area_scan_3d_camera/Basic/CapturePointCloudWithNormals/CapturePointCloudWithNormals.csproj +++ b/area_scan_3d_camera/Basic/CapturePointCloudWithNormals/CapturePointCloudWithNormals.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/ConnectAndCaptureImages/ConnectAndCaptureImages.csproj b/area_scan_3d_camera/Basic/ConnectAndCaptureImages/ConnectAndCaptureImages.csproj index f13856a..15b9762 100644 --- a/area_scan_3d_camera/Basic/ConnectAndCaptureImages/ConnectAndCaptureImages.csproj +++ b/area_scan_3d_camera/Basic/ConnectAndCaptureImages/ConnectAndCaptureImages.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/ConnectToCamera/ConnectToCamera.csproj b/area_scan_3d_camera/Basic/ConnectToCamera/ConnectToCamera.csproj index d0b2ba7..ba8ccb0 100644 --- a/area_scan_3d_camera/Basic/ConnectToCamera/ConnectToCamera.csproj +++ b/area_scan_3d_camera/Basic/ConnectToCamera/ConnectToCamera.csproj @@ -112,7 +112,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Basic/SaveVirtualDevice/SaveVirtualDevice.csproj b/area_scan_3d_camera/Basic/SaveVirtualDevice/SaveVirtualDevice.csproj index 0840436..41a4093 100644 --- a/area_scan_3d_camera/Basic/SaveVirtualDevice/SaveVirtualDevice.csproj +++ b/area_scan_3d_camera/Basic/SaveVirtualDevice/SaveVirtualDevice.csproj @@ -109,7 +109,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.cs b/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.cs index 4dcb804..53bffe9 100644 --- a/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.cs +++ b/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.cs @@ -217,6 +217,14 @@ private void Calibrate() SaveExtrinsicParameters(cameraToBase.ToString()); } break; + case "F": + var corner = new PointXYZ(); + var status = calibration.ExtractCurrentImageFirstCorner(ref camera, ref corner); + Utils.ShowError(status); + + if (status.IsOK()) + Console.WriteLine("The first corner is: {0}, {1}, {2}", corner.X, corner.Y, corner.Z); + break; default: Console.WriteLine("Unknown command."); break; @@ -231,6 +239,7 @@ private string InputCommand() Console.WriteLine("T: Obtain the 2D image with feature recognition result"); Console.WriteLine("A: Enter the current robot pose"); Console.WriteLine("C: Calculate extrinsic parameters"); + Console.WriteLine("F: Obtain the first corner of current image"); return Console.ReadLine(); } diff --git a/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.csproj b/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.csproj index 8f2229e..d66df58 100644 --- a/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.csproj +++ b/area_scan_3d_camera/Calibration/HandEyeCalibration/HandEyeCalibration.csproj @@ -100,7 +100,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/MechEyeCSharpSamples.sln b/area_scan_3d_camera/MechEyeCSharpSamples.sln index d6cb8f8..9ccfa61 100644 --- a/area_scan_3d_camera/MechEyeCSharpSamples.sln +++ b/area_scan_3d_camera/MechEyeCSharpSamples.sln @@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CapturePointCloud", "Basic\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CapturePeriodically", "Advanced\CapturePeriodically\CapturePeriodically.csproj", "{B886D300-E70D-4530-9B38-046F91E7A133}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CaptureDepthSource2DImage", "Advanced\CaptureDepthSource2DImage\CaptureDepthSource2DImage.csproj", "{3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleCamerasCaptureSequentially", "Advanced\MultipleCamerasCaptureSequentially\MultipleCamerasCaptureSequentially.csproj", "{5762BB21-7544-492F-A3C4-A8FD68267019}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleCamerasCaptureSimultaneously", "Advanced\MultipleCamerasCaptureSimultaneously\MultipleCamerasCaptureSimultaneously.csproj", "{B9366EAE-914F-442F-A339-B620B95BCB49}" @@ -163,6 +165,14 @@ Global {B886D300-E70D-4530-9B38-046F91E7A133}.Release|Any CPU.Build.0 = Release|Any CPU {B886D300-E70D-4530-9B38-046F91E7A133}.Release|x64.ActiveCfg = Release|x64 {B886D300-E70D-4530-9B38-046F91E7A133}.Release|x64.Build.0 = Release|x64 + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Debug|x64.ActiveCfg = Debug|x64 + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Debug|x64.Build.0 = Debug|x64 + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Release|Any CPU.Build.0 = Release|Any CPU + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Release|x64.ActiveCfg = Release|x64 + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1}.Release|x64.Build.0 = Release|x64 {5762BB21-7544-492F-A3C4-A8FD68267019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5762BB21-7544-492F-A3C4-A8FD68267019}.Debug|Any CPU.Build.0 = Debug|Any CPU {5762BB21-7544-492F-A3C4-A8FD68267019}.Debug|x64.ActiveCfg = Debug|x64 @@ -315,6 +325,7 @@ Global {EFDEB798-4D61-4A79-9981-8E755ECB158B} = {7F571407-D08F-48B4-BAA3-C4D4DF63F453} {7E497210-9394-42C1-AA77-39ECA4FCDD9B} = {7F571407-D08F-48B4-BAA3-C4D4DF63F453} {B886D300-E70D-4530-9B38-046F91E7A133} = {209A38F1-163D-4173-9ED2-BD59CD3BA1DA} + {3C9D8BA2-9B0E-4E1F-A3E9-BD095D4F28C1} = {209A38F1-163D-4173-9ED2-BD59CD3BA1DA} {5762BB21-7544-492F-A3C4-A8FD68267019} = {209A38F1-163D-4173-9ED2-BD59CD3BA1DA} {B9366EAE-914F-442F-A339-B620B95BCB49} = {209A38F1-163D-4173-9ED2-BD59CD3BA1DA} {A6F98E9B-6E26-4D54-8E4A-B468DB0D4403} = {7F571407-D08F-48B4-BAA3-C4D4DF63F453} diff --git a/area_scan_3d_camera/README.md b/area_scan_3d_camera/README.md index f95244a..b241a37 100644 --- a/area_scan_3d_camera/README.md +++ b/area_scan_3d_camera/README.md @@ -29,7 +29,12 @@ The samples marked with `(OpenCV)` require [Emgu.CV.runtime.windows](https://www Set multiple exposure times, and then obtain and save the untextured and textured point clouds. * [CapturePointCloudWithNormals](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Basic/CapturePointCloudWithNormals) Calculate normals and save the untextured and textured point clouds with normals. + * [SaveVirtualDevice](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Basic/SaveVirtualDevice) + Save the data acquired by the camera as a virtual device file. * **Advanced** + * [CaptureDepthSource2DImage](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/CaptureDepthSource2DImage) `(OpenCV)` + Obtain and save the 2D image from the depth source camera. + > Note: This sample is only applicable to camera models that provide the depth-source 2D image, such as Mech-Eye ULTRA M. * [ConvertDepthMapToPointCloud](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/ConvertDepthMapToPointCloud) Generate a point cloud from the depth map and save the point cloud. * [MultipleCamerasCaptureSequentially](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/MultipleCamerasCaptureSequentially)`(OpenCV)` @@ -38,6 +43,8 @@ The samples marked with `(OpenCV)` require [Emgu.CV.runtime.windows](https://www Obtain and save 2D images, depth maps, and point clouds simultaneously from multiple cameras. * [CapturePeriodically](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/CapturePeriodically)`(OpenCV)` Obtain and save 2D images, depth maps, and point clouds periodically for the specified duration from a camera. + * [WarmUp](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/WarmUp) + Warm up the device. * [Mapping2DImageToDepthMap](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/Mapping2DImageToDepthMap) Generate untextured and textured point clouds from a masked 2D image and a depth map. * [RenderDepthMap](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/area_scan_3d_camera/Advanced/RenderDepthMap) `(OpenCV)` diff --git a/area_scan_3d_camera/Util/GetCameraIntrinsics/GetCameraIntrinsics.csproj b/area_scan_3d_camera/Util/GetCameraIntrinsics/GetCameraIntrinsics.csproj index 6044c6d..5ea9efe 100644 --- a/area_scan_3d_camera/Util/GetCameraIntrinsics/GetCameraIntrinsics.csproj +++ b/area_scan_3d_camera/Util/GetCameraIntrinsics/GetCameraIntrinsics.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Util/ManageUserSets/ManageUserSets.csproj b/area_scan_3d_camera/Util/ManageUserSets/ManageUserSets.csproj index c73eb65..1b57621 100644 --- a/area_scan_3d_camera/Util/ManageUserSets/ManageUserSets.csproj +++ b/area_scan_3d_camera/Util/ManageUserSets/ManageUserSets.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Util/PrintCameraInfo/PrintCameraInfo.csproj b/area_scan_3d_camera/Util/PrintCameraInfo/PrintCameraInfo.csproj index 6c37ab9..dee8712 100644 --- a/area_scan_3d_camera/Util/PrintCameraInfo/PrintCameraInfo.csproj +++ b/area_scan_3d_camera/Util/PrintCameraInfo/PrintCameraInfo.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Util/SaveAndLoadUserSet/SaveAndLoadUserSet.csproj b/area_scan_3d_camera/Util/SaveAndLoadUserSet/SaveAndLoadUserSet.csproj index 3f0a32e..30bf802 100644 --- a/area_scan_3d_camera/Util/SaveAndLoadUserSet/SaveAndLoadUserSet.csproj +++ b/area_scan_3d_camera/Util/SaveAndLoadUserSet/SaveAndLoadUserSet.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Util/SetDepthRange/SetDepthRange.csproj b/area_scan_3d_camera/Util/SetDepthRange/SetDepthRange.csproj index ce84199..c40be7a 100644 --- a/area_scan_3d_camera/Util/SetDepthRange/SetDepthRange.csproj +++ b/area_scan_3d_camera/Util/SetDepthRange/SetDepthRange.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.cs b/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.cs index eb3611e..945da97 100644 --- a/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.cs +++ b/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.cs @@ -29,26 +29,56 @@ static int Main() // Set the "Point Cloud Processing" parameters, and then obtain the parameter values to check if the setting was successful. var surfaceSmoothingName = MMind.Eye.PointCloudProcessingSetting.SurfaceSmoothing.Name; var noiseRemovalName = MMind.Eye.PointCloudProcessingSetting.NoiseRemoval.Name; + var depthSmoothName = MMind.Eye.PointCloudProcessingSetting.DepthSmooth.Name; + var depthHoleFillingName = MMind.Eye.PointCloudProcessingSetting.DepthHoleFilling.Name; + var depthSurfaceNoiseRemovalName = MMind.Eye.PointCloudProcessingSetting.DepthSurfaceNoiseRemoval.Name; + var phaseClusterOutlierRemovalName = MMind.Eye.PointCloudProcessingSetting.PhaseClusterOutlierRemoval.Name; + var spuriousPhaseRemovalName = MMind.Eye.PointCloudProcessingSetting.SpuriousPhaseRemoval.Name; + var largeGradNoiseRemovalName = MMind.Eye.PointCloudProcessingSetting.LargeGradNoiseRemoval.Name; var outlierRemovalName = MMind.Eye.PointCloudProcessingSetting.OutlierRemoval.Name; var edgePreservationName = MMind.Eye.PointCloudProcessingSetting.EdgePreservation.Name; Utils.ShowError(currentUserSet.SetEnumValue(surfaceSmoothingName, (int)MMind.Eye.PointCloudProcessingSetting.SurfaceSmoothing.Value.Normal)); Utils.ShowError(currentUserSet.SetEnumValue(noiseRemovalName, (int)MMind.Eye.PointCloudProcessingSetting.NoiseRemoval.Value.Normal)); + Utils.ShowError(currentUserSet.SetEnumValue(depthSmoothName, (int)MMind.Eye.PointCloudProcessingSetting.DepthSmooth.Value.Normal)); + Utils.ShowError(currentUserSet.SetEnumValue(depthHoleFillingName, (int)MMind.Eye.PointCloudProcessingSetting.DepthHoleFilling.Value.Normal)); + Utils.ShowError(currentUserSet.SetEnumValue(depthSurfaceNoiseRemovalName, (int)MMind.Eye.PointCloudProcessingSetting.DepthSurfaceNoiseRemoval.Value.Normal)); + Utils.ShowError(currentUserSet.SetEnumValue(phaseClusterOutlierRemovalName, (int)MMind.Eye.PointCloudProcessingSetting.PhaseClusterOutlierRemoval.Value.L5)); + Utils.ShowError(currentUserSet.SetEnumValue(spuriousPhaseRemovalName, (int)MMind.Eye.PointCloudProcessingSetting.SpuriousPhaseRemoval.Value.Normal)); + Utils.ShowError(currentUserSet.SetEnumValue(largeGradNoiseRemovalName, (int)MMind.Eye.PointCloudProcessingSetting.LargeGradNoiseRemoval.Value.Normal)); Utils.ShowError(currentUserSet.SetEnumValue(outlierRemovalName, (int)MMind.Eye.PointCloudProcessingSetting.OutlierRemoval.Value.Normal)); Utils.ShowError(currentUserSet.SetEnumValue(edgePreservationName, (int)MMind.Eye.PointCloudProcessingSetting.EdgePreservation.Value.Normal)); var surfaceSmoothingMode = new int(); var noiseRemovalMode = new int(); + var depthSmoothMode = new int(); + var depthHoleFillingMode = new int(); + var depthSurfaceNoiseRemovalMode = new int(); + var phaseClusterOutlierRemovalMode = new int(); + var spuriousPhaseRemovalMode = new int(); + var largeGradNoiseRemovalMode = new int(); var outlierRemovalMode = new int(); var edgePreservationMode = new int(); Utils.ShowError(currentUserSet.GetEnumValue(surfaceSmoothingName, ref surfaceSmoothingMode)); Utils.ShowError(currentUserSet.GetEnumValue(noiseRemovalName, ref noiseRemovalMode)); + Utils.ShowError(currentUserSet.GetEnumValue(depthSmoothName, ref depthSmoothMode)); + Utils.ShowError(currentUserSet.GetEnumValue(depthHoleFillingName, ref depthHoleFillingMode)); + Utils.ShowError(currentUserSet.GetEnumValue(depthSurfaceNoiseRemovalName, ref depthSurfaceNoiseRemovalMode)); + Utils.ShowError(currentUserSet.GetEnumValue(phaseClusterOutlierRemovalName, ref phaseClusterOutlierRemovalMode)); + Utils.ShowError(currentUserSet.GetEnumValue(spuriousPhaseRemovalName, ref spuriousPhaseRemovalMode)); + Utils.ShowError(currentUserSet.GetEnumValue(largeGradNoiseRemovalName, ref largeGradNoiseRemovalMode)); Utils.ShowError(currentUserSet.GetEnumValue(outlierRemovalName, ref outlierRemovalMode)); Utils.ShowError(currentUserSet.GetEnumValue(edgePreservationName, ref edgePreservationMode)); - Console.WriteLine("Point Cloud Surface Smoothing: {0}.", surfaceSmoothingMode); - Console.WriteLine("Point Cloud Noise Removal: {0}.", noiseRemovalMode); - Console.WriteLine("Point Cloud Outlier Removal: {0}.", outlierRemovalMode); - Console.WriteLine("Point Cloud Edge Preservation: {0}.", edgePreservationMode); + Console.WriteLine("Point Cloud Surface Smoothing: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", surfaceSmoothingMode); + Console.WriteLine("Point Cloud Noise Removal: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", noiseRemovalMode); + Console.WriteLine("Depth Smooth: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", depthSmoothMode); + Console.WriteLine("Depth Hole Filling: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", depthHoleFillingMode); + Console.WriteLine("Depth Surface Noise Removal: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", depthSurfaceNoiseRemovalMode); + Console.WriteLine("Phase Cluster Outlier Removal: {0} (0: Off, 1: L1, 2: L2, 3: L3, 4: L4, 5: L5, 6: L6, 7: L7, 8: L8, 9: L9, 10: L10).", phaseClusterOutlierRemovalMode); + Console.WriteLine("Spurious Phase Removal: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", spuriousPhaseRemovalMode); + Console.WriteLine("Large Gradient Noise Removal: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", largeGradNoiseRemovalMode); + Console.WriteLine("Point Cloud Outlier Removal: {0} (0: Off, 1: Weak, 2: Normal, 3: Strong).", outlierRemovalMode); + Console.WriteLine("Point Cloud Edge Preservation: {0} (0: Sharp, 1: Normal, 2: Smooth).", edgePreservationMode); // Save all the parameter settings to the currently selected user set. var successMessage = "Save the current parameter settings to the selected user set."; diff --git a/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.csproj b/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.csproj index 1bf7a77..143811a 100644 --- a/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.csproj +++ b/area_scan_3d_camera/Util/SetPointCloudProcessingParameters/SetPointCloudProcessingParameters.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.cs b/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.cs index e88278f..9aba66d 100644 --- a/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.cs +++ b/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.cs @@ -25,8 +25,17 @@ static int Main() // Obtain the name of the currently selected user set. var currentUserSet = userSetManager.CurrentUserSet(); Console.WriteLine("Current user set: {0}", currentUserSet.GetName()); + var availableParams = new List(); + Utils.ShowError(currentUserSet.GetAvailableParameterNames(ref availableParams)); // Set the exposure times for acquiring depth information. + if (availableParams.Contains(MMind.Eye.Scanning3DSetting.ExposureCount.Name)) + { + Utils.ShowError(currentUserSet.SetIntValue(MMind.Eye.Scanning3DSetting.ExposureCount.Name, 1)); + var exposureCount = new int(); + Utils.ShowError(currentUserSet.GetIntValue(MMind.Eye.Scanning3DSetting.ExposureCount.Name, ref exposureCount)); + Console.WriteLine("3D scanning exposure count : {0}.", exposureCount); + } var exposure3DName = MMind.Eye.Scanning3DSetting.ExposureSequence.Name; Utils.ShowError(currentUserSet.SetFloatArrayValue(exposure3DName, new List { 5 })); //Utils.ShowError(currentUserSet.SetFloatArrayValue(exposure3DName, new List { 5, 10 })); @@ -38,6 +47,48 @@ static int Main() for (int i = 0; i < exposureSequence.Count; ++i) Console.WriteLine("3D scanning exposure time {0} : {1} ms.", i + 1, exposureSequence[i]); + // Some models provide exposure group parameters. Use "GroupExposureSelector" to select the + // target group, and then set the group exposure time, gain, and power level. + if (availableParams.Contains(MMind.Eye.Scanning3DSetting.GroupExposureSelector.Name) && + availableParams.Contains(MMind.Eye.Scanning3DSetting.GroupExposureTime.Name) && + availableParams.Contains(MMind.Eye.Scanning3DSetting.GroupGain.Name) && + availableParams.Contains(MMind.Eye.Scanning3DSetting.GroupDlpPowerLevel.Name)) + { + var groupExposureSelectorName = MMind.Eye.Scanning3DSetting.GroupExposureSelector.Name; + var groupExposureTimeName = MMind.Eye.Scanning3DSetting.GroupExposureTime.Name; + var groupGainName = MMind.Eye.Scanning3DSetting.GroupGain.Name; + var groupDlpPowerLevelName = MMind.Eye.Scanning3DSetting.GroupDlpPowerLevel.Name; + + Utils.ShowError(currentUserSet.SetEnumValue( + groupExposureSelectorName, + (int)MMind.Eye.Scanning3DSetting.GroupExposureSelector.Value.Exposure1)); + Utils.ShowError(currentUserSet.SetFloatValue(groupExposureTimeName, 10)); + Utils.ShowError(currentUserSet.SetFloatValue(groupGainName, 2.0)); + Utils.ShowError(currentUserSet.SetIntValue(groupDlpPowerLevelName, 80)); + + var groupExposureTime = new double(); + var groupGain = new double(); + var groupDlpPowerLevel = new int(); + Utils.ShowError(currentUserSet.GetFloatValue(groupExposureTimeName, ref groupExposureTime)); + Utils.ShowError(currentUserSet.GetFloatValue(groupGainName, ref groupGain)); + Utils.ShowError(currentUserSet.GetIntValue(groupDlpPowerLevelName, ref groupDlpPowerLevel)); + Console.WriteLine("Group Exposure1: exposure time {0} ms, gain {1} dB, DLP power level {2}.", + groupExposureTime, groupGain, groupDlpPowerLevel); + + Utils.ShowError(currentUserSet.SetEnumValue( + groupExposureSelectorName, + (int)MMind.Eye.Scanning3DSetting.GroupExposureSelector.Value.Exposure2)); + Utils.ShowError(currentUserSet.SetFloatValue(groupExposureTimeName, 5)); + Utils.ShowError(currentUserSet.SetFloatValue(groupGainName, 0.0)); + Utils.ShowError(currentUserSet.SetIntValue(groupDlpPowerLevelName, 60)); + + Utils.ShowError(currentUserSet.GetFloatValue(groupExposureTimeName, ref groupExposureTime)); + Utils.ShowError(currentUserSet.GetFloatValue(groupGainName, ref groupGain)); + Utils.ShowError(currentUserSet.GetIntValue(groupDlpPowerLevelName, ref groupDlpPowerLevel)); + Console.WriteLine("Group Exposure2: exposure time {0} ms, gain {1} dB, DLP power level {2}.", + groupExposureTime, groupGain, groupDlpPowerLevel); + } + // Set the ROI for the depth map and point cloud, and then obtain the parameter values for // checking. var roi3DName = MMind.Eye.Scanning3DSetting.ROI.Name; @@ -103,6 +154,26 @@ static int Main() //Utils.ShowError(currentUserSet.GetFloatValue(scan2dGainName,ref scan2dGain)); //Console.WriteLine("2D image gain: {0} dB.", scan2dGain); + + // The following parameters are only available on some models. Uncomment to set and read values. + //var patternRoleGainName = MMind.Eye.Scanning2DSetting.PatternRoleGain.Name; + //Utils.ShowError(currentUserSet.SetFloatValue(patternRoleGainName, 2.0)); + //double patternRoleGain = new double(); + //Utils.ShowError(currentUserSet.GetFloatValue(patternRoleGainName, ref patternRoleGain)); + //Console.WriteLine("2D pattern role gain: {0} dB.", patternRoleGain); + // + //var flashGainName = MMind.Eye.Scanning2DSetting.FlashGain.Name; + //Utils.ShowError(currentUserSet.SetFloatValue(flashGainName, 2.0)); + //double flashGain = new double(); + //Utils.ShowError(currentUserSet.GetFloatValue(flashGainName, ref flashGain)); + //Console.WriteLine("2D flash gain: {0} dB.", flashGain); + // + //var flashPowerLevelName = MMind.Eye.Scanning2DSetting.FlashPowerLevel.Name; + //Utils.ShowError(currentUserSet.SetIntValue(flashPowerLevelName, 80)); + //int flashPowerLevel = new int(); + //Utils.ShowError(currentUserSet.GetIntValue(flashPowerLevelName, ref flashPowerLevel)); + //Console.WriteLine("2D flash power level: {0} %.", flashPowerLevel); + var exposureMode2D = new int(); double scan2DExposureTime = new double(); Utils.ShowError(currentUserSet.GetEnumValue(exposureModeName, ref exposureMode2D)); diff --git a/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.csproj b/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.csproj index a3afefb..08b37d9 100644 --- a/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.csproj +++ b/area_scan_3d_camera/Util/SetScanningParameters/SetScanningParameters.csproj @@ -85,7 +85,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/BlindSpotFiltering/BlindSpotFiltering.csproj b/profiler/Advanced/BlindSpotFiltering/BlindSpotFiltering.csproj index cd7f48d..f7d9198 100644 --- a/profiler/Advanced/BlindSpotFiltering/BlindSpotFiltering.csproj +++ b/profiler/Advanced/BlindSpotFiltering/BlindSpotFiltering.csproj @@ -79,7 +79,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/NoiseRemoval/NoiseRemoval.csproj b/profiler/Advanced/NoiseRemoval/NoiseRemoval.csproj index 80470a0..06928ef 100644 --- a/profiler/Advanced/NoiseRemoval/NoiseRemoval.csproj +++ b/profiler/Advanced/NoiseRemoval/NoiseRemoval.csproj @@ -79,7 +79,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/ProfileAlignment/ProfileAlignment.csproj b/profiler/Advanced/ProfileAlignment/ProfileAlignment.csproj index 0d73451..a45d117 100644 --- a/profiler/Advanced/ProfileAlignment/ProfileAlignment.csproj +++ b/profiler/Advanced/ProfileAlignment/ProfileAlignment.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/RegisterProfilerEvent/RegisterProfilerEvent.csproj b/profiler/Advanced/RegisterProfilerEvent/RegisterProfilerEvent.csproj index 74a01e3..86d4bd3 100644 --- a/profiler/Advanced/RegisterProfilerEvent/RegisterProfilerEvent.csproj +++ b/profiler/Advanced/RegisterProfilerEvent/RegisterProfilerEvent.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/TransformPointCloud/TransformPointCloud.cs b/profiler/Advanced/TransformPointCloud/TransformPointCloud.cs index ec3ecef..ec368a4 100644 --- a/profiler/Advanced/TransformPointCloud/TransformPointCloud.cs +++ b/profiler/Advanced/TransformPointCloud/TransformPointCloud.cs @@ -79,6 +79,10 @@ private static void SetParameters(UserSet userSet) // Set the "Scan Line Count" parameter (the number of lines to be scanned) to 1600 Utils.ShowError( userSet.SetIntValue(MMind.Eye.ScanSettings.ScanLineCount.Name, 1600)); + // Set the "Travel Speed" parameter to 100 mm/s. This value is used to calculate the + // Y-axis resolution and scan distance when line scan is triggered at a fixed rate. + Utils.ShowError( + userSet.SetFloatValue(MMind.Eye.TriggerSettings.TravelSpeed.Name, 100.0)); } /// Convert the profile data to an untextured point cloud in the custom reference frame and save it @@ -104,6 +108,14 @@ private static void ConvertBatchToPointCloudWithTransformation(ProfileBatch batc Utils.ShowError(status); return; } + double scanDistance = 0; + status = userSet.GetFloatValue(MMind.Eye.ScanSettings.ScanDistance.Name, ref scanDistance); + if (!status.IsOK()) + { + Utils.ShowError(status); + return; + } + Console.WriteLine($"Current Y-axis resolution: {yResolution} um, scan distance: {scanDistance} um."); // Uncomment the following lines for custom Y Unit // // Prompt to enter the desired encoder resolution, which is the travel distance corresponding to // // one quadrature signal. diff --git a/profiler/Advanced/TransformPointCloud/TransformPointCloud.csproj b/profiler/Advanced/TransformPointCloud/TransformPointCloud.csproj index c92eae0..e88ffeb 100644 --- a/profiler/Advanced/TransformPointCloud/TransformPointCloud.csproj +++ b/profiler/Advanced/TransformPointCloud/TransformPointCloud.csproj @@ -79,7 +79,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.cs b/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.cs index 0de6400..ca8441d 100644 --- a/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.cs +++ b/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.cs @@ -129,6 +129,10 @@ private static void SetParameters(UserSet userSet) // Set the "Scan Line Count" parameter (the number of lines to be scanned) to 1600 Utils.ShowError( userSet.SetIntValue(MMind.Eye.ScanSettings.ScanLineCount.Name, 1600)); + // Set the "Travel Speed" parameter to 100 mm/s. This value is used to calculate the + // Y-axis resolution and scan distance when line scan is triggered at a fixed rate. + Utils.ShowError( + userSet.SetFloatValue(MMind.Eye.TriggerSettings.TravelSpeed.Name, 100.0)); // Set the "Laser Power" parameter to 100 Utils.ShowError(userSet.SetIntValue(MMind.Eye.BrightnessSettings.LaserPower.Name, 100)); diff --git a/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.csproj b/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.csproj index 702d58d..dee3920 100644 --- a/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.csproj +++ b/profiler/Advanced/TriggerMultipleProfilersSimultaneously/TriggerMultipleProfilersSimultaneously.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Advanced/UseVirtualDevice/UseVirtualDevice.csproj b/profiler/Advanced/UseVirtualDevice/UseVirtualDevice.csproj index b867a3b..f1a944a 100644 --- a/profiler/Advanced/UseVirtualDevice/UseVirtualDevice.csproj +++ b/profiler/Advanced/UseVirtualDevice/UseVirtualDevice.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Basic/TriggerNonStopAcquisition/TriggerNonStopAcquisition.csproj b/profiler/Basic/TriggerNonStopAcquisition/TriggerNonStopAcquisition.csproj index fe2620f..eb58989 100644 --- a/profiler/Basic/TriggerNonStopAcquisition/TriggerNonStopAcquisition.csproj +++ b/profiler/Basic/TriggerNonStopAcquisition/TriggerNonStopAcquisition.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.cs b/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.cs index 6f4f958..9a08171 100644 --- a/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.cs +++ b/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.cs @@ -60,7 +60,7 @@ private static void SetHDRExposure(UserSet userSet, int exposureTime, double pro secondThreshold)); } - private static void SetEncoderTrigger(UserSet userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value triggerDirection, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value triggerSignalCountingMode, int triggerInterval) + private static void SetEncoderTrigger(UserSet userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value triggerDirection, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value triggerSignalCountingMode, int triggerInterval, double encoderResolution) { // Set the "Line Scan Trigger Source" parameter to "Encoder" Utils.ShowError(userSet.SetEnumValue( @@ -81,6 +81,10 @@ private static void SetEncoderTrigger(UserSet userSet, MMind.Eye.TriggerSettings // Set the (encoder) "Trigger Interval" parameter to 10 Utils.ShowError( userSet.SetIntValue(MMind.Eye.TriggerSettings.EncoderTriggerInterval.Name, 10)); + + // Set the "Encoder Resolution" parameter (unit: μm) + Utils.ShowError( + userSet.SetFloatValue(MMind.Eye.TriggerSettings.EncoderResolution.Name, encoderResolution)); } private static void SetParameters(UserSet userSet) @@ -123,7 +127,8 @@ private static void SetParameters(UserSet userSet) // Set the (encoder) "Trigger Direction" parameter to "Both" // Set the (encoder) "Trigger Signal Counting Mode" parameter to "1×" // Set the (encoder) "Trigger Interval" parameter to 10 - SetEncoderTrigger(userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value.Both, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value.Multiple_1, 10); + // Set the "Encoder Resolution" parameter to 5 μm + SetEncoderTrigger(userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value.Both, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value.Multiple_1, 10, 5); // Set the "Scan Line Count" parameter (the number of lines to be scanned) to 1600 Utils.ShowError( diff --git a/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.csproj b/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.csproj index af05245..ac6cf59 100644 --- a/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.csproj +++ b/profiler/Basic/TriggerWithExternalDeviceAndEncoder/TriggerWithExternalDeviceAndEncoder.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.cs b/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.cs index 00b340b..d452436 100644 --- a/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.cs +++ b/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.cs @@ -105,6 +105,10 @@ private static void SetParameters(UserSet userSet) // Set the "Scan Line Count" parameter (the number of lines to be scanned) to 1600 Utils.ShowError( userSet.SetIntValue(MMind.Eye.ScanSettings.ScanLineCount.Name, 1600)); + // Set the "Travel Speed" parameter to 100 mm/s. This value is used to calculate the + // Y-axis resolution and scan distance when line scan is triggered at a fixed rate. + Utils.ShowError( + userSet.SetFloatValue(MMind.Eye.TriggerSettings.TravelSpeed.Name, 100.0)); // Set the "Laser Power" parameter to 100 Utils.ShowError(userSet.SetIntValue(MMind.Eye.BrightnessSettings.LaserPower.Name, 100)); diff --git a/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.csproj b/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.csproj index 45a36a9..f828357 100644 --- a/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.csproj +++ b/profiler/Basic/TriggerWithExternalDeviceAndFixedRate/TriggerWithExternalDeviceAndFixedRate.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.cs b/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.cs index f8b0fae..3f7f7c9 100644 --- a/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.cs +++ b/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.cs @@ -58,7 +58,7 @@ private static void SetHDRExposure(UserSet userSet, int exposureTime, double pro secondThreshold)); } - private static void SetEncoderTrigger(UserSet userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value triggerDirection, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value triggerSignalCountingMode, int triggerInterval) + private static void SetEncoderTrigger(UserSet userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value triggerDirection, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value triggerSignalCountingMode, int triggerInterval, double encoderResolution) { // Set the "Line Scan Trigger Source" parameter to "Encoder" Utils.ShowError(userSet.SetEnumValue( @@ -79,6 +79,10 @@ private static void SetEncoderTrigger(UserSet userSet, MMind.Eye.TriggerSettings // Set the (encoder) "Trigger Interval" parameter to 10 Utils.ShowError( userSet.SetIntValue(MMind.Eye.TriggerSettings.EncoderTriggerInterval.Name, 10)); + + // Set the "Encoder Resolution" parameter (unit: μm) + Utils.ShowError( + userSet.SetFloatValue(MMind.Eye.TriggerSettings.EncoderResolution.Name, encoderResolution)); } private static void SetParameters(UserSet userSet) @@ -121,7 +125,8 @@ private static void SetParameters(UserSet userSet) // Set the (encoder) "Trigger Direction" parameter to "Both" // Set the (encoder) "Trigger Signal Counting Mode" parameter to "1×" // Set the (encoder) "Trigger Interval" parameter to 10 - SetEncoderTrigger(userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value.Both, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value.Multiple_1, 10); + // Set the "Encoder Resolution" parameter to 5 μm + SetEncoderTrigger(userSet, MMind.Eye.TriggerSettings.EncoderTriggerDirection.Value.Both, MMind.Eye.TriggerSettings.EncoderTriggerSignalCountingMode.Value.Multiple_1, 10, 5); // Set the "Scan Line Count" parameter (the number of lines to be scanned) to 1600 Utils.ShowError( diff --git a/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.csproj b/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.csproj index bc57950..bec32ed 100644 --- a/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.csproj +++ b/profiler/Basic/TriggerWithSoftwareAndEncoder/TriggerWithSoftwareAndEncoder.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.cs b/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.cs index fc91d42..21be758 100644 --- a/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.cs +++ b/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.cs @@ -102,6 +102,10 @@ private static void SetParameters(UserSet userSet) // Set the "Scan Line Count" parameter (the number of lines to be scanned) to 1600 Utils.ShowError( userSet.SetIntValue(MMind.Eye.ScanSettings.ScanLineCount.Name, 1600)); + // Set the "Travel Speed" parameter to 100 mm/s. This value is used to calculate the + // Y-axis resolution and scan distance when line scan is triggered at a fixed rate. + Utils.ShowError( + userSet.SetFloatValue(MMind.Eye.TriggerSettings.TravelSpeed.Name, 100.0)); // Set the "Laser Power" parameter to 100 Utils.ShowError(userSet.SetIntValue(MMind.Eye.BrightnessSettings.LaserPower.Name, 100)); diff --git a/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.csproj b/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.csproj index 641a87f..399e7d2 100644 --- a/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.csproj +++ b/profiler/Basic/TriggerWithSoftwareAndFixedRate/TriggerWithSoftwareAndFixedRate.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Calibration/MoveDirVecCalibration/App.config b/profiler/Calibration/MoveDirVecCalibration/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/profiler/Calibration/MoveDirVecCalibration/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.cs b/profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.cs new file mode 100644 index 0000000..5881a39 --- /dev/null +++ b/profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.cs @@ -0,0 +1,591 @@ +/* +With this sample, you can complete the calibration of the movement direction vector for a single laser profiler, obtain the calibrated movement direction vector, the corresponding reprojection error, and correction parameters for downstream processing (including depth maps and pixel offsets obtained from direction correction). The sample aims for engineering reproducibility and result acceptability, demonstrating a complete closed-loop process from acquisition to correction and back to the camera coordinate system. +*/ + +using System; +using MMind.Eye; +using Emgu.CV; +using Emgu.CV.CvEnum; +using System.Threading; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Linq; + + + +class MoveDirVecCalibration +{ + private const int CV_8UC1 = 0; + private const int CV_32FC1 = 5; + + public static T GetInputNumber() where T : IConvertible + { + while (true) + { + string input = Console.ReadLine(); + try + { + if (typeof(T) == typeof(bool)) + { + input = input.Trim().ToLower(); + if (input == "true" || input == "1") + return (T)Convert.ChangeType(true, typeof(T)); + if (input == "false" || input == "0") + return (T)Convert.ChangeType(false, typeof(T)); + throw new Exception(); + } + return (T)Convert.ChangeType(input, typeof(T)); + } + catch + { + Console.WriteLine($"Invalid input! Please enter a valid number."); + } + } + } + + // Set the calibration mode based on user input + public static ProfilerCalibrationMode InputCalibType() + { + while (true) + { + Console.WriteLine("\nEnter the number that represents the calibration types:\n1: Wide\n2: Angle"); + int input = GetInputNumber(); + switch (input) + { + case 1: return ProfilerCalibrationMode.Wide; + case 2: return ProfilerCalibrationMode.Angle; + default: Console.WriteLine("Invalid input! Please enter 1 or 2."); break; + } + } + } + + // Set the calibration mode based on user input + public static int InputMovementAxis() + { + while (true) + { + Console.WriteLine("\nEnter the number that represents the movement axis:\n1: X\n2: Y\n3: Z"); + int input = GetInputNumber(); + return input; + } + } + + // Set the target transformation axis based on user input + public static MMind.Eye.TargetTranslateAxis InputTargetTransformAxis() + { + while (true) + { + Console.WriteLine("\nEnter the number that represents the transform axis:\n1: X\n2: Y"); + int input = GetInputNumber(); + switch (input) + { + case 1: return MMind.Eye.TargetTranslateAxis.X; + case 2: return MMind.Eye.TargetTranslateAxis.Y; + default: Console.WriteLine("Invalid input! Please enter 1 or 2."); break; + } + } + } + + // Print error messages when stitching fails + public static void PrintError(MultiProfilerErrorStatus errorStatus) + { + if (errorStatus == null) + { + Console.WriteLine("\nerrorStatus: null"); + return; + } + Console.WriteLine($"\nerrorStatus: {errorStatus.ErrorCode}"); + Console.WriteLine($"\nerrorDescription: {errorStatus.MultiProfilerErrorDescription}"); + Console.WriteLine($"\nerrorSource: {errorStatus.ErrorSource} {errorStatus.GroupID}"); + } + + // Acquire profile data from a profiler + public static bool AcquireProfileData(Profiler profiler, ref ProfileBatch totalBatch, int captureLineCount, int dataWidth, bool isSoftwareTrigger) + { + Console.WriteLine("Start data acquisition."); + ErrorStatus status = profiler.StartAcquisition(); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return false; + } + + if (isSoftwareTrigger) + { + status = profiler.TriggerSoftware(); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return false; + } + } + + totalBatch.Clear(); + totalBatch.Reserve((ulong)captureLineCount); + while (totalBatch.Height() < (ulong)captureLineCount) + { + ProfileBatch batch = new ProfileBatch((ulong)dataWidth); + status = profiler.RetrieveBatchData(ref batch); + if (status.IsOK()) + { + if (!totalBatch.Append(batch)) + break; + Thread.Sleep(200); + } + else + { + MMind.Eye.Utils.ShowError(status); + return false; + } + } + + Console.WriteLine("Stop data acquisition."); + status = profiler.StopAcquisition(); + if (!status.IsOK()) + MMind.Eye.Utils.ShowError(status); + return status.IsOK(); + } + + // Get device information and interact with the user for additional parameters + public static DeviceInfo GetDeviceInfo(Profiler profiler) + { + UserSet userSet = profiler.CurrentUserSet(); + ProfilerInfo profilerInfo = new ProfilerInfo(); + ErrorStatus status = profiler.GetProfilerInfo(ref profilerInfo); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + MMind.Eye.Utils.PrintProfilerInfo(profilerInfo); + + // Get X xResolution + double xResolution = 0; + status = userSet.GetFloatValue(MMind.Eye.PointCloudResolutions.XAxisResolution.Name, ref xResolution); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + + // Get Y Resolution + double yResolution = 0; + status = userSet.GetFloatValue(MMind.Eye.PointCloudResolutions.YResolution.Name, ref yResolution); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + + // get Profile ROI + ProfileROI roiValue = new ProfileROI(); + status = userSet.GetProfileRoiValue(MMind.Eye.ProfileROISettings.ROI.Name, ref roiValue); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + + Console.WriteLine("\nEnter the downsampling interval in the X direction: "); + uint downsampleX = GetInputNumber(); + + Console.WriteLine("\nEnter the downsampling interval in the Y direction: "); + uint downsampleY = GetInputNumber(); + + Console.WriteLine("\nEnter the Camera motion direction: "); + bool directionPositive = GetInputNumber(); + + Console.WriteLine("Please confirm the following device settings:"); + Console.WriteLine("--------------------------------------------"); + Console.WriteLine($"1. X-Axis Resolution (mm): {xResolution / 1000:F3}"); + Console.WriteLine($"2. Y-Axis Resolution (mm): {yResolution / 1000:F3}"); + Console.WriteLine($"3. Downsampling Factor (X): {downsampleX}"); + Console.WriteLine($"4. Downsampling Factor (Y): {downsampleY}"); + Console.WriteLine($"5. Motion Direction Sign: {directionPositive}"); + Console.WriteLine($"6. ROI Size (Width , Height): ({roiValue.Width}, {roiValue.Height})"); + Console.WriteLine($"7. ROI Center (X,Y): ({roiValue.XAxisCenter}, 0)"); + Console.WriteLine("--------------------------------------------"); + + DeviceInfo deviceInfo = new DeviceInfo(); + deviceInfo.DX = (float)(xResolution / 1000); + deviceInfo.DY = (float)(yResolution / 1000); + deviceInfo.DownsampleX = downsampleX; + deviceInfo.DownsampleY = downsampleY; + deviceInfo.MoveDirSign = directionPositive; + deviceInfo.ROISize = new Point2f { X = (float)roiValue.Width, Y = (float)roiValue.Height }; + deviceInfo.ROICenter = new Point2f { X = (float)roiValue.XAxisCenter, Y = 0 }; + return deviceInfo; + } + + // Asynchronously capture images from a profiler + public static ProfilerImage CaptureAsync(Profiler profiler) + { + ProfilerInfo profilerInfo = new ProfilerInfo(); + MMind.Eye.Utils.ShowError(profiler.GetProfilerInfo(ref profilerInfo)); + + // Select "calib" user set to capture image. + string calibSetting = "calib"; + UserSetManager userSetManager = profiler.UserSetManager(); + string successMessage = $"Set current set as the \"{calibSetting}\" user set."; + MMind.Eye.Utils.ShowError(userSetManager.SelectUserSet(calibSetting), successMessage); + + UserSet userSet = profiler.CurrentUserSet(); + + int dataWidth = 0; + MMind.Eye.Utils.ShowError(userSet.GetIntValue(MMind.Eye.ScanSettings.DataPointsPerProfile.Name, ref dataWidth)); + int captureLineCount = 0; + userSet.GetIntValue(MMind.Eye.ScanSettings.ScanLineCount.Name, ref captureLineCount); + + ProfileBatch profileBatch = new ProfileBatch((ulong)dataWidth); + + int dataAcquisitionTriggerSource = 0; + MMind.Eye.Utils.ShowError(userSet.GetEnumValue(MMind.Eye.TriggerSettings.DataAcquisitionTriggerSource.Name, ref dataAcquisitionTriggerSource)); + + //// Adjust the "Trigger Delay" appropriately to avoid interference between devices and ensure + /// optimal imaging performance. + // showError(userSet.setEnumValue(mmind::eye::trigger_settings::TriggerDelay::name, 100)); + bool isSoftwareTrigger = dataAcquisitionTriggerSource == (int)MMind.Eye.TriggerSettings.DataAcquisitionTriggerSource.Value.Software; + + if (!AcquireProfileData(profiler, ref profileBatch, captureLineCount, dataWidth, isSoftwareTrigger)) + return null; + + if (profileBatch.CheckFlag(ProfileBatch.BatchFlag.Incomplete)) + Console.WriteLine($"Part of the batch's data is lost, the number of valid profiles is: {profileBatch.ValidHeight()}."); + + var depthMap = profileBatch.GetDepthMap(); + var intensityImage = profileBatch.GetIntensityImage(); + + ProfilerImage result = new ProfilerImage(); + ImageWrapper imgDepth = new ImageWrapper + { + Data = depthMap.Data(), + Rows = captureLineCount, + Cols = dataWidth, + Type = 5 + }; + ImageWrapper imgIntensity = new ImageWrapper + { + Data = intensityImage.Data(), + Rows = captureLineCount, + Cols = dataWidth, + Type = 0 + }; + result.Depth = imgDepth.Clone(); + result.Intensity = imgIntensity.Clone(); + + GC.KeepAlive(depthMap); + GC.KeepAlive(intensityImage); + return result; + } + + /* Discovers and connects multiple Mech-Eye 3D Laser Profilers for calibration. + * Ensures that all connected profilers are of the same model for calibration.*/ + public static Profiler FindAndConnectProfilerForCalibration() + { + Console.WriteLine("Find Mech-Eye 3D Laser Profilers...\n"); + List profilerInfoList = Profiler.DiscoverProfilers(); + + if (profilerInfoList == null || profilerInfoList.Count == 0) + { + Console.WriteLine("No Mech-Eye 3D Laser Profilers found.\n"); + return new Profiler(); + } + + for (int i = 0; i < profilerInfoList.Count; i++) + { + Console.WriteLine($"Mech-Eye 3D Laser Profiler index : {i}\n"); + MMind.Eye.Utils.PrintProfilerInfo(profilerInfoList[i]); + } + + string str = Console.ReadLine(); + int index = 0; + Console.WriteLine("Please enter the device index you want to choose as major profiler: "); + + if (Regex.IsMatch(str, @"^\d+$") && int.Parse(str) < profilerInfoList.Count) + { + index = int.Parse(str); + } + else + { + Console.WriteLine("Input invalid. Please enter the device index you want to connect (Automatically connect to Profiler 0.): "); + } + + // Connect to selected profilers + var profiler = new Profiler(); + + ErrorStatus status = profiler.Connect(profilerInfoList[index]); + if (!status.IsOK()) + MMind.Eye.Utils.ShowError(status); + return profiler; + } + + public static Mat WrapImage(ImageWrapper img) + { + DepthType depthType; + int channels = 1; + int elemSize; + + switch (img.Type) + { + case 0: // CV_8UC1 + depthType = DepthType.Cv8U; + elemSize = 1; + break; + + case 5: // CV_32FC1 + depthType = DepthType.Cv32F; + elemSize = 4; + break; + + default: + throw new NotSupportedException( + $"Unsupported image type: {img.Type}"); + } + + return new Mat( + img.Rows, + img.Cols, + depthType, + channels, + img.Data, + img.Cols * elemSize + ); + } + + private static bool CaptureImages(Profiler profilerOpt, out List profilerImages) + { + profilerImages = new List(); + while (true) + { + // Confirm capture with the user + if (!MMind.Eye.Utils.ConfirmCapture()) + { + profilerOpt.Disconnect(); + break; + } + else + profilerImages.Add(CaptureAsync(profilerOpt)); + } + return true; + } + + static int Main() + { + + // Set the target size + var targetSize = new TargetSize(); + while (true) + { + Console.WriteLine("\nEnter the target top length: "); + targetSize.TopLength = GetInputNumber(); + + Console.WriteLine("\nEnter the target bottom length: "); + targetSize.BottomLength = GetInputNumber(); + + Console.WriteLine("\nEnter the target height: "); + targetSize.Height = GetInputNumber(); + + // Show the input values for confirmation + Console.WriteLine("\nYou entered the following values:"); + Console.WriteLine($"Top Length: {targetSize.TopLength}"); + Console.WriteLine($"Bottom Length: {targetSize.BottomLength}"); + Console.WriteLine($"Height: {targetSize.Height}"); + + // Ask user if they want to continue or reinput + Console.Write("\nContinue with the process? (y to continue, any other key to reinput): "); + string confirm = Console.ReadLine(); + if (confirm == "y" || confirm == "Y") + { + break; + } + } + + // Choose the device for calibration + var profilerOpt = FindAndConnectProfilerForCalibration(); + + if (profilerOpt == null) + { + Console.WriteLine("No profilers connected."); + return -1; + } + + // Get the major device Info by retrieving user input + Console.WriteLine("\nGet the major deviceInfo"); + var majorDeviceInfo = GetDeviceInfo(profilerOpt); + + // Get the major profiler info + var majorProfilerInfo = new ProfilerInfo(); + var status = profilerOpt.GetProfilerInfo(ref majorProfilerInfo); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return -1; + } + + //Capture images for movement direction calibration + var profilerImages = new List(); + // Start to capture images for calibration + if (!CaptureImages(profilerOpt, out profilerImages) || profilerImages.Count() < 2) + { + Console.WriteLine("Failed to capture sufficient images for calibration.\n;"); + return -1; + } + + // Configure calibration parameters + var targetPoses = new List(); + var targetPose = new TargetPose(); + bool continuePoseProcess = false; + + while (!continuePoseProcess) + { + Console.WriteLine("\nEnter the distance between targets: "); + targetPose.TranslateDistance = GetInputNumber(); + + Console.WriteLine("\nEnter the rotation angle between targets:"); + targetPose.RotateAngleInDegree = GetInputNumber(); + + Console.WriteLine("\nEnter the rotation radius between targets: "); + targetPose.RotateRadius = GetInputNumber(); + + // Show the input values for confirmation + Console.WriteLine("\nYou entered the following values:"); + Console.WriteLine($"Distance: {targetPose.TranslateDistance}"); + Console.WriteLine($"Rotation Angle: {targetPose.RotateAngleInDegree}"); + Console.WriteLine($"Rotation Radius: {targetPose.RotateRadius}"); + + // Ask user if they want to continue or reinput + Console.Write("\nContinue with the process? (y to continue, any other key to reinput):"); + string choice = Console.ReadLine(); + continuePoseProcess = (choice?.ToLower() == "y"); + } + + // Set the calib mode + var calibMode = InputCalibType(); + + // Set the transform axis + var transformAxis = InputTargetTransformAxis(); + + // Set the translation/rotation axis parameters based on the calibration mode type + targetPose.Mode = calibMode; + + switch (calibMode) + { + case ProfilerCalibrationMode.Wide: + targetPose.TranslateAxis = (TargetTranslateAxis)((int)transformAxis); + targetPose.RotateAxis = TargetRotateAxis.NullAxis; + break; + + case ProfilerCalibrationMode.Angle: + targetPose.RotateAxis = (TargetRotateAxis)((int)transformAxis); + targetPose.TranslateAxis = TargetTranslateAxis.NullAxis; + break; + } + targetPoses.Add(targetPose); + + int moveAxis = InputMovementAxis(); + + Console.WriteLine("\n++++++++++++++++++++++Starting movement direction calibration+++++++++++++++++++++++++"); + + var calibInstance = new ProfilerCalibrationInterfaces(); + + calibInstance.SetCalibCameraModel(majorProfilerInfo.DeviceName); + + calibInstance.SetMajorDeviceInfo(majorDeviceInfo); + + calibInstance.SetCalibTargetSize(targetSize); + + calibInstance.SetCalibTargetPoses(targetPoses); + + var errorStatus = calibInstance.CalibrateSingleProfilerMoveDirection(profilerImages[0].Depth, profilerImages[1].Depth, moveAxis, out MoveDirCalibResult calibResult, default, false); + + if (!errorStatus.IsOK()) + { + PrintError(errorStatus); + return -1; + } + + Console.WriteLine("\nCalibration completed successfully."); + Console.WriteLine($"Movement direct vector is : {{ {calibResult.MoveVec.x}, {calibResult.MoveVec.y}, {calibResult.MoveVec.z} }}"); + + Point3f moveVec = new Point3f + { + X = calibResult.MoveVec.x, + Y = calibResult.MoveVec.y, + Z = calibResult.MoveVec.z + }; + + errorStatus = calibInstance.CorrectProfilerMoveDir(moveVec, profilerImages[0], out TransformedImageInfo correctedResult, default, false); + if (!errorStatus.IsOK()) + { + PrintError(errorStatus); + return -1; + } + + Console.WriteLine("\nDirection correction completed."); + Console.WriteLine($"Pixel offset to camera origin: [ {{ {correctedResult.PixelBias.x}, {correctedResult.PixelBias.y} }}(pixels)"); + + + double dx = -(double)correctedResult.PixelBias.x; + double dy = -(double)correctedResult.PixelBias.y; + + Mat translationMat = new Mat(2, 3, DepthType.Cv64F, 1); + translationMat.SetTo(new double[] + { + 1.0, 0.0, dx, + 0.0, 1.0, dy + }); + + Mat alignedDepth = new Mat(); + ImageWrapper depthWrapper = correctedResult.GetDepth(); + + Mat depthMat = new Mat( + depthWrapper.Rows, + depthWrapper.Cols, + DepthType.Cv32F, + 1, + depthWrapper.Data, + depthWrapper.Cols * sizeof(float) + ); + + System.Drawing.Size outSize = + new System.Drawing.Size(depthWrapper.Cols, depthWrapper.Rows); + + CvInvoke.WarpAffine( + depthMat, // IInputArray + alignedDepth, + translationMat, + outSize, // System.Drawing.Size + Inter.Nearest, + Warp.Default, + BorderType.Constant, + new Emgu.CV.Structure.MCvScalar(float.NaN) + ); + + //Save results for verification + using (Mat mat = WrapImage(profilerImages[0].Depth)) + { + CvInvoke.Imwrite("01_raw_depth.tiff", mat); + } + using (Mat mat = WrapImage(depthWrapper)) + { + CvInvoke.Imwrite("02_corrected_depth_with_offset.tiff", mat); + } + + CvInvoke.Imwrite("03_aligned_depth_for_stitching.tiff", alignedDepth); + + Console.WriteLine(@" + Demo completed successfully. + Saved results: + - 01_raw_depth.tiff + - 02_corrected_depth_with_offset.tiff + - 03_aligned_depth_for_stitching.tiff + "); + + return 0; + + } + +} + diff --git a/profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.csproj b/profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.csproj new file mode 100644 index 0000000..ba78cdc --- /dev/null +++ b/profiler/Calibration/MoveDirVecCalibration/MoveDirVecCalibration.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8} + Exe + MoveDirVecCalibration + MoveDirVecCalibration + v4.8 + 512 + true + true + + + x64 + true + full + false + $(SolutionDir)/Build_debug/$(AssemblyName) + DEBUG;TRACE + prompt + 4 + false + + + x64 + pdbonly + false + $(SolutionDir)/Build/$(AssemblyName) + TRACE + prompt + 4 + + + true + $(SolutionDir)/Build_debug/$(AssemblyName) + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + $(SolutionDir)/Build/$(AssemblyName) + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.7.0.5276 + + + 2.6.0 + + + + + + + \ No newline at end of file diff --git a/profiler/Calibration/MoveDirVecCalibration/README.md b/profiler/Calibration/MoveDirVecCalibration/README.md new file mode 100644 index 0000000..52cda36 --- /dev/null +++ b/profiler/Calibration/MoveDirVecCalibration/README.md @@ -0,0 +1,5 @@ +# MoveDirVecCalibration Sample + +With this sample, you can complete the calibration of the movement direction vector for a single laser profiler, obtain the calibrated movement direction vector, the corresponding reprojection error, and correction parameters for downstream processing (including depth maps and pixel offsets obtained from direction correction). The sample aims for engineering reproducibility and result acceptability, demonstrating a complete closed-loop process from acquisition to correction and back to the camera coordinate system. + +If you have any questions or have anything to share, feel free to post on the [Mech-Mind Online Community](https://community.mech-mind.com/). The community also contains a [specific category for development with Mech-Eye SDK](https://community.mech-mind.com/c/mech-eye-sdk-development/19). diff --git a/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.cs b/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.cs index 2f728ae..bf75b8c 100644 --- a/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.cs +++ b/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.cs @@ -1,4 +1,4 @@ -/* +/* With this sample, perform multi profiler calibration through. */ @@ -346,8 +346,8 @@ public static DeviceInfo GetDeviceInfo(Profiler profiler) Console.WriteLine("Please confirm the following device settings:"); Console.WriteLine("--------------------------------------------"); - Console.WriteLine($"1. X-Axis Resolution (um): {xResolution / 1000:F3}"); - Console.WriteLine($"2. Y-Axis Resolution (um): {yResolution / 1000:F3}"); + Console.WriteLine($"1. X-Axis Resolution (mm): {xResolution / 1000:F3}"); + Console.WriteLine($"2. Y-Axis Resolution (mm): {yResolution / 1000:F3}"); Console.WriteLine($"3. Downsampling Factor (X): {downsampleX}"); Console.WriteLine($"4. Downsampling Factor (Y): {downsampleY}"); Console.WriteLine($"5. Motion Direction Sign: {directionPositive}"); @@ -401,23 +401,29 @@ public static ProfilerImage CaptureAsync(Profiler profiler) if (profileBatch.CheckFlag(ProfileBatch.BatchFlag.Incomplete)) Console.WriteLine($"Part of the batch's data is lost, the number of valid profiles is: {profileBatch.ValidHeight()}."); + var depthMap = profileBatch.GetDepthMap(); + var intensityImage = profileBatch.GetIntensityImage(); + ProfilerImage result = new ProfilerImage(); ImageWrapper imgDepth = new ImageWrapper { - Data = profileBatch.GetDepthMap().Data(), + Data = depthMap.Data(), Rows = captureLineCount, Cols = dataWidth, Type = 5 }; ImageWrapper imgIntensity = new ImageWrapper { - Data = profileBatch.GetIntensityImage().Data(), + Data = intensityImage.Data(), Rows = captureLineCount, Cols = dataWidth, Type = 0 }; result.Depth = imgDepth.Clone(); result.Intensity = imgIntensity.Clone(); + + GC.KeepAlive(depthMap); + GC.KeepAlive(intensityImage); return result; } diff --git a/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.csproj b/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.csproj index 92b079d..b209090 100644 --- a/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.csproj +++ b/profiler/Calibration/MultipleProfilersCalibration/MultipleProfilersCalibration.csproj @@ -80,8 +80,8 @@ 4.7.0.5276 - - 2.5.2 + + 2.6.0 diff --git a/profiler/Calibration/WidthExpansionCalibration/App.config b/profiler/Calibration/WidthExpansionCalibration/App.config new file mode 100644 index 0000000..193aecc --- /dev/null +++ b/profiler/Calibration/WidthExpansionCalibration/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/profiler/Calibration/WidthExpansionCalibration/README.md b/profiler/Calibration/WidthExpansionCalibration/README.md new file mode 100644 index 0000000..fe883a3 --- /dev/null +++ b/profiler/Calibration/WidthExpansionCalibration/README.md @@ -0,0 +1,5 @@ +# WidthExpansionCalibration Sample + +This sample demonstrates width-expansion calibration and stitching for a single laser profiler. The calibration estimates horizontal expansion parameters using reference position biases, generates the stitching configuration, and outputs the final results along with corrected calibration parameters. + +If you have any questions or have anything to share, feel free to post on the [Mech-Mind Online Community](https://community.mech-mind.com/). The community also contains a [specific category for development with Mech-Eye SDK](https://community.mech-mind.com/c/mech-eye-sdk-development/19). diff --git a/profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.cs b/profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.cs new file mode 100644 index 0000000..29df1cc --- /dev/null +++ b/profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.cs @@ -0,0 +1,617 @@ +/* +With this sample, you can complete the calibration of the movement direction vector for a single laser profiler, obtain the calibrated movement direction vector, the corresponding reprojection error, and correction parameters for downstream processing (including depth maps and pixel offsets obtained from direction correction). The sample aims for engineering reproducibility and result acceptability, demonstrating a complete closed-loop process from acquisition to correction and back to the camera coordinate system. +*/ + +using System; +using MMind.Eye; +using Emgu.CV; +using Emgu.CV.CvEnum; +using System.Threading; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Linq; + + + +class WidthExpansionCalibration +{ + private const int CV_8UC1 = 0; + private const int CV_32FC1 = 5; + + public static T GetInputNumber() where T : IConvertible + { + while (true) + { + string input = Console.ReadLine(); + try + { + if (typeof(T) == typeof(bool)) + { + input = input.Trim().ToLower(); + if (input == "true" || input == "1") + return (T)Convert.ChangeType(true, typeof(T)); + if (input == "false" || input == "0") + return (T)Convert.ChangeType(false, typeof(T)); + throw new Exception(); + } + return (T)Convert.ChangeType(input, typeof(T)); + } + catch + { + Console.WriteLine($"Invalid input! Please enter a valid number."); + } + } + } + + // Set the calibration mode based on user input + public static ProfilerCalibrationMode InputCalibType() + { + while (true) + { + Console.WriteLine("\nEnter the number that represents the calibration types:\n1: Wide\n2: Angle"); + int input = GetInputNumber(); + switch (input) + { + case 1: return ProfilerCalibrationMode.Wide; + case 2: return ProfilerCalibrationMode.Angle; + default: Console.WriteLine("Invalid input! Please enter 1 or 2."); break; + } + } + } + + // Set the calibration mode based on user input + public static int InputWidthExpansionCalibType() + { + while (true) + { + Console.WriteLine("\nEnter the number that represents the movement axis:\n1: mmind::eye::WidthExpansionType::S\n2: mmind::eye::WidthExpansionType::Z\n3: mmind::eye::WidthExpansionType::Disorder"); + int input = GetInputNumber(); + return input; + } + } + + // Set the target transformation axis based on user input + public static MMind.Eye.TargetTranslateAxis InputTargetTransformAxis() + { + while (true) + { + Console.WriteLine("\nEnter the number that represents the transform axis:\n1: X\n2: Y"); + int input = GetInputNumber(); + switch (input) + { + case 1: return MMind.Eye.TargetTranslateAxis.X; + case 2: return MMind.Eye.TargetTranslateAxis.Y; + default: Console.WriteLine("Invalid input! Please enter 1 or 2."); break; + } + } + } + + // Print error messages when stitching fails + public static void PrintError(MultiProfilerErrorStatus errorStatus) + { + if (errorStatus == null) + { + Console.WriteLine("\nerrorStatus: null"); + return; + } + Console.WriteLine($"\nerrorStatus: {errorStatus.ErrorCode}"); + Console.WriteLine($"\nerrorDescription: {errorStatus.MultiProfilerErrorDescription}"); + Console.WriteLine($"\nerrorSource: {errorStatus.ErrorSource} {errorStatus.GroupID}"); + } + + // Acquire profile data from a profiler + public static bool AcquireProfileData(Profiler profiler, ref ProfileBatch totalBatch, int captureLineCount, int dataWidth, bool isSoftwareTrigger) + { + Console.WriteLine("Start data acquisition."); + ErrorStatus status = profiler.StartAcquisition(); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return false; + } + + if (isSoftwareTrigger) + { + status = profiler.TriggerSoftware(); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return false; + } + } + + totalBatch.Clear(); + totalBatch.Reserve((ulong)captureLineCount); + while (totalBatch.Height() < (ulong)captureLineCount) + { + ProfileBatch batch = new ProfileBatch((ulong)dataWidth); + status = profiler.RetrieveBatchData(ref batch); + if (status.IsOK()) + { + if (!totalBatch.Append(batch)) + break; + Thread.Sleep(200); + } + else + { + MMind.Eye.Utils.ShowError(status); + return false; + } + } + + Console.WriteLine("Stop data acquisition."); + status = profiler.StopAcquisition(); + if (!status.IsOK()) + MMind.Eye.Utils.ShowError(status); + return status.IsOK(); + } + + // Get device information and interact with the user for additional parameters + public static DeviceInfo GetDeviceInfo(Profiler profiler) + { + UserSet userSet = profiler.CurrentUserSet(); + ProfilerInfo profilerInfo = new ProfilerInfo(); + ErrorStatus status = profiler.GetProfilerInfo(ref profilerInfo); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + MMind.Eye.Utils.PrintProfilerInfo(profilerInfo); + + // Get X xResolution + double xResolution = 0; + status = userSet.GetFloatValue(MMind.Eye.PointCloudResolutions.XAxisResolution.Name, ref xResolution); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + + // Get Y Resolution + double yResolution = 0; + status = userSet.GetFloatValue(MMind.Eye.PointCloudResolutions.YResolution.Name, ref yResolution); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + + // get Profile ROI + ProfileROI roiValue = new ProfileROI(); + status = userSet.GetProfileRoiValue(MMind.Eye.ProfileROISettings.ROI.Name, ref roiValue); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return null; + } + + Console.WriteLine("\nEnter the downsampling interval in the X direction: "); + uint downsampleX = GetInputNumber(); + + Console.WriteLine("\nEnter the downsampling interval in the Y direction: "); + uint downsampleY = GetInputNumber(); + + Console.WriteLine("\nEnter the Camera motion direction: "); + bool directionPositive = GetInputNumber(); + + Console.WriteLine("Please confirm the following device settings:"); + Console.WriteLine("--------------------------------------------"); + Console.WriteLine($"1. X-Axis Resolution (mm): {xResolution / 1000:F3}"); + Console.WriteLine($"2. Y-Axis Resolution (mm): {yResolution / 1000:F3}"); + Console.WriteLine($"3. Downsampling Factor (X): {downsampleX}"); + Console.WriteLine($"4. Downsampling Factor (Y): {downsampleY}"); + Console.WriteLine($"5. Motion Direction Sign: {directionPositive}"); + Console.WriteLine($"6. ROI Size (Width , Height): ({roiValue.Width}, {roiValue.Height})"); + Console.WriteLine($"7. ROI Center (X,Y): ({roiValue.XAxisCenter}, 0)"); + Console.WriteLine("--------------------------------------------"); + + DeviceInfo deviceInfo = new DeviceInfo(); + deviceInfo.DX = (float)(xResolution / 1000); + deviceInfo.DY = (float)(yResolution / 1000); + deviceInfo.DownsampleX = downsampleX; + deviceInfo.DownsampleY = downsampleY; + deviceInfo.MoveDirSign = directionPositive; + deviceInfo.ROISize = new Point2f { X = (float)roiValue.Width, Y = (float)roiValue.Height }; + deviceInfo.ROICenter = new Point2f { X = (float)roiValue.XAxisCenter, Y = 0 }; + return deviceInfo; + } + + // Asynchronously capture images from a profiler + public static ProfilerImage CaptureAsync(Profiler profiler) + { + ProfilerInfo profilerInfo = new ProfilerInfo(); + MMind.Eye.Utils.ShowError(profiler.GetProfilerInfo(ref profilerInfo)); + + // Select "calib" user set to capture image. + string calibSetting = "calib"; + UserSetManager userSetManager = profiler.UserSetManager(); + string successMessage = $"Set current set as the \"{calibSetting}\" user set."; + MMind.Eye.Utils.ShowError(userSetManager.SelectUserSet(calibSetting), successMessage); + + UserSet userSet = profiler.CurrentUserSet(); + + int dataWidth = 0; + MMind.Eye.Utils.ShowError(userSet.GetIntValue(MMind.Eye.ScanSettings.DataPointsPerProfile.Name, ref dataWidth)); + int captureLineCount = 0; + userSet.GetIntValue(MMind.Eye.ScanSettings.ScanLineCount.Name, ref captureLineCount); + + ProfileBatch profileBatch = new ProfileBatch((ulong)dataWidth); + + int dataAcquisitionTriggerSource = 0; + MMind.Eye.Utils.ShowError(userSet.GetEnumValue(MMind.Eye.TriggerSettings.DataAcquisitionTriggerSource.Name, ref dataAcquisitionTriggerSource)); + + //// Adjust the "Trigger Delay" appropriately to avoid interference between devices and ensure + /// optimal imaging performance. + // showError(userSet.setEnumValue(mmind::eye::trigger_settings::TriggerDelay::name, 100)); + bool isSoftwareTrigger = dataAcquisitionTriggerSource == (int)MMind.Eye.TriggerSettings.DataAcquisitionTriggerSource.Value.Software; + + if (!AcquireProfileData(profiler, ref profileBatch, captureLineCount, dataWidth, isSoftwareTrigger)) + return null; + + if (profileBatch.CheckFlag(ProfileBatch.BatchFlag.Incomplete)) + Console.WriteLine($"Part of the batch's data is lost, the number of valid profiles is: {profileBatch.ValidHeight()}."); + + var depthMap = profileBatch.GetDepthMap(); + var intensityImage = profileBatch.GetIntensityImage(); + + ProfilerImage result = new ProfilerImage(); + ImageWrapper imgDepth = new ImageWrapper + { + Data = depthMap.Data(), + Rows = captureLineCount, + Cols = dataWidth, + Type = 5 + }; + ImageWrapper imgIntensity = new ImageWrapper + { + Data = intensityImage.Data(), + Rows = captureLineCount, + Cols = dataWidth, + Type = 0 + }; + result.Depth = imgDepth.Clone(); + result.Intensity = imgIntensity.Clone(); + + GC.KeepAlive(depthMap); + GC.KeepAlive(intensityImage); + return result; + } + + /* Discovers and connects multiple Mech-Eye 3D Laser Profilers for calibration. + * Ensures that all connected profilers are of the same model for calibration.*/ + public static Profiler FindAndConnectProfilerForCalibration() + { + Console.WriteLine("Find Mech-Eye 3D Laser Profilers...\n"); + List profilerInfoList = Profiler.DiscoverProfilers(); + + if (profilerInfoList == null || profilerInfoList.Count == 0) + { + Console.WriteLine("No Mech-Eye 3D Laser Profilers found.\n"); + return new Profiler(); + } + + for (int i = 0; i < profilerInfoList.Count; i++) + { + Console.WriteLine($"Mech-Eye 3D Laser Profiler index : {i}\n"); + MMind.Eye.Utils.PrintProfilerInfo(profilerInfoList[i]); + } + + string str = Console.ReadLine(); + int index = 0; + Console.WriteLine("Please enter the device index you want to choose as major profiler: "); + + if (Regex.IsMatch(str, @"^\d+$") && int.Parse(str) < profilerInfoList.Count) + { + index = int.Parse(str); + } + else + { + Console.WriteLine("Input invalid. Please enter the device index you want to connect (Automatically connect to Profiler 0.): "); + } + + // Connect to selected profilers + var profiler = new Profiler(); + + ErrorStatus status = profiler.Connect(profilerInfoList[index]); + if (!status.IsOK()) + MMind.Eye.Utils.ShowError(status); + return profiler; + } + + public static Mat WrapImage(ImageWrapper img) + { + DepthType depthType; + int channels = 1; + int elemSize; + + switch (img.Type) + { + case 0: // CV_8UC1 + depthType = DepthType.Cv8U; + elemSize = 1; + break; + + case 5: // CV_32FC1 + depthType = DepthType.Cv32F; + elemSize = 4; + break; + + default: + throw new NotSupportedException( + $"Unsupported image type: {img.Type}"); + } + + return new Mat( + img.Rows, + img.Cols, + depthType, + channels, + img.Data, + img.Cols * elemSize + ); + } + + private static bool CaptureImages(Profiler profilerOpt, out List profilerImages, out ProfilerImage firstImage) + { + profilerImages = new List(); + firstImage = new ProfilerImage(); + bool flag = true; + while (true) + { + if (!MMind.Eye.Utils.ConfirmCapture()) + { + profilerOpt.Disconnect(); + break; + } + if (flag == true) + { + firstImage = CaptureAsync(profilerOpt); + flag = false; + } + else + profilerImages.Add(CaptureAsync(profilerOpt)); + } + return true; + } + static int Main() + { + + // Set the target size + var targetSize = new TargetSize(); + while (true) + { + Console.WriteLine("\nInput target geometry parameters (unit: mm)"); + Console.WriteLine("\nEnter the target top length: "); + targetSize.TopLength = GetInputNumber(); + + Console.WriteLine("\nEnter the target bottom length: "); + targetSize.BottomLength = GetInputNumber(); + + Console.WriteLine("\nEnter the target height: "); + targetSize.Height = GetInputNumber(); + + // Show the input values for confirmation + Console.WriteLine("\nYou entered the following values:"); + Console.WriteLine($"Top Length: {targetSize.TopLength}"); + Console.WriteLine($"Bottom Length: {targetSize.BottomLength}"); + Console.WriteLine($"Height: {targetSize.Height}"); + + // Ask user if they want to continue or reinput + Console.Write("\nContinue with the process? (y to continue, any other key to reinput): "); + string confirm = Console.ReadLine(); + if (confirm == "y" || confirm == "Y") + { + break; + } + } + + // Choose the device for calibration + var profilerOpt = FindAndConnectProfilerForCalibration(); + + if (profilerOpt == null) + { + Console.WriteLine("No profilers connected."); + return -1; + } + + // Get the major device Info by retrieving user input + Console.WriteLine("\nGet the major deviceInfo"); + var majorDeviceInfo = GetDeviceInfo(profilerOpt); + + // Get the major profiler info + var majorProfilerInfo = new ProfilerInfo(); + var status = profilerOpt.GetProfilerInfo(ref majorProfilerInfo); + if (!status.IsOK()) + { + MMind.Eye.Utils.ShowError(status); + return -1; + } + + // Configure calibration parameters + var targetPoses = new List(); + var targetPose = new TargetPose(); + bool continuePoseProcess = false; + + while (!continuePoseProcess) + { + Console.WriteLine("\nEnter the distance between targets: "); + targetPose.TranslateDistance = GetInputNumber(); + + Console.WriteLine("\nEnter the rotation angle between targets:"); + targetPose.RotateAngleInDegree = GetInputNumber(); + + Console.WriteLine("\nEnter the rotation radius between targets: "); + targetPose.RotateRadius = GetInputNumber(); + + // Show the input values for confirmation + Console.WriteLine("\nYou entered the following values:"); + Console.WriteLine($"Distance: {targetPose.TranslateDistance}"); + Console.WriteLine($"Rotation Angle: {targetPose.RotateAngleInDegree}"); + Console.WriteLine($"Rotation Radius: {targetPose.RotateRadius}"); + + // Ask user if they want to continue or reinput + Console.Write("\nContinue with the process? (y to continue, any other key to reinput):"); + string choice = Console.ReadLine(); + continuePoseProcess = (choice?.ToLower() == "y"); + } + + // Set the calib mode + var calibMode = InputCalibType(); + + // Set the transform axis + var transformAxis = InputTargetTransformAxis(); + + // Set the translation/rotation axis parameters based on the calibration mode type + targetPose.Mode = calibMode; + + switch (calibMode) + { + case ProfilerCalibrationMode.Wide: + targetPose.TranslateAxis = (TargetTranslateAxis)((int)transformAxis); + targetPose.RotateAxis = TargetRotateAxis.NullAxis; + break; + + case ProfilerCalibrationMode.Angle: + targetPose.RotateAxis = (TargetRotateAxis)((int)transformAxis); + targetPose.TranslateAxis = TargetTranslateAxis.NullAxis; + break; + } + targetPoses.Add(targetPose); + + int widthExpansionType = InputWidthExpansionCalibType(); + + var refPositionBiases = new List(); + + Console.WriteLine("\n++++++++++++++++++++++Starting calibration+++++++++++++++++++++++++"); + + var minorImages = new List(); + + // Start to capture images for calibration + if (!CaptureImages(profilerOpt, out minorImages, out ProfilerImage majorImage)) + { + Console.WriteLine("Failed to capture sufficient images for calibration.\n;"); + return -1; + } + + for (int i = 0; i < minorImages.Count(); i++) + { + RefPositionBias bias = new RefPositionBias(); + bias.GroupID = (uint)i; + Console.WriteLine("\nInput reference position bias X(mm): "); + float a = GetInputNumber(); + Console.WriteLine("\nInput reference position bias Y (mm): "); + float b = GetInputNumber(); + Console.WriteLine("\nInput reference position bias Z (mm): "); + float c = GetInputNumber(); + bias.Bias = (a, b, c); + refPositionBiases.Add(bias); + } + + var calibInstance = new ProfilerCalibrationInterfaces(); + + calibInstance.SetCalibCameraModel(majorProfilerInfo.DeviceName); + + calibInstance.SetMajorDeviceInfo(majorDeviceInfo); + + calibInstance.SetCalibTargetSize(targetSize); + + calibInstance.SetCalibTargetPoses(targetPoses); + + var errorStatus = calibInstance.CalibrateSingleProfilerWidthExpansion(majorImage.Depth, minorImages[0].Depth, refPositionBiases, out List results, default, false); + if (!errorStatus.IsOK()) + { + PrintError(errorStatus); + return -1; + } + + Console.WriteLine("\nCalibration completed successfully."); + + // saveCalibFiles + string filePath; + while (true) + { + Console.Write("Enter the path to save the calibration files (please use English characters for " + + "the path): "); + + filePath = Console.ReadLine(); + + if (string.Equals(filePath, "q", StringComparison.OrdinalIgnoreCase) || + string.Equals(filePath, "exit", StringComparison.OrdinalIgnoreCase)) + { + Console.WriteLine("The user has exited the program."); + return 0; + } + + if (string.IsNullOrEmpty(filePath)) + { + if (filePath == null) + { + Console.WriteLine("The filePath is not set."); + } + else if (filePath.Length == 0) + { + Console.WriteLine("The filePath is empty."); + } + continue; + } + break; + } + + bool saveSuccess = calibInstance.SaveCalibFiles(true, filePath); + if (!saveSuccess) + { + Console.WriteLine($"Error: Failed to save calibration files! Please ensure the target folder exists at {filePath} and you have write permissions."); + return -1; + } + + Console.WriteLine($"Files saved successfully. Path: {filePath}"); + + + // Optional stitching verification + Console.WriteLine("\nProceed with stitching verification? (y/Y to continue): "); + string option; + option = Console.ReadLine(); + + if (option == "y" || option == "Y") + { + FusionResult fusionResult = new FusionResult(); + + ImageInfo majorImageInfo = new ImageInfo(); + majorImageInfo.SetProfilerImage(majorImage); + + var minorImageInfos = new List(); + for (int i = 0; i < minorImages.Count(); ++i) + { + ImageInfo info = new ImageInfo(); + info.GroupID = (uint)i; + info.SetProfilerImage(minorImages[i]); + minorImageInfos.Add(info); + } + errorStatus = calibInstance.StitchProfilerWidthExpansion(majorImageInfo, minorImageInfos, widthExpansionType, out fusionResult, results, true); + if (!errorStatus.IsOK()) + { + PrintError(errorStatus); + return -1; + } + Console.WriteLine("Stitching verification succeeded.\n"); + Console.WriteLine("\nSave refined calibration files? (y/Y to save): "); + option = Console.ReadLine(); + if ((option == "y" || option == "Y") && !calibInstance.SaveCalibFiles(false, filePath)) + { + Console.WriteLine("Error: Failed to save refined calibration files.\n"); + return -1; + } + + using (Mat mat = WrapImage(fusionResult.CombinedImage.Depth)) + { + CvInvoke.Imwrite(filePath + "./fusionResult.tiff", mat); + } + } + return 0; + + } +} + diff --git a/profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.csproj b/profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.csproj new file mode 100644 index 0000000..221f10b --- /dev/null +++ b/profiler/Calibration/WidthExpansionCalibration/WidthExpansionCalibration.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {74083F54-7E84-4854-8CA3-4496A9698023} + Exe + WidthExpansionCalibration + WidthExpansionCalibration + v4.8 + 512 + true + true + + + x64 + true + full + false + $(SolutionDir)/Build_debug/$(AssemblyName) + DEBUG;TRACE + prompt + 4 + false + + + x64 + pdbonly + true + $(SolutionDir)/Build/$(AssemblyName) + TRACE + prompt + 4 + + + true + $(SolutionDir)/Build_debug/$(AssemblyName) + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + $(SolutionDir)/Build/$(AssemblyName) + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + + + + + + + + + + + + + + + + + + + + + + + + 4.7.0.5276 + + + 2.6.0 + + + + + + + \ No newline at end of file diff --git a/profiler/MechEyeCSharpSamples.sln b/profiler/MechEyeCSharpSamples.sln index ffb1323..1090b91 100644 --- a/profiler/MechEyeCSharpSamples.sln +++ b/profiler/MechEyeCSharpSamples.sln @@ -39,6 +39,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WarmUp", "Advanced\WarmUp\W EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleProfilersCalibration", "Calibration\MultipleProfilersCalibration\MultipleProfilersCalibration.csproj", "{A85A01FB-FCBF-41F1-8CD7-8B28A3CEE16C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoveDirVecCalibration", "Calibration\MoveDirVecCalibration\MoveDirVecCalibration.csproj", "{9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WidthExpansionCalibration", "Calibration\WidthExpansionCalibration\WidthExpansionCalibration.csproj", "{74083F54-7E84-4854-8CA3-4496A9698023}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -191,6 +195,22 @@ Global {A85A01FB-FCBF-41F1-8CD7-8B28A3CEE16C}.Release|Any CPU.Build.0 = Release|Any CPU {A85A01FB-FCBF-41F1-8CD7-8B28A3CEE16C}.Release|x64.ActiveCfg = Release|x64 {A85A01FB-FCBF-41F1-8CD7-8B28A3CEE16C}.Release|x64.Build.0 = Release|x64 + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Debug|x64.ActiveCfg = Debug|x64 + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Debug|x64.Build.0 = Debug|x64 + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Release|Any CPU.Build.0 = Release|Any CPU + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Release|x64.ActiveCfg = Release|x64 + {9B8EB0FF-39DF-4004-9473-DFEE998D1BB8}.Release|x64.Build.0 = Release|x64 + {74083F54-7E84-4854-8CA3-4496A9698023}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74083F54-7E84-4854-8CA3-4496A9698023}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74083F54-7E84-4854-8CA3-4496A9698023}.Debug|x64.ActiveCfg = Debug|x64 + {74083F54-7E84-4854-8CA3-4496A9698023}.Debug|x64.Build.0 = Debug|x64 + {74083F54-7E84-4854-8CA3-4496A9698023}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74083F54-7E84-4854-8CA3-4496A9698023}.Release|Any CPU.Build.0 = Release|Any CPU + {74083F54-7E84-4854-8CA3-4496A9698023}.Release|x64.ActiveCfg = Release|x64 + {74083F54-7E84-4854-8CA3-4496A9698023}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/profiler/README.md b/profiler/README.md index a3a9f09..e46d7d7 100644 --- a/profiler/README.md +++ b/profiler/README.md @@ -17,18 +17,18 @@ The samples marked with `(OpenCV)` require [Emgu.CV.runtime.windows](https://www * **Basic** * [TriggerWithSoftwareAndFixedRate](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Basic/TriggerWithSoftwareAndFixedRate) `(OpenCV)` - Trigger data acquisition with signals input from software, trigger line scans at a fixed rate, and then retrieve and save the acquired data. + Trigger data acquisition with the software + fixed rate method, and then retrieve and save the acquired data. * [TriggerWithExternalDeviceAndFixedRate](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Basic/TriggerWithExternalDeviceAndFixedRate) `(OpenCV)` - Trigger data acquisition with signals input from the external device, trigger line scans at a fixed rate, and then retrieve and save the acquired data. + Trigger data acquisition with the external + fixed rate method, and then retrieve and save the acquired data. * [TriggerWithSoftwareAndEncoder](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Basic/TriggerWithSoftwareAndEncoder) `(OpenCV)` - Trigger data acquisition with signals input from software, trigger line scans with signals input from the encoder, and then retrieve and save the acquired data. + Trigger data acquisition with the software + encoder method, and then retrieve and save the acquired data. * [TriggerWithExternalDeviceAndEncoder](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Basic/TriggerWithExternalDeviceAndEncoder) `(OpenCV)` - Trigger data acquisition with signals input from the external device, trigger line scans with signals input from the encoder, and then retrieve and save the acquired data. + Trigger data acquisition with the external + encoder method, and then retrieve and save the acquired data. * [TriggerNonStopAcquisition](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Basic/TriggerNonStopAcquisition) `(OpenCV)` - Trigger non-stop acquisition, and then retrieve and save the acquired data. + Trigger a continuous scan of the target object, and then retrieve and save the acquired data. * **Advanced** * [TriggerMultipleProfilersSimultaneously](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Advanced/TriggerMultipleProfilersSimultaneously) `(OpenCV)` - Trigger multiple laser profilers to acquire data asynchronously and retrieve the acquired data. + Trigger multiple laser profilers to acquire data asynchronously, and then retrieve and save the acquired data. * [BlindSpotFiltering](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Advanced/BlindSpotFiltering) `(OpenCV)` Detect and remove the false data caused by blind spots and obtain the filtered profile data. * [NoiseRemoval](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Advanced/NoiseRemoval) `(OpenCV)` @@ -41,6 +41,8 @@ The samples marked with `(OpenCV)` require [Emgu.CV.runtime.windows](https://www Define and register the callback function for monitoring laser profiler events. * [UseVirtualDevice](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Advanced/UseVirtualDevice) `(OpenCV)` Acquire the profile data stored in a virtual device, generate the intensity image and depth map, and save the images. + * [WarmUp](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Advanced/WarmUp) `(OpenCV)` + Warm up the device. * **Util** * [RenderDepthMap](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Util/RenderDepthMap) `(OpenCV)` Obtain and save the depth map rendered with the jet color scheme. @@ -51,8 +53,12 @@ The samples marked with `(OpenCV)` require [Emgu.CV.runtime.windows](https://www * [HandleNanAndNegativeInDepth](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Util/HandleNanAndNegativeInDepth) `(OpenCV)` Trigger data acquisition and handle NaN and negative values in depth data. * **Calibration** + * [MoveDirVecCalibration](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Calibration/MoveDirVecCalibration) `(OpenCV)` + Calibrate the movement direction vector for a single laser profiler, and output calibration results and alignment parameters for subsequent stitching. * [MultipleProfilersCalibration](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Calibration/MultipleProfilersCalibration) `(OpenCV)` Calibrate multiple profilers that simultaneously scan the same target object, and output the calibration results and errors, stitching results, the stitched depth map, and the stitched point cloud. + * [WidthExpansionCalibration](https://github.com/MechMindRobotics/mecheye_csharp_samples/tree/master/profiler/Calibration/WidthExpansionCalibration) `(OpenCV)` + Perform width-expansion calibration and stitching for a single laser profiler, and output calibration results and stitching results. ## Build the Samples diff --git a/profiler/Util/HandleNanAndNegativeInDepth/HandleNanAndNegativeInDepth.csproj b/profiler/Util/HandleNanAndNegativeInDepth/HandleNanAndNegativeInDepth.csproj index 89e9a7d..47fe144 100644 --- a/profiler/Util/HandleNanAndNegativeInDepth/HandleNanAndNegativeInDepth.csproj +++ b/profiler/Util/HandleNanAndNegativeInDepth/HandleNanAndNegativeInDepth.csproj @@ -79,7 +79,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Util/ManageUserSets/ManageUserSets.csproj b/profiler/Util/ManageUserSets/ManageUserSets.csproj index 7cc950d..86233dc 100644 --- a/profiler/Util/ManageUserSets/ManageUserSets.csproj +++ b/profiler/Util/ManageUserSets/ManageUserSets.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Util/PrintProfilerStatus/PrintProfilerStatus.csproj b/profiler/Util/PrintProfilerStatus/PrintProfilerStatus.csproj index b2625b5..2753085 100644 --- a/profiler/Util/PrintProfilerStatus/PrintProfilerStatus.csproj +++ b/profiler/Util/PrintProfilerStatus/PrintProfilerStatus.csproj @@ -82,7 +82,7 @@ - 2.5.2 + 2.6.0 diff --git a/profiler/Util/RenderDepthMap/RenderDepthMap.csproj b/profiler/Util/RenderDepthMap/RenderDepthMap.csproj index 381c07d..7a12989 100644 --- a/profiler/Util/RenderDepthMap/RenderDepthMap.csproj +++ b/profiler/Util/RenderDepthMap/RenderDepthMap.csproj @@ -79,7 +79,7 @@ - 2.5.2 + 2.6.0