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