Click here to show toolbars of the Web Online Help System: show toolbars |
//***************************************************************************************/ // // File name: Simple3dBinPicking.cpp // Location: See Matrox Example Launcher in the MIL Control Center // // // Synopsis: This program contains an example of simple 3D bin picking // by combining a 2D Model Finder and a 3D alignment. // // Copyright (C) Matrox Electronic Systems Ltd., 1992-2016. // All Rights Reserved //***************************************************************************************/ #include <mil.h> #include <math.h> #include <stdlib.h> #include <vector> //**************************************************************************** // Example description. //**************************************************************************** void PrintHeader() { MosPrintf(MIL_TEXT("[EXAMPLE NAME]\n")); MosPrintf(MIL_TEXT("Simple3dBinPicking\n\n")); MosPrintf(MIL_TEXT("[SYNOPSIS]\n")); MosPrintf(MIL_TEXT("This example shows how to combine 2D Model Finder and \n")); MosPrintf(MIL_TEXT("3D alignment to estimate the pose of 3D objects stacked \n")); MosPrintf(MIL_TEXT("with minor variations in pitch and roll. \n\n")); MosPrintf(MIL_TEXT("[MODULES USED]\n")); MosPrintf(MIL_TEXT("Modules used: 3dMap, Geometric Model Finder, Buffer, \n") MIL_TEXT("Calibration, Display, Graphics, Image Processing. \n\n")); } // Enumerator to index model and scene objects (values must not change). enum {eModel = 0, eScene = 1}; // File names of the point clouds acquired from a 3D device such as a Gocator 3110 from LMI Technologies static const MIL_INT NUM_SCENE_SCANS = 3; static const MIL_TEXT_CHAR* const FILE_POINT_CLOUD[NUM_SCENE_SCANS + 1] = {M_IMAGE_PATH MIL_TEXT("Simple3dBinPicking/3dPlugCloudModel.ply" ), // Equivalent index: eModel (0) M_IMAGE_PATH MIL_TEXT("Simple3dBinPicking/BinCloudScene_0.ply" ), // Equivalent index: eScene + 0 (1) M_IMAGE_PATH MIL_TEXT("Simple3dBinPicking/BinCloudScene_1.ply" ), // Equivalent index: eScene + 1 (2) M_IMAGE_PATH MIL_TEXT("Simple3dBinPicking/BinCloudScene_2.ply" )}; // Equivalent index: eScene + 2 (3) #define MAX_STRING_SIZE 256L // Maximum number of characters a string can have. // Set this constant to 1 if the example should run without live grabbing // with a third-party 3D scanner; in this case, 3D point cloud data will // be loaded from PLY files. Otherwise, setting this constant to 0, the // user must provide the code to acquire the data from an installed 3D // scanner. See function 'AcquirePointCloud()' for more details. #define STANDALONE_DEMO 1 // Depth map parameters. static const MIL_INT DEPTHMAP_SIZE_X = 300; // (pixels) static const MIL_INT DEPTHMAP_SIZE_Y = 480; // (pixels) static const MIL_INT DEPTHMAP_NUM_VALUES = 65536; // 16 bits image (2^16) static const MIL_DOUBLE DEPTHMAP_MISSING_DATA = DEPTHMAP_NUM_VALUES-1; // Numeric value of missing depth-map data. // 3D scanner field of view, excluding the floor. static const MIL_DOUBLE SCANNER_FOV_MIN_X = -44.0; // (mm) static const MIL_DOUBLE SCANNER_FOV_MIN_Y = -80.0; // (mm) static const MIL_DOUBLE SCANNER_FOV_MIN_Z = -6.0; // (mm) static const MIL_DOUBLE SCANNER_FOV_MAX_X = 50.0; // (mm) static const MIL_DOUBLE SCANNER_FOV_MAX_Y = 80.0; // (mm) static const MIL_DOUBLE SCANNER_FOV_MAX_Z = -60.0; // (mm) // ROI margins to add to model's bounding box. static const MIL_DOUBLE MODEL_ROI_MARGIN_X = 5.0; // (mm) static const MIL_DOUBLE MODEL_ROI_MARGIN_Y = 5.0; // (mm) static const MIL_DOUBLE MODEL_ROI_MARGIN_Z = 20.0; // (mm) // 2d Model Finder parameters. static const MIL_DOUBLE FINDER_ACCEPTANCE = 50.0; // (%) // 2d Model Finder graphic colors. #define FOUND_OCCURRENCES_COLOR M_RGB888(192, 0, 0) #define SELECTED_OCCURRENCE_COLOR M_RGB888(0, 255, 0) // 3D alignment parameters. static const MIL_INT ALIGN_DECIMATION_STEP_MODEL = 4; // Corresponds to a decimation factor of 4*4=16. static const MIL_INT ALIGN_DECIMATION_STEP_SCENE = 4; // Corresponds to a decimation factor of 4*4=16. static const MIL_DOUBLE ALIGN_MODEL_OVERLAP = 90.0; // (%) static const MIL_INT ALIGN_MAX_ITERATIONS = 50; static const MIL_INT ALIGN_ERROR_MINIMIZATION_METRIC = M_POINT_TO_POINT; // Structure grouping the six components of a 3D pose. struct SPose { MIL_DOUBLE Tx, Ty, Tz, Rx, Ry, Rz; }; // Structure defining a 3D box and its corresponding 2d ROI in a depth-map. struct SBox { MIL_DOUBLE MinX, MinY, MinZ, MaxX, MaxY, MaxZ; // 3D bounding intervals in each dimension. MIL_INT OffsetX, OffsetY, SizeX, SizeY; // 2d ROI in the depth-map. }; // Utility function. void CropPointCloudToBox(MIL_ID MilPtCldCtn); void DefineModelRoiBox(MIL_ID MilPtCldCtn, MIL_ID MilDepthMap, SBox& ModelRoiBox); void MapDynamicRangeTo8Bits(MIL_ID MilSystem, MIL_ID MilScrImage, MIL_ID MilTgtImage); void AcquirePointCloud(MIL_ID MilPtCldCtn, MIL_INT Index); void RemoveFixture(MIL_ID Id); void GetPose(MIL_ID PtCldCtn, MIL_INT64 TargetCoordinateSystem, MIL_INT64 ReferenceCoordinateSystem, SPose& Pose); bool FindPrealignmentWithTopFoundOccurrence(MIL_ID MilSystem, MIL_ID MilPtCldCtn[], MIL_DOUBLE ModelMeanElevation, MIL_ID MilDepthMap[], MIL_ID MilFinderFixturingOffset, MIL_ID MilFinderResult, MIL_ID MilPrealignmentMatrix, MIL_INT* pTopOccIdx); void ExtractAlignedDepthMaps(MIL_ID MilSystem, MIL_ID MilPtCldCtn[], MIL_ID MilDepthMap[], MIL_ID MilAlignmentResult, SPose& AlignmentPose); bool AlignmentCriterionReached(MIL_INT64 AlignmentStatus); void DisplayAlignment2d(MIL_ID MilDepthMap[], MIL_ID MilGraphicList, SBox ModelBox); bool CheckForRequiredMILFile(MIL_CONST_TEXT_PTR FileName); // Preprocessor switch to enable a 3D display. #if M_MIL_USE_WINDOWS && !M_MIL_USE_CE && !M_MIL_USE_RT #define ENABLE_DISPLAY_3D 1 #else #define ENABLE_DISPLAY_3D 0 #endif #if ENABLE_DISPLAY_3D #include <MdispD3D.h> // 3D display parameters. static const MIL_INT DISPLAY_3D_SIZE_X = 640; // (pixels) static const MIL_INT DISPLAY_3D_SIZE_Y = 480; // (pixels) static const MIL_DOUBLE DISPLAY_3D_ROTATE = MD3D_FALSE; // MD3D_FALSE: do not rotate the display. static const MIL_DOUBLE DISPLAY_3D_POINT = MD3D_ENABLE; // MD3D_ENABLE: display points. static const MIL_DOUBLE DISPLAY_3D_LOOK_AT_X = 0.0; // (mm) static const MIL_DOUBLE DISPLAY_3D_LOOK_AT_Y = 0.0; // (mm) static const MIL_DOUBLE DISPLAY_3D_LOOK_AT_Z = 0.0; // (mm) static const MIL_DOUBLE DISPLAY_3D_EYE_THETA = 45.0; // (deg) static const MIL_DOUBLE DISPLAY_3D_EYE_PHI = 45.0; // (deg) static const MIL_DOUBLE DISPLAY_3D_EYE_DIST = 180.0; // (mm) void Init3dDisplay(MIL_DISP_D3D_HANDLE MilDispD3D); void Print3dDisplayHelp(); void DisplayPointCloud3d(MIL_ID MilSystem, MIL_DISP_D3D_HANDLE& MilDispD3D, MIL_ID MilDepthMap); void DisplayAlignment3d(MIL_ID MilSystem, MIL_DISP_D3D_HANDLE& MilDispD3D, MIL_ID MilDepthMap[]); #endif //***************************************************************************** // Main. //***************************************************************************** int MosMain(void) { // Print example information in console. PrintHeader(); //-------------------------------------------------------------------------- // Allocate MIL objects. MIL_ID MilApplication; // Application identifier. MIL_ID MilSystem; // System identifier. MIL_ID MilDisplay; // Display for model and object depth maps, and defects distance map. MIL_ID MilGraphicList; // Graphic list in which to draw. MIL_ID MilPtCldCtn[2]; // Model and scene point cloud containers. MIL_ID MilDepthMap[2]; // Model and scene depth maps. MIL_DOUBLE ModelMeanElevation; // Model's mean elevation computed in depth-map. SBox ModelRoiBox; // Model's 3D bounding box and 2d ROI. MIL_ID MilFinderImage[2]; // Images used by model finder: the model and the scene (target). MIL_ID MilFinderContext; // Model finder context. MIL_ID MilFinderFixturingOffset; // Fixturing offset between model's reference point and world's origin. MIL_ID MilFinderResult; // Model finder result. MIL_INT TopOccurrenceIdx; // Index of the found occurrence of top of the stack. MIL_ID MilAlignmentContext; // Pairwise alignment context. MIL_ID MilAlignmentResult; // Pairwise alignment result. MIL_ID MilPrealignmentMatrix; // Prealignment homogeneous matrix array. MIL_INT64 AlignmentStatus; // Status of 3D alignment. SPose AlignmentPose; // The six components of the 3D pose found with 3D alignment. #if ENABLE_DISPLAY_3D MIL_DISP_D3D_HANDLE MilDispD3D = M_NULL; #endif // Allocate application and system. MappAlloc(M_NULL, M_DEFAULT, &MilApplication); //Check for required file. if (!CheckForRequiredMILFile(FILE_POINT_CLOUD[0])) { MappFree(MilApplication); return -1; } MsysAlloc(M_DEFAULT, M_SYSTEM_HOST, M_DEFAULT, M_DEFAULT, &MilSystem); // Allocate and initialize the display. MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_WINDOWED, &MilDisplay); MgraAllocList(MilSystem, M_DEFAULT, &MilGraphicList); MdispControl(MilDisplay, M_ASSOCIATED_GRAPHIC_LIST_ID, MilGraphicList); MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n")); MosGetch(); //-------------------------------------------------------------------------- // Import model's point cloud and generate its 16 bits depth-map. // Allocate the model's 3D point cloud container. M3dmapAllocResult(MilSystem, M_POINT_CLOUD_CONTAINER, M_DEFAULT, &MilPtCldCtn[eModel]); // Acquire a point cloud representing the top-view of a single object, defined as the model. AcquirePointCloud(MilPtCldCtn[eModel], eModel); // Allocate the model's depth-map. MbufAlloc2d(MilSystem, DEPTHMAP_SIZE_X, DEPTHMAP_SIZE_Y, M_UNSIGNED + 16, M_IMAGE + M_DISP + M_PROC, &MilDepthMap[eModel]); // Set the model's extraction box to the scanner field of view, but removing the floor. M3dmapSetBox(MilPtCldCtn[eModel], M_EXTRACTION_BOX, M_BOTH_CORNERS, SCANNER_FOV_MIN_X, SCANNER_FOV_MIN_Y, SCANNER_FOV_MIN_Z, SCANNER_FOV_MAX_X, SCANNER_FOV_MAX_Y, SCANNER_FOV_MAX_Z); // Crop the point cloud to the extraction box, defined as the // scanner field of view, rejecting the floor. CropPointCloudToBox(MilPtCldCtn[eModel]); // Set depth-map's extraction overlap property such that points on top // overwrites points below. M3dmapControl(MilPtCldCtn[eModel], M_GENERAL, M_EXTRACTION_OVERLAP, M_MAX); // Generate model's top-view depth-map. M3dmapExtract(MilPtCldCtn[eModel], MilDepthMap[eModel], M_NULL, M_CORRECTED_DEPTH_MAP, M_ALL, M_DEFAULT); // Compute model's mean depth-map elevation. M3dmapStat(MilDepthMap[eModel], M_NULL, M_NULL, M_NULL, M_DEVIATION_MEAN+M_STAT_ALL, M_DEFAULT, M_DEFAULT, &ModelMeanElevation); //-------------------------------------------------------------------------- // Generate an 8 bits image with optimal dynamic range from the ROI in the model's // depth-map. Define it as Model Finder's model and preprocess its context. // Compute model's 3D bounding box and corresponding ROI in the depth-map, // from which the Model Finder's model will be defined. DefineModelRoiBox(MilPtCldCtn[eModel], MilDepthMap[eModel], ModelRoiBox); // Allocate a buffer that will contain a copy of the model's depth-map's ROI image from // which the Model Finder's model will be defined. MbufAlloc2d(MilSystem, ModelRoiBox.SizeX, ModelRoiBox.SizeY, M_UNSIGNED + 8, M_IMAGE + M_DISP + M_PROC, &MilFinderImage[eModel]); // Create an 8 bits gray-scale image from 16 bits depth-map's dynamic range, // since Model Finder only works with 8 bits images. Use a child buffer to specify the // ROI in the model's depth-map. MIL_ID MilModelRoiChild = MbufChild2d(MilDepthMap[eModel], ModelRoiBox.OffsetX, ModelRoiBox.OffsetY, ModelRoiBox.SizeX, ModelRoiBox.SizeY, M_NULL); MapDynamicRangeTo8Bits(MilSystem, MilModelRoiChild, MilFinderImage[eModel]); MbufFree(MilModelRoiChild); // Allocate model finder objects. MmodAlloc(MilSystem, M_GEOMETRIC, M_DEFAULT, &MilFinderContext); MmodAllocResult(MilSystem, M_DEFAULT, &MilFinderResult); // Add the model's depth-map's ROI as the ModelFinder model. MmodDefine(MilFinderContext, M_IMAGE, MilFinderImage[eModel], M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT); // Set control to find all occurrences in the scene. MmodControl(MilFinderContext, M_ALL, M_NUMBER, M_ALL); // Set acceptance relatively low to account for small deformations // caused by object's 3D pose. MmodControl(MilFinderContext, M_ALL, M_ACCEPTANCE, FINDER_ACCEPTANCE); // Allocate the fixturing offset that will contain the relation between // the model's reference point and the relative coordinate system's origin. McalAlloc(MilSystem, M_FIXTURING_OFFSET, M_DEFAULT, &MilFinderFixturingOffset); // Determine the fixturing offset from the model defined in the context. McalFixture(M_NULL, MilFinderFixturingOffset, M_LEARN_OFFSET, M_MODEL_MOD, MilFinderContext, 0, M_DEFAULT, M_DEFAULT, M_DEFAULT); // Preprocess ModelFinder context. MmodPreprocess(MilFinderContext, M_DEFAULT); // Draw model's edges. MdispSelect(MilDisplay, MilFinderImage[eModel]); MgraColor(M_DEFAULT, SELECTED_OCCURRENCE_COLOR); MmodDraw(M_DEFAULT, MilFinderContext, MilGraphicList, M_DRAW_EDGES+M_DRAW_BOX+M_DRAW_POSITION, 0, M_DEFAULT); MosPrintf(MIL_TEXT("A scanned object sample, acquired using a third-party 3D scanner, \n" )); MosPrintf(MIL_TEXT("is restored. A top-view depth-map of the object is generated and \n" )); MosPrintf(MIL_TEXT("used to define a 2-dimensional Model Finder model (displayed \n" )); MosPrintf(MIL_TEXT("in green). \n\n")); MosPrintf(MIL_TEXT("Press any key to continue. \n\n")); MosGetch(); // ---------------------------------------------------------------------------------- // Find model occurrences' 3D poses in bin stack scenes. // Allocate the scene's 3D point cloud container. M3dmapAllocResult(MilSystem, M_POINT_CLOUD_CONTAINER, M_DEFAULT, &MilPtCldCtn[eScene]); // Allocate the scene's depth-map. MbufAlloc2d(MilSystem, DEPTHMAP_SIZE_X, DEPTHMAP_SIZE_Y, M_UNSIGNED + 16, M_IMAGE + M_DISP + M_PROC, &MilDepthMap[eScene]); // Set the scene's extraction box to the scanner field of view, but removing the floor. M3dmapSetBox(MilPtCldCtn[eScene], M_EXTRACTION_BOX, M_BOTH_CORNERS, SCANNER_FOV_MIN_X, SCANNER_FOV_MIN_Y, SCANNER_FOV_MIN_Z, SCANNER_FOV_MAX_X, SCANNER_FOV_MAX_Y, SCANNER_FOV_MAX_Z); // Set depth-map's extraction overlap property such that points on top // overwrites points below. M3dmapControl(MilPtCldCtn[eScene], M_GENERAL, M_EXTRACTION_OVERLAP, M_MAX); // Allocate a buffer that will contain a copy of the scene's depth-map image in // which Model Finder will find occurrences of the model. MbufAlloc2d(MilSystem, DEPTHMAP_SIZE_X, DEPTHMAP_SIZE_Y, M_UNSIGNED+8, M_IMAGE+M_DISP+M_PROC, &MilFinderImage[eScene]); // Allocate 3D pairwise alignment objects. M3dmapAlloc(MilSystem, M_PAIRWISE_ALIGNMENT_CONTEXT, M_DEFAULT, &MilAlignmentContext); M3dmapAllocResult(MilSystem, M_ALIGNMENT_RESULT, M_DEFAULT, &MilAlignmentResult); MbufAlloc2d(MilSystem, 4, 4, M_FLOAT+32, M_ARRAY, &MilPrealignmentMatrix); // Set 3D alignment parameters M3dmapControl(MilAlignmentContext, M_DEFAULT, M_DECIMATION_STEP_MODEL , ALIGN_DECIMATION_STEP_MODEL ); M3dmapControl(MilAlignmentContext, M_DEFAULT, M_DECIMATION_STEP_SCENE , ALIGN_DECIMATION_STEP_SCENE ); M3dmapControl(MilAlignmentContext, M_DEFAULT, M_MODEL_OVERLAP , ALIGN_MODEL_OVERLAP ); M3dmapControl(MilAlignmentContext, M_DEFAULT, M_MAX_ITERATIONS , ALIGN_MAX_ITERATIONS ); M3dmapControl(MilAlignmentContext, M_DEFAULT, M_ERROR_MINIMIZATION_METRIC, ALIGN_ERROR_MINIMIZATION_METRIC); // For each scene, find the model occurrence on top of the stack using // 2d model finder and determine its 3D pose using 3D alignment. for (MIL_INT iScene = 0; iScene < NUM_SCENE_SCANS; iScene++) { // Acquire a point cloud of the scene, representing a stack of model occurrences. AcquirePointCloud(MilPtCldCtn[eScene], eScene + iScene); // Generate the scene's top-view depth-map. M3dmapExtract(MilPtCldCtn[eScene], MilDepthMap[eScene], M_NULL, M_CORRECTED_DEPTH_MAP, M_ALL, M_DEFAULT); // Create an 8 bits gray-scale image from 16 bits depth-map's dynamic range, // since Model Finder only works with 8 bits images. MapDynamicRangeTo8Bits(MilSystem, MilDepthMap[eScene], MilFinderImage[eScene]); // Display the scene's depth-map. MgraClear(M_DEFAULT, MilGraphicList); MdispSelect(MilDisplay, MilFinderImage[eScene]); #if ENABLE_DISPLAY_3D // Show the scene's depth-map as a point cloud using a 3D display. DisplayPointCloud3d(MilSystem, MilDispD3D, MilDepthMap[eScene]); #endif // Find occurrences of the model in the scene's depth-map. MmodFind(MilFinderContext, MilFinderImage[eScene], MilFinderResult); // Draw edges of all found occurrences. MgraColor(M_DEFAULT, FOUND_OCCURRENCES_COLOR); MmodDraw(M_DEFAULT, MilFinderResult, MilGraphicList, M_DRAW_EDGES, M_ALL, M_DEFAULT); // Determine which found occurrence is on top of the stack and define a fixturing transform that // prealigns the model and this occurrence, to be used as a starting point for M3dmapAlign. if (!FindPrealignmentWithTopFoundOccurrence(MilSystem, MilPtCldCtn, ModelMeanElevation, MilDepthMap, MilFinderFixturingOffset, MilFinderResult, MilPrealignmentMatrix, &TopOccurrenceIdx)) { MosPrintf(MIL_TEXT("No occurrence found. Press any key to continue.\n\n")); MosGetch(); continue; } // Highlight the selected found occurrence, determined to be on top of the stack. MgraColor(M_DEFAULT, SELECTED_OCCURRENCE_COLOR); MmodDraw(M_DEFAULT, MilFinderResult, MilGraphicList, M_DRAW_EDGES+M_DRAW_BOX, TopOccurrenceIdx, M_DEFAULT); // Display information in prompt about the stack. if (iScene == 0) MosPrintf(MIL_TEXT("The stack of objects has been scanned. \n\n")); else { MosPrintf(MIL_TEXT("The first object located was removed from the stack of objects \n")); MosPrintf(MIL_TEXT("and a new scan was done. \n\n")); } // Display Model Finder information in prompt. MosPrintf(MIL_TEXT("Object occurrences that are on top are located in the 2-dimensional depth-map. \n")); MosPrintf(MIL_TEXT("The top-most occurrence is detected (displayed in green). \n\n")); #if ENABLE_DISPLAY_3D // Print the 3D display help in command prompt (only once). if (iScene == 0) Print3dDisplayHelp(); #endif MosPrintf(MIL_TEXT("Press any key to continue.\n\n")); MosGetch(); // Perform 3D alignment of the model and the selected found occurrence in the scene. M3dmapAlign(MilAlignmentContext, MilPtCldCtn[eModel], M_ALL, MilPtCldCtn[eScene], M_ALL, MilPrealignmentMatrix, MilAlignmentResult, M_DEFAULT, &AlignmentStatus); // Verify the success of the alignment. if (AlignmentCriterionReached(AlignmentStatus)) { // Use the 3D alignment result to generate a depth-map of the model aligned // on the occurrence. ExtractAlignedDepthMaps(MilSystem, MilPtCldCtn, MilDepthMap, MilAlignmentResult, AlignmentPose); MosPrintf(MIL_TEXT("The 3D pose of the top-most occurrence has been estimated using \n")); MosPrintf(MIL_TEXT("3D alignment with the 3D model sample: \n\n")); MosPrintf(MIL_TEXT("\t(X, Y, Z) : (%9.4f mm ,%9.4f mm ,%9.4f mm ) \n" ), AlignmentPose.Tx, AlignmentPose.Ty, AlignmentPose.Tz); MosPrintf(MIL_TEXT("\t(Roll, Pitch, Yaw): (%9.4f deg,%9.4f deg,%9.4f deg) \n\n"), AlignmentPose.Rx, AlignmentPose.Ry, AlignmentPose.Rz); // Show the result of the 3D alignment using a 2d display. DisplayAlignment2d(MilDepthMap, MilGraphicList, ModelRoiBox); #if ENABLE_DISPLAY_3D // Show the result of the 3D alignment using a 3D display. DisplayAlignment3d(MilSystem, MilDispD3D, MilDepthMap); #endif } else { MosPrintf(MIL_TEXT("Occurrence's pose was not successfully determined. \n\n")); } MosPrintf(MIL_TEXT("Press any key to continue.\n\n")); MosGetch(); } // Hide the display by unselecting any buffer associated. MdispSelect(MilDisplay, M_NULL); #if ENABLE_DISPLAY_3D MdispD3DHide(MilDispD3D); #endif MosPrintf(MIL_TEXT("Press any key to end.\n\n")); MosGetch(); //------------------------------------------------------------------------------------------- // Free allocations. MbufFree(MilPrealignmentMatrix); M3dmapFree(MilAlignmentResult); M3dmapFree(MilAlignmentContext); McalFree(MilFinderFixturingOffset); MmodFree(MilFinderResult); MmodFree(MilFinderContext); for (MIL_INT i = 0; i < 2; i++) { MbufFree(MilFinderImage[i]); M3dmapFree(MilPtCldCtn[i]); MbufFree(MilDepthMap[i]); } MgraFree(MilGraphicList); #if ENABLE_DISPLAY_3D MdispD3DFree(MilDispD3D); #endif MdispFree(MilDisplay); MsysFree(MilSystem); MappFree(MilApplication); return 0; } //**************************************************************************** // Compute 3D bounding box and corresponding 2d ROI in the depth-map. //**************************************************************************** void DefineModelRoiBox(MIL_ID MilPtCldCtn, MIL_ID MilDepthMap, SBox& ModelRoiBox) { // Compute a robust bounding box of all points. M3dmapControl(MilPtCldCtn, M_GENERAL, M_BOUNDING_BOX_ALGORITHM, M_ROBUST); M3dmapSetBox(MilPtCldCtn, M_EXTRACTION_BOX, M_BOUNDING_BOX, M_ALL, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT); // Inquire the computed bounding box. MIL_DOUBLE BoxMinX, BoxMinY, BoxMinZ; MIL_DOUBLE BoxMaxX, BoxMaxY, BoxMaxZ; M3dmapInquire(MilPtCldCtn, M_GENERAL, M_EXTRACTION_BOX_MIN_X + M_TYPE_MIL_DOUBLE, &BoxMinX); M3dmapInquire(MilPtCldCtn, M_GENERAL, M_EXTRACTION_BOX_MIN_Y + M_TYPE_MIL_DOUBLE, &BoxMinY); M3dmapInquire(MilPtCldCtn, M_GENERAL, M_EXTRACTION_BOX_MIN_Z + M_TYPE_MIL_DOUBLE, &BoxMinZ); M3dmapInquire(MilPtCldCtn, M_GENERAL, M_EXTRACTION_BOX_MAX_X + M_TYPE_MIL_DOUBLE, &BoxMaxX); M3dmapInquire(MilPtCldCtn, M_GENERAL, M_EXTRACTION_BOX_MAX_Y + M_TYPE_MIL_DOUBLE, &BoxMaxY); M3dmapInquire(MilPtCldCtn, M_GENERAL, M_EXTRACTION_BOX_MAX_Z + M_TYPE_MIL_DOUBLE, &BoxMaxZ); // Add a margin to the bounding box. BoxMinX -= MODEL_ROI_MARGIN_X; BoxMinY -= MODEL_ROI_MARGIN_Y; BoxMinZ -= MODEL_ROI_MARGIN_Z; BoxMaxX += MODEL_ROI_MARGIN_X; BoxMaxY += MODEL_ROI_MARGIN_Y; BoxMaxZ += MODEL_ROI_MARGIN_Z; // Convert x-y bounding corners from world to pixel units in the depth-map. MIL_DOUBLE RoiMinX, RoiMinY; MIL_DOUBLE RoiMaxX, RoiMaxY; McalTransformCoordinate(MilDepthMap, M_WORLD_TO_PIXEL, BoxMinX, BoxMinY, &RoiMinX, &RoiMinY); McalTransformCoordinate(MilDepthMap, M_WORLD_TO_PIXEL, BoxMaxX, BoxMaxY, &RoiMaxX, &RoiMaxY); // Copy values to output structure. ModelRoiBox.MinX = BoxMinX; ModelRoiBox.MinY = BoxMinY; ModelRoiBox.MinZ = BoxMinZ; ModelRoiBox.MaxX = BoxMaxX; ModelRoiBox.MaxY = BoxMaxY; ModelRoiBox.MaxZ = BoxMaxZ; ModelRoiBox.OffsetX = static_cast<MIL_INT>(RoiMinX); ModelRoiBox.OffsetY = static_cast<MIL_INT>(RoiMinY); ModelRoiBox.SizeX = static_cast<MIL_INT>(RoiMaxX - RoiMinX); ModelRoiBox.SizeY = static_cast<MIL_INT>(RoiMaxY - RoiMinY); // Redefine the extraction box as it was. M3dmapSetBox(MilPtCldCtn, M_EXTRACTION_BOX, M_BOTH_CORNERS, SCANNER_FOV_MIN_X, SCANNER_FOV_MIN_Y, SCANNER_FOV_MIN_Z, SCANNER_FOV_MAX_X, SCANNER_FOV_MAX_Y, SCANNER_FOV_MAX_Z); } //**************************************************************************** // Remove the points outside the extraction box from the point cloud. //**************************************************************************** void CropPointCloudToBox(MIL_ID MilPtCldCtn) { // Allocate enough memory to hold the maximum number of points. This is faster than // computing the actual number of points inside the extraction box. MIL_INT MaxNumElements = M3dmapGet(MilPtCldCtn, M_POINT_CLOUD_INDEX(0), M_XYZ, M_EXCLUDE_INVALID_POINTS, M_FLOAT+64, M_NULL, M_NULL, M_NULL, M_NULL, M_NULL); std::vector<MIL_DOUBLE> xyz(MaxNumElements); // Get the points inside the extraction box. MIL_INT ActualNumElements = M3dmapGet(MilPtCldCtn, M_POINT_CLOUD_INDEX(0), M_XYZ, M_INCLUDE_POINTS_INSIDE_BOX_ONLY, M_FLOAT+64, MaxNumElements, &xyz[0], M_NULL, M_NULL, M_NULL); // Put back the points in the same point cloud. // Since the number of points changed, the point cloud must be cleared before calling M3dmapPut(). M3dmapClear(MilPtCldCtn, M_POINT_CLOUD_INDEX(0), M_CLEAR, M_DEFAULT); M3dmapPut (MilPtCldCtn, M_POINT_CLOUD_INDEX(0), M_XYZ, M_FLOAT+64, ActualNumElements, &xyz[0], M_NULL, M_NULL, M_NULL, M_DEFAULT); } //**************************************************************************** // Create an 8 bits gray-scale image from 16 bits depth-map's dynamic range. //**************************************************************************** void MapDynamicRangeTo8Bits(MIL_ID MilSystem, MIL_ID MilScrImage, MIL_ID MilTgtImage) { // Allocate a statistics result and context to compute depth-map's min and max values. MIL_ID MilStatContext = MimAlloc(MilSystem, M_STATISTICS_CONTEXT, M_DEFAULT, M_NULL); MIL_ID MilStatResult = MimAllocResult(MilSystem, M_DEFAULT, M_STATISTICS_RESULT, M_NULL); MimControl(MilStatContext, M_STAT_MIN, M_ENABLE); MimControl(MilStatContext, M_STAT_MAX, M_ENABLE); MimControl(MilStatContext, M_CONDITION, M_NOT_EQUAL); MimControl(MilStatContext, M_COND_LOW, DEPTHMAP_MISSING_DATA); // Allocate a ramp LUT that will map the dynamic range of the 16 bits depth-map // into an 8 bits gray-scale image. MIL_ID MilDynRangeLut = MbufAlloc1d(MilSystem, DEPTHMAP_NUM_VALUES, 8+M_UNSIGNED, M_LUT, M_NULL); // Compute depth-map's extreme values, excluding missing data. MIL_INT DepthMapMin, DepthMapMax; MimStatCalculate(MilStatContext, MilScrImage, MilStatResult, M_DEFAULT); MimGetResult(MilStatResult, M_STAT_MIN+M_TYPE_MIL_INT, &DepthMapMin); MimGetResult(MilStatResult, M_STAT_MAX+M_TYPE_MIL_INT, &DepthMapMax); // Define a ramp LUT mapping the dynamic 16 bits range to the full 8 bits range. // The LUT also set all pixels outside this range to 0. MbufClear(MilDynRangeLut, 0.0); MgenLutRamp(MilDynRangeLut, DepthMapMin, 1.0, DepthMapMax, 255.0); // Perform the LUT mapping. MimLutMap(MilScrImage, MilTgtImage, MilDynRangeLut); // Free allocations. MbufFree(MilDynRangeLut); MimFree(MilStatResult); MimFree(MilStatContext); } //**************************************************************************** // Acquires a point cloud. In STANDALONE_DEMO mode, it imports the point cloud // from a PLY file. Otherwise, the user must insert the code to grab the 3D // data from an installed 3D scanner and connect it to the already existing // code snippet in order to put the 3D data in the point cloud container. //**************************************************************************** void AcquirePointCloud(MIL_ID MilPtCldCtn, MIL_INT Index) { // Do not accumulate scene point clouds in container, so clear it before acquisition. M3dmapClear(MilPtCldCtn, M_ALL, M_DELETE, M_DEFAULT); #if STANDALONE_DEMO // Import 3D stack scene acquired using a 3D device (e.g. a Gocator 3110 from LMI Technologies) // and exported to a PLY file. M3dmapImport(FILE_POINT_CLOUD[Index], M_PLY, MilPtCldCtn, M_POINT_CLOUD_LABEL(Index+1), M_NULL, M_DEFAULT); #else // <==== Insert here the code that grabs a point cloud using a third party 3D scanner. MIL_INT NumPoints = 1; // Number of grabbed 3D points (initial value should be overwritten). // <==== Insert here the code that inquires the number of grabbed 3D points and overwrites // the 'NumPoints' variable above. std::vector<MIL_DOUBLE> x(NumPoints); // x-coordinates of grabbed 3D points. std::vector<MIL_DOUBLE> y(NumPoints); // y-coordinates of grabbed 3D points. std::vector<MIL_DOUBLE> z(NumPoints); // z-coordinates of grabbed 3D points. // <==== Insert here the code that initializes the three 3D point coordinate // arrays above (x, y, z) from the grabbed 3D point cloud. // Put the grabbed 3D points into a MIL 3D point cloud. M3dmapPut(MilPtCldCtn, M_POINT_CLOUD_LABEL(Index+1), M_POSITION, M_FLOAT+64, NumPoints, &x[0], &y[0], &z[0], M_NULL, M_DEFAULT); // Display a warning in prompt if the point cloud does not seem to have been // properly grabbed or initialized. if (NumPoints == 1) { MosPrintf(MIL_TEXT("! WARNING: 3D data grab does not seem to have acquired \n")); MosPrintf(MIL_TEXT(" enough points or the point cloud does not seem \n")); MosPrintf(MIL_TEXT(" to have been properly initialized. Following \n")); MosPrintf(MIL_TEXT(" execution of the example may give unexpected results. \n\n")); MosPrintf(MIL_TEXT("Press any key to continue.\n\n")); MosGetch(); } #endif } //**************************************************************************** // Remove the fixture on an object by moving the relative coordinate system // to be on the absolute coordinate system. //**************************************************************************** void RemoveFixture(MIL_ID Id) { McalSetCoordinateSystem(Id, M_RELATIVE_COORDINATE_SYSTEM, M_ABSOLUTE_COORDINATE_SYSTEM, M_IDENTITY+M_ASSIGN, M_NULL, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT); } //**************************************************************************** // Get 3D pose of specified point cloud container. //**************************************************************************** void GetPose(MIL_ID MilPtCldCtn, MIL_INT64 TargetCoordinateSystem, MIL_INT64 ReferenceCoordinateSystem, SPose& Pose) { // Get 6 pose elements. McalGetCoordinateSystem(MilPtCldCtn, TargetCoordinateSystem, ReferenceCoordinateSystem, M_TRANSLATION , M_NULL, &Pose.Tx, &Pose.Ty, &Pose.Tz, M_NULL); McalGetCoordinateSystem(MilPtCldCtn, TargetCoordinateSystem, ReferenceCoordinateSystem, M_ROTATION_XYZ, M_NULL, &Pose.Rx, &Pose.Ry, &Pose.Rz, M_NULL); // Keep absolute rotation values below 180 degrees for clarity. if (fabs(Pose.Rx) > 180.0) Pose.Rx = fmod(Pose.Rx - 360.0, 360.0); if (fabs(Pose.Ry) > 180.0) Pose.Ry = fmod(Pose.Ry - 360.0, 360.0); if (fabs(Pose.Rz) > 180.0) Pose.Rz = fmod(Pose.Rz - 360.0, 360.0); } //**************************************************************************** // Determine which found occurrence is on top of the stack and define a // fixturing transform that prealigns the model and this occurrence. //**************************************************************************** bool FindPrealignmentWithTopFoundOccurrence(MIL_ID MilSystem, MIL_ID MilPtCldCtn[], MIL_DOUBLE ModelMeanElevation, MIL_ID MilDepthMap[], MIL_ID MilFinderFixturingOffset, MIL_ID MilFinderResult, MIL_ID MilPrealignmentMatrix, MIL_INT* pTopOccIdx) { // Get the number of found occurrences in the scene. MIL_INT NumOccurrences; MmodGetResult(MilFinderResult, M_GENERAL, M_NUMBER+M_TYPE_MIL_INT, &NumOccurrences); // Return if no occurrence. if (NumOccurrences == 0) return false; // Generate the top-view depth-map of the model in its initial pose // (with any fixturing removed). RemoveFixture(MilPtCldCtn[eModel]); M3dmapExtract(MilPtCldCtn[eModel], MilDepthMap[eModel], M_NULL, M_CORRECTED_DEPTH_MAP, M_ALL, M_DEFAULT); // Create a mask buffer of valid model points in the model's depth-map. MIL_ID ModelMask = MbufAlloc2d(MilSystem, DEPTHMAP_SIZE_X, DEPTHMAP_SIZE_Y, M_UNSIGNED+1, M_PROC+M_IMAGE+M_DISP, M_NULL); // In the model's mask, set to zero all pixels corresponding to missing data and // to one all valid pixels. MbufClear(ModelMask, 0.0); MbufCopyCond(MilDepthMap[eModel], ModelMask, MilDepthMap[eModel], M_NOT_EQUAL, DEPTHMAP_MISSING_DATA); // Loop on each found occurrence in the scene, compute its mean elevation in the depth-map // (using the model's mask) and select the higher (the one on top). MIL_DOUBLE CurTopOccMeanElevation = 0.0; for (MIL_INT iOcc = 0; iOcc < NumOccurrences; iOcc++) { // Fixture the scene's point cloud on the current found occurrence, taking // into account the fixturing offset between the model's reference point // and the world's origin. RemoveFixture(MilPtCldCtn[eScene]); McalFixture(MilPtCldCtn[eScene], MilFinderFixturingOffset, M_MOVE_RELATIVE, M_RESULT_MOD, MilFinderResult, iOcc, M_DEFAULT, M_DEFAULT, M_DEFAULT); // Extract the top-view depth-map of the scene fixtured on the occurrence. M3dmapExtract(MilPtCldCtn[eScene], MilDepthMap[eScene], M_NULL, M_CORRECTED_DEPTH_MAP, M_ALL, M_DEFAULT); // Compute occurrence's mean elevation in the scene only from the pixels // enabled by the model's mask. MIL_DOUBLE OccMeanElevation; M3dmapStat(MilDepthMap[eScene], M_NULL, ModelMask, M_NULL, M_DEVIATION_MEAN+M_STAT_ALL, M_DEFAULT, M_DEFAULT, &OccMeanElevation); // Since the z scale is negative, we actually search for the lowest elevation. if ((iOcc == 0) || (iOcc > 0 && (OccMeanElevation < CurTopOccMeanElevation)) ) { // Save the index and mean elevation of the currently selected occurrence. *pTopOccIdx = iOcc; CurTopOccMeanElevation = OccMeanElevation; // Apply an additional z offset to the scene's point cloud to align the // mean elevation of the occurrence with the mean elevation of the model. MIL_DOUBLE OffsetZ = CurTopOccMeanElevation - ModelMeanElevation; McalSetCoordinateSystem(MilPtCldCtn[eScene], M_RELATIVE_COORDINATE_SYSTEM, M_RELATIVE_COORDINATE_SYSTEM, M_TRANSLATION, M_NULL, 0.0, 0.0, OffsetZ, M_DEFAULT); // The resulting pose of the scene's point cloud, expressed as an homogeneous matrix, // defines a transformation that coarsely 3D aligns the model and the occurrence and // it can be used as a prealignment for M3dmapAlign. McalGetCoordinateSystem(MilPtCldCtn[eScene], M_RELATIVE_COORDINATE_SYSTEM, M_ABSOLUTE_COORDINATE_SYSTEM, M_HOMOGENEOUS_MATRIX, MilPrealignmentMatrix, M_NULL, M_NULL, M_NULL, M_NULL); } } // Free allocations. MbufFree(ModelMask); // Reset scene's pose and regenerate the scene's depth-map. RemoveFixture(MilPtCldCtn[eScene]); M3dmapExtract(MilPtCldCtn[eScene], MilDepthMap[eScene], M_NULL, M_CORRECTED_DEPTH_MAP, M_ALL, M_DEFAULT); return true; } //**************************************************************************** // Use the 3D alignment result to generate a depth-map of the model aligned // on the occurrence. //**************************************************************************** void ExtractAlignedDepthMaps(MIL_ID MilSystem, MIL_ID MilPtCldCtn[], MIL_ID MilDepthMap[], MIL_ID MilAlignmentResult, SPose& AlignmentPose) { // Use the 3D alignment result to fixture the model with the found occurrence in the scene. McalFixture(MilPtCldCtn[eScene], M_NULL, M_MOVE_RELATIVE, M_RESULT_ALIGNMENT_3DMAP, MilAlignmentResult, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT); // Determine the found occurrence 3D pose after 3D alignment. GetPose(MilPtCldCtn[eScene], M_RELATIVE_COORDINATE_SYSTEM, M_ABSOLUTE_COORDINATE_SYSTEM, AlignmentPose); // Get the full 3D pose of the occurrence. MIL_ID Pose = MbufAlloc2d(MilSystem, 4, 4, M_FLOAT+32, M_ARRAY, M_NULL); McalGetCoordinateSystem(MilPtCldCtn[eScene], M_ABSOLUTE_COORDINATE_SYSTEM, M_RELATIVE_COORDINATE_SYSTEM, M_HOMOGENEOUS_MATRIX, Pose, M_NULL, M_NULL, M_NULL, M_NULL); // Fixture the model to the found occurrence in the scene using its 3D pose. McalSetCoordinateSystem(MilPtCldCtn[eModel], M_RELATIVE_COORDINATE_SYSTEM, M_ABSOLUTE_COORDINATE_SYSTEM, M_HOMOGENEOUS_MATRIX, Pose, M_DEFAULT, M_DEFAULT, M_DEFAULT, M_DEFAULT); M3dmapExtract(MilPtCldCtn[eModel], MilDepthMap[eModel], M_NULL, M_CORRECTED_DEPTH_MAP, M_ALL, M_DEFAULT); // Remove fixturing of the model and scene's point clouds. RemoveFixture(MilPtCldCtn[eModel]); RemoveFixture(MilPtCldCtn[eScene]); MbufFree(Pose); } //**************************************************************************** // Returns true if an alignment stop criterion has been successfully reached. //**************************************************************************** bool AlignmentCriterionReached(MIL_INT64 AlignmentStatus) { switch(AlignmentStatus) { case M_MAX_ITERATIONS_REACHED: case M_ALIGN_RMS_ERROR_THRESHOLD_REACHED: case M_ALIGN_RMS_ERROR_RELATIVE_THRESHOLD_REACHED: return true; case M_NOT_ENOUGH_POINT_PAIRS: case M_NO_VALID_POINTS: return false; default: return false; } } //**************************************************************************** // Show the result of 3D alignment using a 2d display. //**************************************************************************** void DisplayAlignment2d(MIL_ID MilDepthMap[], MIL_ID MilGraphicList, SBox ModelBox) { // The number of points needed to define the 12 lines representing a 3D box. const MIL_INT NumBoxPoints = 24; // Define box lines (from pairs of points) expressed in absolute coordinate system units. // | Box back square ------------------------------------------ | Box front square ----------------------------------------- | Connect box back square with front square ---------------- | // | xyZ-XyZ XyZ-XYZ XYZ-xYZ xYZ-xyZ | xyz-Xyz Xyz-XYz XYz-xYz xYz-xyz | xyz-xyZ xYz-xYZ Xyz-XyZ XYz-XYZ | MIL_DOUBLE BoxInAbsX[NumBoxPoints] = { ModelBox.MinX, ModelBox.MaxX, ModelBox.MaxX, ModelBox.MinX , ModelBox.MinX, ModelBox.MaxX, ModelBox.MaxX, ModelBox.MinX , ModelBox.MinX, ModelBox.MinX, ModelBox.MaxX, ModelBox.MaxX , ModelBox.MaxX, ModelBox.MaxX, ModelBox.MinX, ModelBox.MinX , ModelBox.MaxX, ModelBox.MaxX, ModelBox.MinX, ModelBox.MinX , ModelBox.MinX, ModelBox.MinX, ModelBox.MaxX, ModelBox.MaxX }; MIL_DOUBLE BoxInAbsY[NumBoxPoints] = { ModelBox.MinY, ModelBox.MinY, ModelBox.MaxY, ModelBox.MaxY , ModelBox.MinY, ModelBox.MinY, ModelBox.MaxY, ModelBox.MaxY , ModelBox.MinY, ModelBox.MaxY, ModelBox.MinY, ModelBox.MaxY , ModelBox.MinY, ModelBox.MaxY, ModelBox.MaxY, ModelBox.MinY , ModelBox.MinY, ModelBox.MaxY, ModelBox.MaxY, ModelBox.MinY , ModelBox.MinY, ModelBox.MaxY, ModelBox.MinY, ModelBox.MaxY }; MIL_DOUBLE BoxInAbsZ[NumBoxPoints] = { ModelBox.MaxZ, ModelBox.MaxZ, ModelBox.MaxZ, ModelBox.MaxZ , ModelBox.MinZ, ModelBox.MinZ, ModelBox.MinZ, ModelBox.MinZ , ModelBox.MinZ, ModelBox.MinZ, ModelBox.MinZ, ModelBox.MinZ , ModelBox.MaxZ, ModelBox.MaxZ, ModelBox.MaxZ, ModelBox.MaxZ , ModelBox.MinZ, ModelBox.MinZ, ModelBox.MinZ, ModelBox.MinZ , ModelBox.MaxZ, ModelBox.MaxZ, ModelBox.MaxZ, ModelBox.MaxZ }; // Convert 3D cube box points from absolute to pixel units in the depth-map. MIL_DOUBLE BoxInPixX[NumBoxPoints]; MIL_DOUBLE BoxInPixY[NumBoxPoints]; McalTransformCoordinate3dList(MilDepthMap[eModel], M_ABSOLUTE_COORDINATE_SYSTEM, M_PIXEL_COORDINATE_SYSTEM, NumBoxPoints, BoxInAbsX, BoxInAbsY, BoxInAbsZ, BoxInPixX, BoxInPixY, M_NULL , M_DEPTH_MAP); // Define each line as the start and end pixels in the image. MIL_INT NumLines = NumBoxPoints/2; MIL_DOUBLE* BoxInPixStartX = BoxInPixX; MIL_DOUBLE* BoxInPixStartY = BoxInPixY; MIL_DOUBLE* BoxInPixEndX = BoxInPixX + NumLines; MIL_DOUBLE* BoxInPixEndY = BoxInPixY + NumLines; // Remove any graphics. MgraClear(M_DEFAULT, MilGraphicList); // Draw lines of the box's back square. Make them darker for a clearer 3D effect. MIL_DOUBLE DarkColorR = 0.4 * M_RGB888_R(SELECTED_OCCURRENCE_COLOR); MIL_DOUBLE DarkColorG = 0.4 * M_RGB888_G(SELECTED_OCCURRENCE_COLOR); MIL_DOUBLE DarkColorB = 0.4 * M_RGB888_B(SELECTED_OCCURRENCE_COLOR); MgraColor(M_DEFAULT, M_RGB888(DarkColorR,DarkColorG,DarkColorB)); MgraLines(M_DEFAULT, MilGraphicList, 4, BoxInPixStartX, BoxInPixStartY, BoxInPixEndX, BoxInPixEndY, M_DEFAULT); // Draw lines connecting the front and back box's squares. MgraColor(M_DEFAULT, SELECTED_OCCURRENCE_COLOR); MgraLines(M_DEFAULT, MilGraphicList, 4, BoxInPixStartX+4, BoxInPixStartY+4, BoxInPixEndX+4, BoxInPixEndY+4, M_DEFAULT); // Draw lines of the box's front square. MgraColor(M_DEFAULT, SELECTED_OCCURRENCE_COLOR); MgraLines(M_DEFAULT, MilGraphicList, 4, BoxInPixStartX+8, BoxInPixStartY+8, BoxInPixEndX+8, BoxInPixEndY+8, M_DEFAULT); } #if ENABLE_DISPLAY_3D //**************************************************************************** // Initialize 3D display parameters. //**************************************************************************** void Init3dDisplay(MIL_DISP_D3D_HANDLE MilDispD3D) { // Set rendering parameters. MdispD3DControl(MilDispD3D, MD3D_ROTATE, DISPLAY_3D_ROTATE ); MdispD3DControl(MilDispD3D, MD3D_POINT , DISPLAY_3D_POINT ); // Set camera pose. MdispD3DControl(MilDispD3D, MD3D_LOOK_AT_X, DISPLAY_3D_LOOK_AT_X); MdispD3DControl(MilDispD3D, MD3D_LOOK_AT_Y, DISPLAY_3D_LOOK_AT_Y); MdispD3DControl(MilDispD3D, MD3D_LOOK_AT_Z, DISPLAY_3D_LOOK_AT_Z); MdispD3DControl(MilDispD3D, MD3D_EYE_THETA, DISPLAY_3D_EYE_THETA); MdispD3DControl(MilDispD3D, MD3D_EYE_PHI, DISPLAY_3D_EYE_PHI); MdispD3DControl(MilDispD3D, MD3D_EYE_DIST, DISPLAY_3D_EYE_DIST); } //**************************************************************************** // Print 3D display commands help in prompt. //**************************************************************************** void Print3dDisplayHelp() { MosPrintf(MIL_TEXT("D3D display controls (note: you must set the focus on the D3D display window):\n") MIL_TEXT(" . Left-click to move the object.\n") MIL_TEXT(" . Right-click to rotate the object.\n") MIL_TEXT(" . Scroll wheel to zoom the object.\n") MIL_TEXT(" . Press 'R' to start/stop the animation.\n") MIL_TEXT(" . Press 'P' to enable/disable the point cloud.\n") MIL_TEXT(" . Press 'V' to change the display of the 3d map visualization volume.\n") MIL_TEXT(" . Press 'L' to change the depth color mode (intensity or LUT (gray or Color)).\n\n")); } //**************************************************************************** // Show a depth-map as a point cloud using a 3D display. //**************************************************************************** void DisplayPointCloud3d(MIL_ID MilSystem, MIL_DISP_D3D_HANDLE& MilDispD3D, MIL_ID MilDepthMap) { // Allocate a texture color map for each depth-map. MIL_ID MilTexture = MbufAllocColor(MilSystem, 3, DEPTHMAP_SIZE_X, DEPTHMAP_SIZE_Y, 8+M_UNSIGNED, M_IMAGE+M_PROC, M_NULL); // The depth maps' textures are uniform. MbufClearCond(MilTexture, 150, 150, 150, MilDepthMap, M_NOT_EQUAL, DEPTHMAP_MISSING_DATA); // If the 3D display is not allocated yet, allocate and initialize it. if (MilDispD3D == M_NULL) { MilDispD3D = MdepthSysD3DAlloc(M_NULL, M_NULL, M_NULL, M_NULL, &MilDepthMap, &MilTexture, 1, DISPLAY_3D_SIZE_X, DISPLAY_3D_SIZE_Y, 8, M_NULL); // Detect the case where the 3D display could not be allocated. It can happen if // it is not supported on the current system. If it is the case, free allocations // and quit without doing anything. if (MilDispD3D == M_NULL) { MbufFree(MilTexture); return; } Init3dDisplay(MilDispD3D); } else // If already allocated, only update its data to display MdepthSysD3DSetSystems(MilDispD3D, M_NULL, M_NULL, M_NULL, M_NULL, &MilDepthMap, &MilTexture, 1, 8); // Show the 3D display. MdispD3DShow(MilDispD3D); // Free allocations. MbufFree(MilTexture); } //**************************************************************************** // Show the result of 3D alignment using a 3D display. //**************************************************************************** void DisplayAlignment3d(MIL_ID MilSystem, MIL_DISP_D3D_HANDLE& MilDispD3D, MIL_ID MilDepthMap[]) { // Allocate a texture color map for each depth-map. MIL_ID MilTexture[2]; for (MIL_INT i = 0; i < 2; i++) MbufAllocColor(MilSystem, 3, DEPTHMAP_SIZE_X, DEPTHMAP_SIZE_Y, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &MilTexture[i]); // The depth maps' textures are uniform. MIL_DOUBLE ModelColorR = M_RGB888_R(SELECTED_OCCURRENCE_COLOR); MIL_DOUBLE ModelColorG = M_RGB888_G(SELECTED_OCCURRENCE_COLOR); MIL_DOUBLE ModelColorB = M_RGB888_B(SELECTED_OCCURRENCE_COLOR); MbufClearCond(MilTexture[eScene], 150, 150, 150, MilDepthMap[eScene], M_NOT_EQUAL, DEPTHMAP_MISSING_DATA); MbufClearCond(MilTexture[eModel], ModelColorR, ModelColorG, ModelColorB, MilDepthMap[eModel], M_NOT_EQUAL, DEPTHMAP_MISSING_DATA); // Associate the calibration so that both maps are expressed in the // same coordinate system. McalAssociate(MilDepthMap[eScene], MilDepthMap[eModel], M_DEFAULT); // Set to invalid pixels of the model's depth-map that are invalid in the // scene's depth-map to not display them. MbufClearCond(MilDepthMap[eModel], DEPTHMAP_MISSING_DATA, 0, 0, MilDepthMap[eScene], M_EQUAL, DEPTHMAP_MISSING_DATA); // If the 3D display is not allocated yet, allocate and initialize it. if (MilDispD3D == M_NULL) { MilDispD3D = MdepthSysD3DAlloc(M_NULL, M_NULL, M_NULL, M_NULL, MilDepthMap, MilTexture, 2, DISPLAY_3D_SIZE_X, DISPLAY_3D_SIZE_Y, 8, M_NULL); Init3dDisplay(MilDispD3D); } else // If already allocated, only update its data to display MdepthSysD3DSetSystems(MilDispD3D, M_NULL, M_NULL, M_NULL, M_NULL, MilDepthMap, MilTexture, 2, 8); // Show the 3D display. MdispD3DShow(MilDispD3D); // Free allocations. for (MIL_INT i = 0; i < 2; i++) MbufFree(MilTexture[i]); } #endif //**************************************************************************** // Check that the given file is present. //**************************************************************************** bool CheckForRequiredMILFile(MIL_CONST_TEXT_PTR FileName) { MIL_INT FilePresent; MappFileOperation(M_DEFAULT, FileName, M_NULL, M_NULL, M_FILE_EXISTS, M_DEFAULT, &FilePresent); if (FilePresent == M_NO) { MosPrintf(MIL_TEXT("\n") MIL_TEXT("The footage needed to run this example is missing. You need \n") MIL_TEXT("to obtain and apply a separate specific update to have it.\n\n")); MosPrintf(MIL_TEXT("Press <Enter> to end.\n\n")); MosGetch(); } return (FilePresent == M_YES); }