#include <mil.h>
#define RUN_LINEAR_CALIBRATION_EXAMPLE M_YES
#define RUN_TSAI_CALIBRATION_EXAMPLE M_YES
void LinearInterpolationCalibration(MIL_ID MilSystem, MIL_ID MilDisplay);
void TsaiCalibration(MIL_ID MilSystem, MIL_ID MilDisplay);
int MosMain(void)
{
MIL_ID MilApplication,
MilSystem,
MilDisplay;
MappAllocDefault(M_DEFAULT, &MilApplication, &MilSystem, &MilDisplay, M_NULL, M_NULL);
MosPrintf(MIL_TEXT("CALIBRATION MODULE:\n"));
MosPrintf(MIL_TEXT("-------------------\n\n"));
#if (RUN_LINEAR_CALIBRATION_EXAMPLE)
LinearInterpolationCalibration(MilSystem, MilDisplay);
#endif
#if (RUN_TSAI_CALIBRATION_EXAMPLE)
TsaiCalibration(MilSystem, MilDisplay);
#endif
MappFreeDefault(MilApplication, MilSystem, MilDisplay, M_NULL, M_NULL);
return 0;
}
#define GRID_IMAGE_FILE M_IMAGE_PATH MIL_TEXT("CalGrid.mim")
#define BOARD_IMAGE_FILE M_IMAGE_PATH MIL_TEXT("CalBoard.mim")
#define GRID_OFFSET_X 0
#define GRID_OFFSET_Y 0
#define GRID_OFFSET_Z 0
#define GRID_ROW_SPACING 1
#define GRID_COLUMN_SPACING 1
#define GRID_ROW_NUMBER 18
#define GRID_COLUMN_NUMBER 25
#define MEAS_BOX_POS_X1 55
#define MEAS_BOX_POS_Y1 24
#define MEAS_BOX_WIDTH1 7
#define MEAS_BOX_HEIGHT1 425
#define MEAS_BOX_POS_X2 225
#define MEAS_BOX_POS_Y2 11
#define MEAS_BOX_WIDTH2 7
#define MEAS_BOX_HEIGHT2 450
#define WIDTH_APPROXIMATION 410
#define WIDTH_VARIATION 25
#define MIN_EDGE_VALUE 5
void LinearInterpolationCalibration(MIL_ID MilSystem, MIL_ID MilDisplay)
{
MIL_ID MilImage,
MilOverlayImage,
MilCalibration,
MeasMarker1,
MeasMarker2;
MIL_DOUBLE WorldDistance1, WorldDistance2;
MIL_DOUBLE PixelDistance1, PixelDistance2;
MIL_DOUBLE PosX1, PosY1, PosX2, PosY2, PosX3, PosY3, PosX4, PosY4;
MIL_INT CalibrationStatus;
MdispControl(MilDisplay, M_OVERLAY_CLEAR, M_DEFAULT);
MbufRestore(GRID_IMAGE_FILE, MilSystem, &MilImage);
MdispSelect(MilDisplay, MilImage);
MdispControl(MilDisplay, M_OVERLAY, M_ENABLE);
MdispInquire(MilDisplay, M_OVERLAY_ID, &MilOverlayImage);
MosPrintf(MIL_TEXT("\nLINEAR INTERPOLATION CALIBRATION:\n"));
MosPrintf(MIL_TEXT("------------\n\n"));
MosPrintf(MIL_TEXT("The displayed grid has been grabbed with a high distortion\n"));
MosPrintf(MIL_TEXT("camera and will be used to calibrate the camera.\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
McalAlloc(MilSystem, M_DEFAULT, M_DEFAULT, &MilCalibration);
McalGrid(MilCalibration, MilImage,
GRID_OFFSET_X, GRID_OFFSET_Y, GRID_OFFSET_Z,
GRID_ROW_NUMBER, GRID_COLUMN_NUMBER,
GRID_ROW_SPACING, GRID_COLUMN_SPACING,
M_DEFAULT, M_DEFAULT);
McalInquire(MilCalibration, M_CALIBRATION_STATUS + M_TYPE_MIL_INT, &CalibrationStatus);
if( CalibrationStatus == M_CALIBRATED )
{
McalTransformImage(MilImage, MilImage, MilCalibration,
M_BILINEAR + M_OVERSCAN_CLEAR, M_DEFAULT, M_DEFAULT);
MosPrintf(MIL_TEXT("The camera has been calibrated and the image of the grid\n"));
MosPrintf(MIL_TEXT("has been transformed to remove its distortions.\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
MbufLoad(BOARD_IMAGE_FILE, MilImage);
McalAssociate(MilCalibration, MilImage, M_DEFAULT);
MmeasAllocMarker(MilSystem, M_STRIPE, M_DEFAULT, &MeasMarker1);
MmeasAllocMarker(MilSystem, M_STRIPE, M_DEFAULT, &MeasMarker2);
MmeasSetMarker(MeasMarker1, M_BOX_ORIGIN, MEAS_BOX_POS_X1, MEAS_BOX_POS_Y1);
MmeasSetMarker(MeasMarker1, M_BOX_SIZE, MEAS_BOX_WIDTH1, MEAS_BOX_HEIGHT1);
MmeasSetMarker(MeasMarker2, M_BOX_ORIGIN, MEAS_BOX_POS_X2, MEAS_BOX_POS_Y2);
MmeasSetMarker(MeasMarker2, M_BOX_SIZE, MEAS_BOX_WIDTH2, MEAS_BOX_HEIGHT2);
MmeasSetMarker(MeasMarker1, M_ORIENTATION, M_HORIZONTAL, M_NULL);
MmeasSetMarker(MeasMarker2, M_ORIENTATION, M_HORIZONTAL, M_NULL);
MmeasSetMarker(MeasMarker1, M_EDGEVALUE_MIN, MIN_EDGE_VALUE, M_NULL);
MmeasSetScore(MeasMarker1, M_STRENGTH_SCORE,
0.0,
0.0,
M_MAX_POSSIBLE_VALUE,
M_MAX_POSSIBLE_VALUE,
M_DEFAULT,
M_DEFAULT,
M_DEFAULT);
MmeasSetScore(MeasMarker1, M_STRIPE_WIDTH_SCORE,
WIDTH_APPROXIMATION - WIDTH_VARIATION,
WIDTH_APPROXIMATION + WIDTH_VARIATION,
WIDTH_APPROXIMATION + WIDTH_VARIATION,
WIDTH_APPROXIMATION + WIDTH_VARIATION,
M_DEFAULT,
M_PIXEL,
M_DEFAULT);
MmeasSetMarker(MeasMarker2, M_EDGEVALUE_MIN, MIN_EDGE_VALUE, M_NULL);
MmeasSetScore(MeasMarker2, M_STRENGTH_SCORE,
0.0,
0.0,
M_MAX_POSSIBLE_VALUE,
M_MAX_POSSIBLE_VALUE,
M_DEFAULT,
M_DEFAULT,
M_DEFAULT);
MmeasSetScore(MeasMarker2, M_STRIPE_WIDTH_SCORE,
WIDTH_APPROXIMATION - WIDTH_VARIATION,
WIDTH_APPROXIMATION + WIDTH_VARIATION,
WIDTH_APPROXIMATION + WIDTH_VARIATION,
WIDTH_APPROXIMATION + WIDTH_VARIATION,
M_DEFAULT,
M_PIXEL,
M_DEFAULT);
MmeasFindMarker(M_DEFAULT, MilImage, MeasMarker1, M_STRIPE_WIDTH+M_POSITION);
MmeasFindMarker(M_DEFAULT, MilImage, MeasMarker2, M_STRIPE_WIDTH+M_POSITION);
MmeasGetResult(MeasMarker1, M_STRIPE_WIDTH, &WorldDistance1, M_NULL);
MmeasGetResult(MeasMarker2, M_STRIPE_WIDTH, &WorldDistance2, M_NULL);
MmeasSetMarker(MeasMarker1, M_RESULT_OUTPUT_UNITS, M_PIXEL, M_NULL);
MmeasSetMarker(MeasMarker2, M_RESULT_OUTPUT_UNITS, M_PIXEL, M_NULL);
MmeasGetResult(MeasMarker1, M_STRIPE_WIDTH, &PixelDistance1, M_NULL);
MmeasGetResult(MeasMarker2, M_STRIPE_WIDTH, &PixelDistance2, M_NULL);
MmeasGetResult(MeasMarker1, M_POSITION+M_EDGE_FIRST, &PosX1, &PosY1);
MmeasGetResult(MeasMarker1, M_POSITION+M_EDGE_SECOND, &PosX2, &PosY2);
MmeasGetResult(MeasMarker2, M_POSITION+M_EDGE_FIRST, &PosX3, &PosY3);
MmeasGetResult(MeasMarker2, M_POSITION+M_EDGE_SECOND, &PosX4, &PosY4);
MgraColor(M_DEFAULT, M_COLOR_YELLOW);
MmeasDraw(M_DEFAULT, MeasMarker1, MilOverlayImage, M_DRAW_WIDTH, M_DEFAULT, M_RESULT);
MmeasDraw(M_DEFAULT, MeasMarker2, MilOverlayImage, M_DRAW_WIDTH, M_DEFAULT, M_RESULT);
MgraBackColor(M_DEFAULT, M_COLOR_BLACK);
MgraText(M_DEFAULT, MilOverlayImage, (MIL_INT)(PosX1+0.5-40),
(MIL_INT)((PosY1+0.5)+((PosY2 - PosY1)/2.0)), MIL_TEXT(" Distance 1 "));
MgraText(M_DEFAULT, MilOverlayImage, (MIL_INT)(PosX3+0.5-40),
(MIL_INT)((PosY3+0.5)+((PosY4 - PosY3)/2.0)), MIL_TEXT(" Distance 2 "));
MosPrintf(MIL_TEXT("A distorted image grabbed with the same camera was loaded and\n"));
MosPrintf(MIL_TEXT("calibrated measurements were done to evaluate ")
MIL_TEXT("the board dimensions.\n"));
MosPrintf(MIL_TEXT("\n========================================================\n"));
MosPrintf(MIL_TEXT(" Distance 1 Distance 2 \n"));
MosPrintf(MIL_TEXT("--------------------------------------------------------\n"));
MosPrintf(MIL_TEXT(" Calibrated unit: %8.2lf cm %6.2lf cm \n"),
WorldDistance1, WorldDistance2);
MosPrintf(MIL_TEXT(" Uncalibrated unit: %8.2lf pixels %6.2lf pixels\n"),
PixelDistance1, PixelDistance2);
MosPrintf(MIL_TEXT("========================================================\n\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
MdispControl(MilDisplay, M_OVERLAY_CLEAR, M_DEFAULT);
MbufLoad(BOARD_IMAGE_FILE, MilImage);
McalTransformImage(MilImage, MilImage, MilCalibration,
M_BILINEAR+M_OVERSCAN_CLEAR, M_DEFAULT, M_DEFAULT);
MosPrintf(MIL_TEXT("The image was corrected to remove its distortions.\n"));
MmeasFree(MeasMarker1);
MmeasFree(MeasMarker2);
}
else
{
MosPrintf(MIL_TEXT("Calibration generated an exception.\n"));
MosPrintf(MIL_TEXT("See User Guide to resolve the situation.\n\n"));
}
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
McalFree(MilCalibration);
MbufFree(MilImage);
}
#define GRID_ORIGINAL_IMAGE_FILE M_IMAGE_PATH MIL_TEXT("CalGridOriginal.mim")
#define OBJECT_ORIGINAL_IMAGE_FILE M_IMAGE_PATH MIL_TEXT("CalObjOriginal.mim")
#define OBJECT_MOVED_IMAGE_FILE M_IMAGE_PATH MIL_TEXT("CalObjMoved.mim")
#define GRID_ORG_ROW_SPACING 1.5
#define GRID_ORG_COLUMN_SPACING 1.5
#define GRID_ORG_ROW_NUMBER 12
#define GRID_ORG_COLUMN_NUMBER 13
#define GRID_ORG_OFFSET_X 0
#define GRID_ORG_OFFSET_Y 0
#define GRID_ORG_OFFSET_Z 0
#define ENCODER_TRANSLATION_X 0.817
#define ENCODER_TRANSLATION_Y 13.293
#define ENCODER_TRANSLATION_Z -14.060
#define ENCODER_ROTATION_Y 354.207
#define ENCODER_ROTATION_X 317.467
#define ENCODER_ROTATION_Z 281.969
#define MEASURED_CIRCLE_LABEL 1
#define RING1_POS1_X 2.3
#define RING1_POS1_Y 3.9
#define RING2_POS1_X 10.7
#define RING2_POS1_Y 11.1
#define RING1_POS2_X 8.6
#define RING1_POS2_Y 2.5
#define RING2_POS2_X 7.9
#define RING2_POS2_Y 13.2
#define RING_START_RADIUS 1.25
#define RING_END_RADIUS 2.3
#define RING_THICKNESS 0.175
#define STEP_THICKNESS 4.0
#define REGION_COLOR M_RGB888(0,100,255)
#define FEATURE_COLOR M_RGB888(255,0,255)
void MeasureRing(MIL_ID MilSystem, MIL_ID MilDisplay, MIL_ID MilImage,
MIL_DOUBLE MeasureRing1X, MIL_DOUBLE MeasureRing1Y );
void ShowCameraInformation(MIL_ID MilCalibration);
void SetCalibrationOffset(MIL_ID MilCalibration, MIL_DOUBLE ZOffset, MIL_ID MilImage);
void TsaiCalibration(MIL_ID MilSystem, MIL_ID MilDisplay)
{
MIL_ID MilImage,
MilCalibration;
MIL_INT CalibrationStatus;
MbufRestore(GRID_ORIGINAL_IMAGE_FILE, MilSystem, &MilImage);
MdispSelect(MilDisplay, MilImage);
MosPrintf(MIL_TEXT("TSAI BASED CALIBRATION:\n"));
MosPrintf(MIL_TEXT("------------\n\n"));
MosPrintf(MIL_TEXT("The displayed grid has been grabbed with a high perspective\n"));
MosPrintf(MIL_TEXT("camera and will be used to calibrate the camera.\n"));
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
McalAlloc(MilSystem, M_TSAI_BASED, M_DEFAULT, &MilCalibration);
McalGrid(MilCalibration, MilImage,
GRID_ORG_OFFSET_X, GRID_ORG_OFFSET_Y, GRID_ORG_OFFSET_Z,
GRID_ORG_ROW_NUMBER, GRID_ORG_COLUMN_NUMBER,
GRID_ORG_ROW_SPACING, GRID_ORG_COLUMN_SPACING,
M_DEFAULT, M_DEFAULT);
McalInquire(MilCalibration, M_CALIBRATION_STATUS + M_TYPE_MIL_INT, &CalibrationStatus);
if( CalibrationStatus == M_CALIBRATED )
{
MosPrintf(MIL_TEXT("The camera has been calibrated.\n\n"));
ShowCameraInformation(MilCalibration);
MbufLoad(OBJECT_ORIGINAL_IMAGE_FILE, MilImage);
SetCalibrationOffset(MilCalibration, -RING_THICKNESS, MilImage);
MosPrintf(MIL_TEXT("First measured circle at z = %.2f cm. "), -RING_THICKNESS);
MeasureRing(MilSystem, MilDisplay, MilImage, RING1_POS1_X, RING1_POS1_Y );
SetCalibrationOffset(MilCalibration, -(STEP_THICKNESS+RING_THICKNESS), MilImage);
MosPrintf(MIL_TEXT("Second measured circle at z = %.2f cm. "),
-(STEP_THICKNESS+RING_THICKNESS));
MeasureRing(MilSystem, MilDisplay, MilImage, RING2_POS1_X, RING2_POS1_Y );
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
MdispControl(MilDisplay, M_OVERLAY_CLEAR, M_DEFAULT);
McalSetCoordinateSystem(MilCalibration,
M_TOOL_COORDINATE_SYSTEM,
M_ABSOLUTE_COORDINATE_SYSTEM,
M_ROTATION_YXZ + M_ASSIGN,
M_NULL,
ENCODER_ROTATION_Y,
ENCODER_ROTATION_X,
ENCODER_ROTATION_Z,
M_DEFAULT);
McalSetCoordinateSystem(MilCalibration,
M_TOOL_COORDINATE_SYSTEM,
M_ABSOLUTE_COORDINATE_SYSTEM,
M_TRANSLATION + M_COMPOSE_WITH_CURRENT,
M_NULL,
ENCODER_TRANSLATION_X,
ENCODER_TRANSLATION_Y,
ENCODER_TRANSLATION_Z,
M_DEFAULT);
MbufLoad(OBJECT_MOVED_IMAGE_FILE, MilImage);
MosPrintf(MIL_TEXT("Calibration module moved camera position and camera \n"));
MosPrintf(MIL_TEXT("orientation according to known encoder transformation.\n\n"));
ShowCameraInformation(MilCalibration);
SetCalibrationOffset(MilCalibration, -RING_THICKNESS, MilImage);
MosPrintf(MIL_TEXT("First measured circle at z = %.2f cm. "), -RING_THICKNESS);
MeasureRing(MilSystem, MilDisplay, MilImage, RING1_POS2_X, RING1_POS2_Y );
SetCalibrationOffset(MilCalibration, -(STEP_THICKNESS+RING_THICKNESS), MilImage);
MosPrintf(MIL_TEXT("Second measured circle at z = %.2f cm. "),
-(STEP_THICKNESS+RING_THICKNESS));
MeasureRing(MilSystem, MilDisplay, MilImage, RING2_POS2_X, RING2_POS2_Y );
MosPrintf(MIL_TEXT("Press <Enter> to quit.\n\n"));
MosGetch();
}
else
{
MosPrintf(MIL_TEXT("Calibration generated an exception.\n"));
MosPrintf(MIL_TEXT("See User Guide to resolve the situation.\n\n"));
}
McalFree(MilCalibration);
MbufFree(MilImage);
}
void SetCalibrationOffset(MIL_ID MilCalibration, MIL_DOUBLE ZOffset, MIL_ID MilImage)
{
McalSetCoordinateSystem(MilCalibration,
M_RELATIVE_COORDINATE_SYSTEM,
M_ABSOLUTE_COORDINATE_SYSTEM,
M_TRANSLATION + M_ASSIGN,
M_NULL,
0, 0, ZOffset,
M_DEFAULT);
McalAssociate(MilCalibration, MilImage, M_DEFAULT);
}
void MeasureRing(MIL_ID MilSystem, MIL_ID MilDisplay, MIL_ID MilImage,
MIL_DOUBLE MeasureRingX, MIL_DOUBLE MeasureRingY )
{
MIL_ID MilMetrolContext,
MilMetrolResult,
MilOverlayImage;
MIL_DOUBLE Value;
MdispControl(MilDisplay, M_OVERLAY, M_ENABLE);
MdispInquire(MilDisplay, M_OVERLAY_ID, &MilOverlayImage);
MmetAlloc(MilSystem, M_DEFAULT, &MilMetrolContext);
MmetAllocResult(MilSystem, M_DEFAULT, &MilMetrolResult);
MmetAddFeature(MilMetrolContext, M_MEASURED, M_CIRCLE, MEASURED_CIRCLE_LABEL,
M_DEFAULT, M_NULL, M_NULL, 0, M_DEFAULT);
MmetSetRegion(MilMetrolContext, M_FEATURE_LABEL(MEASURED_CIRCLE_LABEL),
M_DEFAULT, M_RING,
MeasureRingX, MeasureRingY,
RING_START_RADIUS, RING_END_RADIUS,
M_NULL, M_NULL );
MmetCalculate(MilMetrolContext, MilImage, MilMetrolResult, M_DEFAULT);
MgraColor(M_DEFAULT, REGION_COLOR);
MmetDraw(M_DEFAULT, MilMetrolResult, MilOverlayImage, M_DRAW_REGION, M_DEFAULT, M_DEFAULT);
MgraColor(M_DEFAULT, FEATURE_COLOR);
MmetDraw(M_DEFAULT, MilMetrolResult, MilOverlayImage, M_DRAW_FEATURE, M_DEFAULT, M_DEFAULT);
MmetGetResult(MilMetrolResult, M_FEATURE_LABEL(MEASURED_CIRCLE_LABEL), M_RADIUS, &Value);
MosPrintf(MIL_TEXT("Measured Radius: %.3f cm\n"), Value );
MmetFree(MilMetrolResult);
MmetFree(MilMetrolContext);
}
void ShowCameraInformation(MIL_ID MilCalibration)
{
MIL_DOUBLE CameraPosX,
CameraPosY,
CameraPosZ,
CameraYaw,
CameraPitch,
CameraRoll;
McalGetCoordinateSystem(MilCalibration,
M_CAMERA_COORDINATE_SYSTEM,
M_ABSOLUTE_COORDINATE_SYSTEM,
M_TRANSLATION,
M_NULL,
&CameraPosX, &CameraPosY, &CameraPosZ,
M_NULL);
McalGetCoordinateSystem(MilCalibration,
M_CAMERA_COORDINATE_SYSTEM,
M_ABSOLUTE_COORDINATE_SYSTEM,
M_ROTATION_YXZ,
M_NULL,
&CameraYaw, &CameraPitch, &CameraRoll,
M_NULL);
MosPrintf(MIL_TEXT("Camera Position in cm: (x, y, z) ")
MIL_TEXT("(%.2f, %.2f, %.2f)\n"), CameraPosX, CameraPosY, CameraPosZ);
MosPrintf(MIL_TEXT("Camera Orientation in degrees: (yaw, pitch, roll) ")
MIL_TEXT("(%.2f, %.2f, %.2f)\n"), CameraYaw, CameraPitch, CameraRoll);
MosPrintf(MIL_TEXT("Press <Enter> to continue.\n\n"));
MosGetch();
}