#include <mil.h>
#include "interactiveexample.h"
#include "standaloneexample.h"
#if M_MIL_USE_LINUX
#define SAVE_PATH MIL_TEXT("")
#elif M_MIL_USE_CE
#define SAVE_PATH MIL_TEXT("\\Userdisk\\")
#else
#define SAVE_PATH MIL_TEXT("")
#endif
void PrintHeader()
{
MosPrintf(MIL_TEXT("[EXAMPLE NAME]\n")
MIL_TEXT("CameraLaserCalibration\n\n")
MIL_TEXT("[SYNOPSIS]\n")
MIL_TEXT("This example demonstrates how to create a robust calibration of a\n")
MIL_TEXT("3d reconstruction setup consisting of a camera and a laser line\n")
MIL_TEXT("(sheet-of-light).\n\n")
MIL_TEXT("[MODULES USED]\n")
MIL_TEXT("Modules used: application, system, display, digitizer, buffer, graphic,\n")
MIL_TEXT(" image processing, calibration, 3d reconstruction.\n\n"));
}
static const MIL_TEXT_CHAR* const CAMERA_CALIBRATION_FILE = SAVE_PATH MIL_TEXT("MilCalibration.mca");
static const MIL_TEXT_CHAR* const CALIBRATION_GRID_FILE = SAVE_PATH MIL_TEXT("CalibrationGrid.mim");
static const MIL_TEXT_CHAR* const CALIBRATION_3D_FILE = SAVE_PATH MIL_TEXT("MilLaser.m3d");
static const MIL_TEXT_CHAR* const REFERENCE_PLANE_FILE_PATTERN = SAVE_PATH MIL_TEXT("ReferencePlane%d.mim");
static const MIL_INT ROW_NUMBER = 15;
static const MIL_INT COLUMN_NUMBER = 16;
static const MIL_DOUBLE ROW_SPACING = 5.0;
static const MIL_DOUBLE COLUMN_SPACING = 5.0;
static const MIL_INT GRID_TYPE = M_CIRCLE_GRID;
static const MIL_DOUBLE INITIAL_CALIBRATION_DEPTH = 0.0;
static const MIL_DOUBLE CALIBRATION_DEPTH_PER_PLANE = -12.0;
static const MIL_DOUBLE GRAY_LEVEL_PER_WORLD_UNIT = -1000.0;
MIL_ID CalibrateCamera(CExampleInterface* pExample);
bool DiagnoseCameraCalibration(CExampleInterface* pExample, MIL_ID MilCalibration);
void SetupLineExtractionParameters(CExampleInterface* pExample,
MIL_INT CalibrationMode,
MIL_INT* pMinContrast);
bool CalibrateLaser(CExampleInterface* pExample, MIL_ID MilLaser, MIL_ID MilCameraCalibration);
bool DiagnoseFullCalibration(CExampleInterface* pExample, MIL_ID MilLaser);
bool DiagnoseDepthCalibration(CExampleInterface* pExample, MIL_ID MilLaser);
int MosMain(void)
{
PrintHeader();
bool RunInteractiveExample = CExampleInterface::AskInteractiveExample();
CExampleInterface* pExample;
if (RunInteractiveExample)
pExample = new CInteractiveExample;
else
pExample = new CStandAloneExample;
if (!pExample->IsValid())
{
MosPrintf(MIL_TEXT("Unable to allocate all MIL objects (system, display, digitizer).\n\n")
MIL_TEXT("Press <Enter> to exit.\n\n"));
MosGetch();
delete pExample;
return -1;
}
MIL_INT CalibrationMode = pExample->AskCalibrationMode();
MIL_ID MilCameraCalibration = M_NULL;
if (CalibrationMode == M_CALIBRATED_CAMERA_LINEAR_MOTION)
MilCameraCalibration = CalibrateCamera(pExample);
pExample->ShowDisplay();
MIL_INT MinContrast;
SetupLineExtractionParameters(pExample, CalibrationMode, &MinContrast);
bool CalibrationSuccessful = false;
while (!CalibrationSuccessful)
{
MIL_ID MilLaser = M3dmapAlloc(pExample->GetMilSystem(), M_LASER, CalibrationMode, M_NULL);
MIL_ID MilLocatePeakContext;
M3dmapInquire(MilLaser, M_CONTEXT, M_LOCATE_PEAK_1D_CONTEXT_ID+M_TYPE_MIL_ID, &MilLocatePeakContext);
MimControl(MilLocatePeakContext, M_MINIMUM_CONTRAST, MinContrast);
CalibrationSuccessful = CalibrateLaser(pExample, MilLaser, MilCameraCalibration);
if (CalibrationSuccessful)
{
pExample->HideDisplay();
M3dmapSave(CALIBRATION_3D_FILE, MilLaser, M_DEFAULT);
MosPrintf(MIL_TEXT("Calibration was successful.\n")
MIL_TEXT("3D reconstruction context was saved as '"));
MosPrintf(CALIBRATION_3D_FILE);
MosPrintf(MIL_TEXT("'\n\nPress <Enter> to exit.\n\n"));
MosGetch();
}
M3dmapFree(MilLaser);
}
if (MilCameraCalibration != M_NULL)
McalFree(MilCameraCalibration);
delete pExample;
return 0;
}
MIL_ID CalibrateCamera(CExampleInterface* pExample)
{
MosPrintf(MIL_TEXT("Calibrating the camera\n")
MIL_TEXT("======================\n\n"));
MIL_ID MilCalibration = pExample->TryToReloadCameraCalibration(CAMERA_CALIBRATION_FILE);
if (MilCalibration == M_NULL)
{
pExample->ShowDisplay();
McalAlloc(pExample->GetMilSystem(), M_TSAI_BASED, M_DEFAULT, &MilCalibration);
bool CalibrationSuccessful = false;
while (!CalibrationSuccessful)
{
pExample->CopyInOverlay(CExampleInterface::eCalibrateCameraImage);
pExample->GrabCalibrationGrid();
MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE);
McalGrid(MilCalibration, pExample->GetMilDisplayImage(), 0.0, 0.0, 0.0, ROW_NUMBER, COLUMN_NUMBER,
ROW_SPACING, COLUMN_SPACING, M_DEFAULT, GRID_TYPE);
MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE);
MIL_INT CalibrationStatus = McalInquire(MilCalibration, M_CALIBRATION_STATUS, M_NULL);
switch (CalibrationStatus)
{
case M_CALIBRATED:
CalibrationSuccessful = DiagnoseCameraCalibration(pExample, MilCalibration);
break;
case M_GRID_NOT_FOUND:
MosPrintf(MIL_TEXT("The camera calibration failed because the grid was not found.\n\n"));
break;
case M_PLANE_ANGLE_TOO_SMALL:
MosPrintf(MIL_TEXT("The camera calibration failed because the camera's optical axis is not\n")
MIL_TEXT("sufficiently inclined (inclination should be at least 30 degrees).\n\n"));
break;
default:
MosPrintf(MIL_TEXT("Calibration failed for unexpected reasons.\n\n"));
break;
}
pExample->PauseInStandAloneMode();
if (!CalibrationSuccessful)
MosPrintf(SEPARATOR);
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
}
pExample->HideDisplay();
McalSave(CAMERA_CALIBRATION_FILE, MilCalibration, M_DEFAULT);
MbufSave(CALIBRATION_GRID_FILE, pExample->GetMilDisplayImage());
MosPrintf(MIL_TEXT("The camera calibration was successful. The calibration context was saved as\n'"));
MosPrintf(CAMERA_CALIBRATION_FILE);
MosPrintf(MIL_TEXT("' and the calibration grid image was saved as\n'"));
MosPrintf(CALIBRATION_GRID_FILE);
MosPrintf(MIL_TEXT("'.\n\nPress <Enter> to continue.\n\n"));
MosGetch();
}
return MilCalibration;
}
bool DiagnoseCameraCalibration(CExampleInterface* pExample, MIL_ID MilCalibration)
{
bool ExtractionIsAccurate = false;
bool CalibrationIsAccurate = false;
MgraColor(M_DEFAULT, M_COLOR_GREEN);
McalDraw(M_DEFAULT, MilCalibration, pExample->GetMilOverlayImage(), M_DRAW_IMAGE_POINTS, M_DEFAULT, M_DEFAULT);
pExample->CopyInOverlay(CExampleInterface::eCalibrateCameraImage);
MosPrintf(MIL_TEXT("Calibration points extracted from the image are displayed in green.\n\n"));
ExtractionIsAccurate = pExample->AskIfFeatureExtractionAccurate();
if (ExtractionIsAccurate)
{
MIL_DOUBLE AveragePixelError, MaximumPixelError, AverageWorldError, MaximumWorldError;
McalInquire(MilCalibration, M_AVERAGE_PIXEL_ERROR, &AveragePixelError);
McalInquire(MilCalibration, M_MAXIMUM_PIXEL_ERROR, &MaximumPixelError);
McalInquire(MilCalibration, M_AVERAGE_WORLD_ERROR, &AverageWorldError);
McalInquire(MilCalibration, M_MAXIMUM_WORLD_ERROR, &MaximumWorldError);
MosPrintf(MIL_TEXT("Calibration points, transformed using the calibration context, are shown in red.\n"));
MosPrintf(MIL_TEXT("Pixel error\n average: %.3g pixels\n maximum: %.3g pixels\n"), AveragePixelError, MaximumPixelError);
MosPrintf(MIL_TEXT("World error\n average: %.3g mm\n maximum: %.3g mm\n\n"), AverageWorldError, MaximumWorldError);
MgraColor(M_DEFAULT, M_COLOR_LIGHT_GRAY);
McalDraw(M_DEFAULT, MilCalibration, pExample->GetMilOverlayImage(), M_DRAW_ABSOLUTE_COORDINATE_SYSTEM+M_DRAW_AXES, M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_RED);
McalDraw(M_DEFAULT, MilCalibration, pExample->GetMilOverlayImage(), M_DRAW_WORLD_POINTS, M_DEFAULT, M_DEFAULT);
pExample->CopyInOverlay(CExampleInterface::eCalibrateCameraImage);
CalibrationIsAccurate = pExample->AskIfCameraCalibrationAccurate();
}
return (ExtractionIsAccurate && CalibrationIsAccurate);
}
void SetupLineExtractionParameters(CExampleInterface* pExample,
MIL_INT CalibrationMode,
MIL_INT* pMinContrast)
{
MosPrintf(MIL_TEXT("Setting up the laser line extraction parameters\n")
MIL_TEXT("===============================================\n\n"));
MgraColor(M_DEFAULT, 255.0);
MIL_ID MilOverlayGreenBand = MbufChildColor(pExample->GetMilOverlayImage(), M_GREEN, M_NULL);
MIL_ID MilLaser = M3dmapAlloc(pExample->GetMilSystem(), M_LASER, CalibrationMode, M_NULL);
MIL_ID MilCalibScan = M3dmapAllocResult(pExample->GetMilSystem(), M_LASER_CALIBRATION_DATA, M_DEFAULT, M_NULL);
MIL_ID MilLocatePeakContext;
M3dmapInquire(MilLaser, M_CONTEXT, M_LOCATE_PEAK_1D_CONTEXT_ID+M_TYPE_MIL_ID, &MilLocatePeakContext);
MimInquire(MilLocatePeakContext, M_MINIMUM_CONTRAST+M_TYPE_MIL_INT, pMinContrast);
pExample->PrintExplanationForMinContrast();
bool IsFinished = false;
while (!IsFinished)
{
IsFinished = pExample->AskMinContrastAdjust(pMinContrast);
pExample->GrabLaserLineToAdjustContrast();
MimControl(MilLocatePeakContext, M_MINIMUM_CONTRAST, *pMinContrast);
M3dmapAddScan(MilLaser, MilCalibScan, pExample->GetMilDisplayImage(), M_NULL, M_NULL, M_DEFAULT, M_DEFAULT);
MdispControl(pExample->GetMilDisplay(), M_UPDATE, M_DISABLE);
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
M3dmapDraw(M_DEFAULT, MilCalibScan, MilOverlayGreenBand, M_DRAW_PEAKS_LAST, M_DEFAULT, M_DEFAULT);
pExample->CopyInOverlay(CExampleInterface::eAdjustMinContrastImage);
MdispControl(pExample->GetMilDisplay(), M_UPDATE, M_ENABLE);
pExample->PauseInStandAloneMode();
M3dmapClear(MilCalibScan, M_DEFAULT, M_REMOVE_LAST_SCAN, M_DEFAULT);
}
MosPrintf(MIL_TEXT("\n\n"));
MbufFree(MilOverlayGreenBand);
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
M3dmapFree(MilCalibScan);
M3dmapFree(MilLaser);
}
bool CalibrateLaser(CExampleInterface* pExample, MIL_ID MilLaser, MIL_ID MilCameraCalibration)
{
MosPrintf(MIL_TEXT("Calibrating the 3d reconstruction setup\n")
MIL_TEXT("=======================================\n\n"));
MgraColor(M_DEFAULT, 255.0);
MIL_ID MilOverlayGreenBand = MbufChildColor(pExample->GetMilOverlayImage(), M_GREEN, M_NULL);
MIL_INT SizeX = MbufInquire(pExample->GetMilDisplayImage(), M_SIZE_X, M_NULL);
MIL_INT SizeY = MbufInquire(pExample->GetMilDisplayImage(), M_SIZE_Y, M_NULL);
MIL_INT CalibrationMode = M3dmapInquire(MilLaser, M_DEFAULT, M_LASER_CONTEXT_TYPE, M_NULL);
MIL_INT MinReferencePlanes;
MIL_DOUBLE Factor;
if (CalibrationMode == M_CALIBRATED_CAMERA_LINEAR_MOTION)
{
MinReferencePlanes = 1;
Factor = 1.0;
}
else
{
MinReferencePlanes = 2;
Factor = GRAY_LEVEL_PER_WORLD_UNIT;
}
MIL_ID MilLocatePeakContext;
M3dmapInquire(MilLaser, M_CONTEXT, M_LOCATE_PEAK_1D_CONTEXT_ID+M_TYPE_MIL_ID, &MilLocatePeakContext);
MIL_INT Orientation = MimInquire(MilLocatePeakContext, M_SCAN_LANE_DIRECTION, M_NULL);
MIL_INT NbColumns = (Orientation == M_VERTICAL ? SizeX : SizeY);
MIL_ID MilCalibScan = M3dmapAllocResult(pExample->GetMilSystem(), M_LASER_CALIBRATION_DATA, M_DEFAULT, M_NULL);
MIL_INT MaxReferencePlanes = M3dmapInquire(MilCalibScan, M_DEFAULT, M_MAX_FRAMES, M_NULL);
MIL_INT ReferencePlaneIndex = 0;
bool ReadyToCalibrate = false;
while (!ReadyToCalibrate)
{
MIL_DOUBLE CalibrationDepth = INITIAL_CALIBRATION_DEPTH + ReferencePlaneIndex*CALIBRATION_DEPTH_PER_PLANE;
bool MaxPlaneIsReached = (ReferencePlaneIndex >= MaxReferencePlanes);
if (CalibrationMode == M_DEPTH_CORRECTION)
{
if (Factor*CalibrationDepth < 0.0 || Factor*CalibrationDepth > 65534.0)
MaxPlaneIsReached = true;
}
if (MaxPlaneIsReached)
{
MosPrintf(MIL_TEXT("The maximum number of reference planes of this example has been reached.\n")
MIL_TEXT("Please modify the source code to use more reference planes.\n\n")
MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
break;
}
bool ShouldAskIfFinished = (ReferencePlaneIndex >= MinReferencePlanes);
pExample->CopyInOverlay(CExampleInterface::eCalibrateLaserImage);
ReadyToCalibrate = pExample->GrabCalibrationLaserLine(ReferencePlaneIndex, CalibrationDepth, ShouldAskIfFinished);
if (!ReadyToCalibrate)
{
M3dmapControl(MilLaser, M_DEFAULT, M_CORRECTED_DEPTH, Factor*CalibrationDepth);
M3dmapAddScan(MilLaser, MilCalibScan, pExample->GetMilDisplayImage(), M_NULL, M_NULL, M_DEFAULT, M_DEFAULT);
M3dmapDraw(M_DEFAULT, MilCalibScan, MilOverlayGreenBand, M_DRAW_PEAKS_LAST, M_DEFAULT, M_DEFAULT);
pExample->CopyInOverlay(CExampleInterface::eCalibrateLaserImage);
MIL_INT NbColumnsWithMissingData;
M3dmapGetResult(MilCalibScan, M_DEFAULT, M_NUMBER_OF_MISSING_DATA_LAST_SCAN + M_TYPE_MIL_INT, &NbColumnsWithMissingData);
MosPrintf(MIL_TEXT("Extracted laser line is displayed in green.\n"));
MosPrintf(MIL_TEXT("Number of columns with missing data: %4d / %d (%.1f%%)\n\n"),
(int)NbColumnsWithMissingData, (int)NbColumns,
100.0*static_cast<MIL_DOUBLE>(NbColumnsWithMissingData)/static_cast<MIL_DOUBLE>(NbColumns));
bool ExtractionIsAccurate = pExample->AskIfLineExtractionAccurate();
pExample->PauseInStandAloneMode();
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
if (ExtractionIsAccurate)
{
const MIL_INT MAX_FILENAME_LENGTH = 32;
MIL_TEXT_CHAR ImageName[MAX_FILENAME_LENGTH];
MosSprintf(ImageName, MAX_FILENAME_LENGTH, REFERENCE_PLANE_FILE_PATTERN, (int)ReferencePlaneIndex);
MbufSave(ImageName, pExample->GetMilDisplayImage());
MosPrintf(MIL_TEXT("Image was saved as '%s'\n\n"), ImageName);
++ReferencePlaneIndex;
}
else
{
M3dmapClear(MilCalibScan, M_DEFAULT, M_REMOVE_LAST_SCAN, M_DEFAULT);
}
MosPrintf(SEPARATOR);
}
}
MappControl(M_DEFAULT, M_ERROR, M_PRINT_DISABLE);
M3dmapCalibrate(MilLaser, MilCalibScan, MilCameraCalibration, M_DEFAULT);
MappControl(M_DEFAULT, M_ERROR, M_PRINT_ENABLE);
MIL_INT CalibrationStatus = M3dmapInquire(MilLaser, M_DEFAULT, M_CALIBRATION_STATUS, M_NULL);
bool CalibrationSuccessful = false;
switch (CalibrationStatus)
{
case M_CALIBRATED:
if (CalibrationMode == M_CALIBRATED_CAMERA_LINEAR_MOTION)
CalibrationSuccessful = DiagnoseFullCalibration(pExample, MilLaser);
else
CalibrationSuccessful = DiagnoseDepthCalibration(pExample, MilLaser);
break;
case M_LASER_LINE_NOT_DETECTED:
MosPrintf(MIL_TEXT("Calibration failed because laser line could not be detected in the calibration\n")
MIL_TEXT("image.\n\n"));
break;
case M_NOT_ENOUGH_MEMORY:
MosPrintf(MIL_TEXT("Calibration failed because there was not enough available memory.\n\n"));
break;
default:
MosPrintf(MIL_TEXT("Calibration failed for unexpected reasons.\n\n"));
break;
}
pExample->PauseInStandAloneMode();
MbufFree(MilOverlayGreenBand);
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
M3dmapFree(MilCalibScan);
return CalibrationSuccessful;
}
bool DiagnoseFullCalibration(CExampleInterface* pExample, MIL_ID MilLaser)
{
MbufClear(pExample->GetMilDisplayImage(), 0.0);
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_RED);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_CALIBRATION_LINES, M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, 255.0);
MIL_ID MilOverlayGreenBand = MbufChildColor(pExample->GetMilOverlayImage(), M_GREEN, M_NULL);
M3dmapDraw(M_DEFAULT, MilLaser, MilOverlayGreenBand, M_DRAW_CALIBRATION_PEAKS, M_DEFAULT, M_DEFAULT);
MbufFree(MilOverlayGreenBand);
MosPrintf(MIL_TEXT("The laser plane has been fitted on the extracted laser line(s).\n")
MIL_TEXT(" Green: extracted laser line(s).\n")
MIL_TEXT(" Red: expected line(s) on the fitted laser plane.\n\n"));
MIL_DOUBLE FitRMSError;
M3dmapInquire(MilLaser, M_DEFAULT, M_FIT_RMS_ERROR, &FitRMSError);
MosPrintf(MIL_TEXT("Fit RMS error: %.3g mm\n\n"), FitRMSError);
bool CalibrationIsAccurate = pExample->AskIfLaserCalibrationAccurate();
return CalibrationIsAccurate;
}
bool DiagnoseDepthCalibration(CExampleInterface* pExample, MIL_ID MilLaser)
{
MbufClear(pExample->GetMilDisplayImage(), 0.0);
MdispControl(pExample->GetMilDisplay(), M_OVERLAY_CLEAR, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_GREEN);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_REGION_VALID , M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_YELLOW);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_REGION_INTERPOLATED, M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_GRAY);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_REGION_UNCALIBRATED, M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_RED);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_REGION_MISSING_DATA, M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_MAGENTA);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_REGION_INVERTED , M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, M_COLOR_WHITE);
M3dmapDraw(M_DEFAULT, MilLaser, pExample->GetMilOverlayImage(), M_DRAW_CALIBRATION_PEAKS , M_DEFAULT, M_DEFAULT);
MosPrintf(MIL_TEXT("The calibration state of each pixel of the camera image is shown:\n")
MIL_TEXT(" Green: Calibrated region (will generate corrected depths)\n")
MIL_TEXT(" Gray: Uncalibrated region (will generate missing data)\n")
MIL_TEXT(" Cause: outside the region between lowest and highest planes.\n")
MIL_TEXT(" Yellow: Interpolated region (will generate less accurate depths)\n")
MIL_TEXT(" Cause: some laser line pixels were missed.\n")
MIL_TEXT(" Red: Missing calibration data (will generate missing data)\n")
MIL_TEXT(" Cause: some laser line pixels were missed on lowest or highest plane.\n")
MIL_TEXT(" Magenta: Inversion (could generate erroneous depths)\n")
MIL_TEXT(" Cause: some laser line pixels of a lower reference plane were\n")
MIL_TEXT(" detected above a higher reference plane.\n\n"));
MIL_INT NbColumns = M3dmapInquire(MilLaser, M_DEFAULT, M_NUMBER_OF_COLUMNS , M_NULL);
MIL_INT NbColumnsWithMissingData = M3dmapInquire(MilLaser, M_DEFAULT, M_NUMBER_OF_COLUMNS_WITH_MISSING_DATA, M_NULL);
MIL_INT NbColumnsWithInversions = M3dmapInquire(MilLaser, M_DEFAULT, M_NUMBER_OF_COLUMNS_WITH_INVERSIONS , M_NULL);
MosPrintf(MIL_TEXT("Number of columns with missing data: %4d / %d (%.1f%%)\n")
MIL_TEXT("Number of columns with inversions: %4d / %d (%.1f%%)\n\n"),
(int)NbColumnsWithMissingData, (int)NbColumns,
100.0*static_cast<MIL_DOUBLE>(NbColumnsWithMissingData)/static_cast<MIL_DOUBLE>(NbColumns),
(int)NbColumnsWithInversions, (int)NbColumns,
100.0*static_cast<MIL_DOUBLE>(NbColumnsWithInversions)/static_cast<MIL_DOUBLE>(NbColumns));
bool CalibrationIsAccurate = pExample->AskIfLaserCalibrationAccurate();
return CalibrationIsAccurate;
}