#include "CanInspection.h"
void PrintHeader()
{
MosPrintf(MIL_TEXT("[EXAMPLE NAME]\n"));
MosPrintf(MIL_TEXT("CanInspection\n\n"));
MosPrintf(MIL_TEXT("[SYNOPSIS]\n"));
MosPrintf(MIL_TEXT("This example demonstrates the continuous inspection of cans using")
MIL_TEXT("\n3d sheet-of-light profiling. The system consists of two cameras")
MIL_TEXT("\nand one laser. Note that during the setup of the grab, the ")
MIL_TEXT("cameras\nwere synchronized so the same laser scan was provided to ")
MIL_TEXT("all\ncameras at the same time.\n"));
MosPrintf(MIL_TEXT("\n\n"));
MosPrintf(MIL_TEXT("[MODULES USED]\n"));
MosPrintf(MIL_TEXT("Modules used: Application, system, display, buffer, ")
MIL_TEXT("graphic, \nimage processing, calibration, "));
MosPrintf(MIL_TEXT("3d reconstruction, model finder. \n"));
}
static const MIL_INT MAP_SIZE_X = 400;
static const MIL_INT MAP_SIZE_Y = 1020;
int MosMain(void)
{
PrintHeader();
MIL_ID MilApplication = MappAlloc(M_NULL, M_DEFAULT, M_NULL);
CExampleManagerFor3D* pExampleMngrFor3D = MakeExampleManager();
if (!pExampleMngrFor3D)
{
MappFree(MilApplication);
return -1;
}
MosPrintf(MIL_TEXT("Press <Enter> to start.\n\n"));
MosGetch();
const MIL_DOUBLE COL_SPACING [NUM_CAMERAS] = { 5.0, 5.0 };
const MIL_DOUBLE ROW_SPACING [NUM_CAMERAS] = { 5.0, 5.0 };
const MIL_INT NB_ROWS [NUM_CAMERAS] = { 16, 16 };
const MIL_INT NB_COLS [NUM_CAMERAS] = { 15, 15 };
const MIL_DOUBLE CORNER_HINT_X [NUM_CAMERAS] = { 1200, 750 };
const MIL_DOUBLE CORNER_HINT_Y [NUM_CAMERAS] = { 300, 200 };
const MIL_DOUBLE OFFSET_Z [NUM_CAMERAS] = { 0.0, 0.0 };
const MIL_INT64 CALIBRATION_TYPE [NUM_CAMERAS] = { M_CHESSBOARD_GRID, M_CHESSBOARD_GRID};
const MIL_CONST_TEXT_PTR GRID_IMG_FILENAME [NUM_CAMERAS] = { EX_PATH("Cam1_grid.mim"), EX_PATH("Cam2_grid.mim") };
SCameraCalibrationInfo CAMERA_CALIBRATION_INFO[NUM_CAMERAS];
for (MIL_INT c = 0; c < NUM_CAMERAS; c++)
{
SCameraCalibrationInfo& CCI = CAMERA_CALIBRATION_INFO[c];
CCI.CornerHintX = CORNER_HINT_X[c];
CCI.CornerHintY = CORNER_HINT_Y[c];
CCI.OffsetZ = OFFSET_Z[c];
CCI.NbRows = NB_ROWS[c];
CCI.NbCols = NB_COLS[c];
CCI.RowSpacing = ROW_SPACING[c];
CCI.ColSpacing = COL_SPACING[c];
CCI.CalibrationType = CALIBRATION_TYPE[c];
CCI.GridImageFilename = GRID_IMG_FILENAME[c];
CCI.Relocate = NO_RELOCATE;
CCI.RelocatedGridImageFilename = NULL;
}
MIL_ID CameraCalibrations[NUM_CAMERAS];
bool CameraCalibrationOk = pExampleMngrFor3D->CalibrateCameras(CAMERA_CALIBRATION_INFO, NUM_CAMERAS, &CameraCalibrations[0]);
if(CameraCalibrationOk)
{
MosPrintf(MIL_TEXT("Press <Enter> to calibrate laser planes.\n\n"));
MosGetch();
const MIL_INT NUM_REF_PLANES = 5;
const MIL_DOUBLE CAL_MIN_CONTRAST [NUM_CAMERAS] = { 100, 100 };
const MIL_INT CAL_NB_REF_PLANES [NUM_CAMERAS] = { NUM_REF_PLANES, NUM_REF_PLANES };
const MIL_INT CAL_SCAN_ORIENTATION[NUM_CAMERAS] = { M_HORIZONTAL, M_HORIZONTAL };
const MIL_INT CAL_PEAK_WIDTH [NUM_CAMERAS] = { 5, 5 };
const MIL_INT CAL_PEAK_WIDTH_DELTA[NUM_CAMERAS] = { 3, 3 };
const MIL_INT LASER_LABELS [NUM_CAMERAS] = { 1, 1 };
const MIL_INT CAMERA_LABELS [NUM_CAMERAS] = { 1, 2 };
const MIL_DOUBLE PLANE_Z[NUM_CAMERAS][MAX_NB_REF_PLANES] =
{ { 11.72, 5.86, 0.00, -5.86, -11.72 },
{ 11.72, 5.86, 0.00, -5.86, -11.72 } };
const SRefPlaneInfo LASER_CALIBRATION_PLANES[NUM_CAMERAS][MAX_NB_REF_PLANES] =
{ {
{ EX_PATH("Cam1RefPlanes\\Cam1_laser_h-2.mim"), PLANE_Z[0][0] },
{ EX_PATH("Cam1RefPlanes\\Cam1_laser_h-1.mim"), PLANE_Z[0][1] },
{ EX_PATH("Cam1RefPlanes\\Cam1_laser_h0.mim") , PLANE_Z[0][2] },
{ EX_PATH("Cam1RefPlanes\\Cam1_laser_h1.mim") , PLANE_Z[0][3] },
{ EX_PATH("Cam1RefPlanes\\Cam1_laser_h2.mim") , PLANE_Z[0][4] }
},
{
{ EX_PATH("Cam2RefPlanes\\Cam2_laser_h-2.mim"), PLANE_Z[0][0] },
{ EX_PATH("Cam2RefPlanes\\Cam2_laser_h-1.mim"), PLANE_Z[0][1] },
{ EX_PATH("Cam2RefPlanes\\Cam2_laser_h0.mim") , PLANE_Z[0][2] },
{ EX_PATH("Cam2RefPlanes\\Cam2_laser_h1.mim") , PLANE_Z[0][3] },
{ EX_PATH("Cam2RefPlanes\\Cam2_laser_h2.mim") , PLANE_Z[0][4] }
} };
const MIL_INT NUM_LASERS_PER_IMAGE = 1;
SCameraLaserInfo LASER_CALIBRATION_INFO[NUM_CAMERAS * NUM_LASERS_PER_IMAGE];
for(MIL_INT c = 0; c < NUM_CAMERAS; c++)
{
SCameraLaserInfo& LCI = LASER_CALIBRATION_INFO[c];
LCI.NumLasersPerImage = NUM_LASERS_PER_IMAGE;
LCI.NumRefPlanes = NUM_REF_PLANES;
LCI.CalMinContrast = CAL_MIN_CONTRAST[c];
LCI.CalNbRefPlanes = CAL_NB_REF_PLANES[c];
LCI.CalScanOrientation = CAL_SCAN_ORIENTATION[c];
LCI.CalPeakWidthNominal= CAL_PEAK_WIDTH[c];
LCI.CalPeakWidthDelta = CAL_PEAK_WIDTH_DELTA[c];
for(MIL_INT l = 0; l < LCI.CalNbRefPlanes; l++)
{
LCI.LaserCalibrationPlanes[l] = LASER_CALIBRATION_PLANES[c][l];
}
LCI.LaserLabel = LASER_LABELS[c];
LCI.CameraLabel = CAMERA_LABELS[c];
LCI.LineExtractionInROI = eLineNoROI;
}
MIL_ID CameraLaserCtxts[NUM_CAMERAS * NUM_LASERS_PER_IMAGE];
bool SheetOfLightOk = pExampleMngrFor3D->CalibrateSheetOfLight(&LASER_CALIBRATION_INFO[0],
&CameraCalibrations[0],
&CameraLaserCtxts[0]);
if (SheetOfLightOk)
{
const MIL_DOUBLE D3D_DISPLAY_REFRESH_PER_SEC = 0.9;
const MIL_INT CAMERA_MAP_MIN_CONTRAST[] = { 100, 100};
const MIL_INT CAMERA_MAP_PEAK_WIDTH[] = { 4 , 4 };
const MIL_INT CAMERA_MAP_PEAK_DELTA[] = { 16 , 16 };
const MIL_DOUBLE CAMERA_MAP_SCAN_SPEED[] = { 0.2927, 0.2927 };
const MIL_DOUBLE CAMERA_MAX_FRAMES = 2670;
const MIL_DOUBLE CAMERA_DISPLACEMENT_MODE = M_CURRENT;
SMapGeneration MapData;
MapData.BoxCornerX = - 26.90;
MapData.BoxCornerY = 5.47;
MapData.BoxCornerZ = 1.00;
MapData.BoxSizeX = 118.00;
MapData.BoxSizeY = 300.00;
MapData.BoxSizeZ = - 13.00;
MapData.MapSizeX = MAP_SIZE_X;
MapData.MapSizeY = MAP_SIZE_Y;
MapData.PixelSizeX = MapData.BoxSizeX / (MAP_SIZE_X - 1.0);
MapData.PixelSizeY = MapData.BoxSizeY / (MAP_SIZE_Y - 1.0);
MapData.GrayScaleZ = MapData.BoxSizeZ / 65534.0;
MapData.IntensityMapType = 8 + M_UNSIGNED;
MapData.SetExtractOverlap= true;
MapData.ExtractOverlap = M_MIN;
MapData.FillXThreshold = 1.0;
MapData.FillYThreshold = 1.0;
SPointCloudAcquisitionInfo SCAN_INFO =
{
{ D3D_DISPLAY_REFRESH_PER_SEC, SHOW_COLOR },
{ CAMERA_MAP_MIN_CONTRAST[0] , CAMERA_MAP_MIN_CONTRAST[1] },
{ CAMERA_MAP_PEAK_WIDTH[0] , CAMERA_MAP_PEAK_WIDTH[1] },
{ CAMERA_MAP_PEAK_DELTA[0] , CAMERA_MAP_PEAK_DELTA[1] },
{ CAMERA_MAP_SCAN_SPEED[0] , CAMERA_MAP_SCAN_SPEED[1] },
CAMERA_MAX_FRAMES,
CAMERA_DISPLACEMENT_MODE,
eLineNoROI,
{ 0, 0, 0, 0 },
MapData,
{
{ EX_PATH("Cam1_cans.avi"), 0, 0, 0, 0, 0 },
{ EX_PATH("Cam2_cans.avi"), 0, 0, 0, 0, 0 }
},
MIL_TEXT("All scan results are continuously accumulated into a single result\n")
MIL_TEXT("object. Each can is inspected when most of it has been scanned.\n")
MIL_TEXT("Color legend:\n \tGray\t \t= missing data\n \tDark blue \t= ")
MIL_TEXT("minimum height\n \tGreen, Yellow \t= middle height\n \tDark ")
MIL_TEXT("red \t= maximum height\n\n")
};
for(MIL_INT d = 0; d < NUM_CAMERAS; d++)
{ SCAN_INFO.DigInfo[d].UpdateInfoFromDisk(); }
CContinuousCanInspection ProcObj(MapData);
const MIL_INT NB_FRAME_FOR_ANALYSIS = 20;
MIL_ID PointCloudContainer = M_NULL;
pExampleMngrFor3D->AcquirePointCloud(eScanWithContinuousAnalysis,
&SCAN_INFO,
CameraLaserCtxts,
&PointCloudContainer,
&ProcObj,
NB_FRAME_FOR_ANALYSIS);
for (MIL_INT c = 0; c < NUM_CAMERAS; c++)
{
for (MIL_INT l = 0; l < NUM_LASERS_PER_IMAGE; l++)
{
MIL_ID& CameraLaserCtx = CameraLaserCtxts[(c*NUM_LASERS_PER_IMAGE) + l];
if (CameraLaserCtx != M_NULL)
{
M3dmapFree(CameraLaserCtx);
CameraLaserCtx = M_NULL;
}
}
}
M3dmapFree(PointCloudContainer);
}
}
else
{
MosPrintf(MIL_TEXT("Press <Enter> to end.\n\n"));
MosGetch();
}
for (MIL_INT c = 0; c < NUM_CAMERAS; c++)
{
if(CameraCalibrations[c] != M_NULL)
{
McalFree(CameraCalibrations[c]);
CameraCalibrations[c] = M_NULL;
}
}
delete pExampleMngrFor3D;
pExampleMngrFor3D = NULL;
MappFree(MilApplication);
return 0;
}
void CContinuousCanInspection::Analyze(SCommonAnalysisObjects& CommonAnalysisObjects)
{
const MIL_INT NUM_SMOOTH = 99;
const MIL_DOUBLE BINARIZE_THRESHOLD = 62;
const MIL_INT CAN_DELTA_X = 60;
const MIL_INT CAN_DELTA_Y = 60;
const MIL_INT MAX_CAN_MISSING_DATA = 1000;
const MIL_DOUBLE MIN_TAB_HEIGHT = 2.5;
const MIL_DOUBLE MAX_TAB_HEIGHT = 5.5;
const MIL_INT YOffset = 30;
const MIL_DOUBLE PROC_TEXT_COLOR = M_COLOR_GREEN;
const MIL_DOUBLE PROC_PASS_COLOR = M_COLOR_GREEN;
const MIL_DOUBLE PROC_FAIL_COLOR = M_COLOR_RED;
const MIL_INT PROC_TEXT_OFFSET_X = 320;
MIL_ID MilSystem = CommonAnalysisObjects.MilSystem;
MIL_ID MilGraphics = CommonAnalysisObjects.MilGraphics;
MIL_ID MilGraphicList = CommonAnalysisObjects.MilGraphicList;
MIL_ID MilDepthMap = CommonAnalysisObjects.MilDepthMap;
CMILDisplayManager* MilResultsDisplay = CommonAnalysisObjects.MilResultsDisplay;
MilResultsDisplay->Control(M_UPDATE, M_DISABLE);
MdispControl(MilResultsDisplay->GetDisplayID(), M_UPDATE_GRAPHIC_LIST, M_DISABLE);
MgraClear(M_DEFAULT, MilGraphicList);
if(!m_CanFoundSoFar)
{ MgraText(MilGraphics, MilGraphicList, TEXT_OFFSET_X, TEXT_OFFSET_Y, MIL_TEXT("Scanning...")); }
MbufClear(m_Remapped8BitImage, 0);
MimShift(MilDepthMap, m_Remapped8BitImage, -8);
MbufClearCond(m_Remapped8BitImage, 0, 0, 0, m_Remapped8BitImage, M_EQUAL, 255.0);
McalAssociate(M_NULL, m_Remapped8BitImage, M_DEFAULT);
MmodFind(m_CanModel, m_Remapped8BitImage, m_CanModelResult);
MIL_INT NumOfOccurences = 0;
MIL_INT *PositionX, *PositionY;
MmodGetResult(m_CanModelResult, M_DEFAULT, M_NUMBER + M_TYPE_MIL_INT, &NumOfOccurences);
PositionX = new MIL_INT [NumOfOccurences];
PositionY = new MIL_INT [NumOfOccurences];
MmodControl(m_CanModelResult, M_DEFAULT, M_RESULT_OUTPUT_UNITS, M_PIXEL);
MmodGetResult(m_CanModelResult, M_DEFAULT, M_POSITION_X + M_TYPE_MIL_INT, PositionX);
MmodGetResult(m_CanModelResult, M_DEFAULT, M_POSITION_Y + M_TYPE_MIL_INT, PositionY);
MIL_TEXT_CHAR CanString[MAX_STRING_LEN] = MIL_TEXT("");
for (MIL_INT i = 0; i < NumOfOccurences; i++)
{
m_CanFoundSoFar = true;
bool CanOpen = false;
MgraColor(MilGraphics, PROC_PASS_COLOR);
MIL_INT PosX, PosY;
PosX = Max(PositionX[i] - CAN_DELTA_X, MIL_INT(0));
PosY = Max(PositionY[i] - CAN_DELTA_Y, MIL_INT(0));
MIL_INT DeltaX = PositionX[i] - PosX;
MIL_INT DeltaY = PositionY[i] - PosY;
MIL_ID CanChild;
MIL_DOUBLE MissingData = 0.0;
MbufChild2d(MilDepthMap,
PosX,
PosY,
Min(DeltaX * 2, MAP_SIZE_X),
Min(DeltaY * 2, MAP_SIZE_Y),
&CanChild);
M3dmapStat(CanChild, M_NULL, M_NULL, M_NULL, M_NUMBER_OF_PIXELS_MISSING_DATA, M_DEFAULT, M_DEFAULT, &MissingData);
if (MissingData > MAX_CAN_MISSING_DATA)
{ CanOpen = true; }
MbufFree(CanChild);
MmodDraw(MilGraphics, m_CanModelResult, MilGraphicList, M_DRAW_POSITION + M_DRAW_EDGES, i, M_DEFAULT);
MmodControl(m_TabModel, M_DEFAULT, M_POSITION_X, PositionX[i]);
MmodControl(m_TabModel, M_DEFAULT, M_POSITION_Y, PositionY[i]);
MmodFind(m_TabModel, m_Remapped8BitImage, m_TabModelResult);
MIL_INT TabOccurences = 0;
MmodGetResult(m_TabModelResult, M_DEFAULT, M_NUMBER + M_TYPE_MIL_INT, &TabOccurences);
bool TabElevated = false;
bool TabBroken = false;
bool TabFound = (TabOccurences == 1);
if(TabFound)
{
MmodGetResult(m_TabModelResult, M_DEFAULT, M_POSITION_X + M_TYPE_MIL_INT, PositionX);
MmodGetResult(m_TabModelResult, M_DEFAULT, M_POSITION_Y + M_TYPE_MIL_INT, PositionY);
MIL_ID TabChild;
MIL_DOUBLE DeviationMean = -DBL_MAX;
const MIL_INT STAT_SIZE = 4;
const MIL_DOUBLE DEVIATION_OUTLIER_DISTANCE = 12.0;
PosX = Max(PositionX[0] - STAT_SIZE, MIL_INT(0));
PosY = Max(PositionY[0] - STAT_SIZE, MIL_INT(0));
MbufChild2d(MilDepthMap, PosX, PosY, STAT_SIZE, STAT_SIZE, &TabChild);
M3dmapStat(TabChild, M_NULL, M_NULL, M_NULL, M_DEVIATION_MEAN + M_STAT_NEGATIVE, DEVIATION_OUTLIER_DISTANCE, M_DEFAULT, &DeviationMean);
MbufFree(TabChild);
TabBroken = (DeviationMean < MIN_TAB_HEIGHT);
TabElevated = (DeviationMean > MAX_TAB_HEIGHT);
}
MgraColor(MilGraphics, CanOpen ? PROC_FAIL_COLOR : PROC_PASS_COLOR);
MosSprintf(CanString, MAX_STRING_LEN, MIL_TEXT("Can surface: %s"), CanOpen ? MIL_TEXT("open") : MIL_TEXT("pass"));
MgraText(MilGraphics, MilGraphicList, PROC_TEXT_OFFSET_X, PositionY[i]-CAN_DELTA_Y, CanString);
MIL_CONST_TEXT_PTR pTabStr = M_NULL;
if(TabFound)
{
if(TabElevated)
{
MgraColor(MilGraphics, PROC_FAIL_COLOR);
pTabStr = MIL_TEXT("elevated");
}
else if(TabBroken)
{
MgraColor(MilGraphics, PROC_FAIL_COLOR);
pTabStr = MIL_TEXT("broken");
}
else
{
MgraColor(MilGraphics, PROC_PASS_COLOR);
pTabStr = MIL_TEXT("pass");
}
}
else
{
MgraColor(MilGraphics, PROC_FAIL_COLOR);
pTabStr = MIL_TEXT("missing");
}
MosSprintf(CanString, MAX_STRING_LEN, MIL_TEXT("Tab : %s"), pTabStr);
MgraText(MilGraphics, MilGraphicList, PROC_TEXT_OFFSET_X, PositionY[i]-CAN_DELTA_Y+YOffset, CanString);
MmodDraw(MilGraphics, m_TabModelResult, MilGraphicList, M_DRAW_EDGES, M_ALL, M_DEFAULT);
}
MdispControl(MilResultsDisplay->GetDisplayID(), M_UPDATE_GRAPHIC_LIST, M_ENABLE);
MilResultsDisplay->Control(M_TITLE, (MIL_DOUBLE)(M_PTR_TO_DOUBLE(MIL_TEXT("Inspection results"))));
MilResultsDisplay->Show(m_Remapped8BitImage);
MilResultsDisplay->Control(M_UPDATE, M_ENABLE);
delete [] PositionX;
delete [] PositionY;
}
void CContinuousCanInspection::AllocProcessingObjects(MIL_ID MilSystem)
{
const MIL_TEXT_CHAR* CAN_MODEL = EX_PATH("CanModel.mmf");
const MIL_TEXT_CHAR* TAB_MODEL = EX_PATH("TabModel.mmf");
const MIL_INT CAN_SIZE_Y = 240;
const MIL_INT RESULTS_SIZE_X = 630;
const MIL_INT SizeY = CAN_SIZE_Y * 2;
MbufAlloc2d(MilSystem, RESULTS_SIZE_X, SizeY, 8, M_IMAGE + M_PROC + M_DISP, &m_Remapped8BitImage);
MmodAllocResult(MilSystem, M_DEFAULT, &m_CanModelResult);
MmodRestore(CAN_MODEL, MilSystem, M_DEFAULT, &m_CanModel);
MmodPreprocess(m_CanModel, M_DEFAULT);
MmodAllocResult(MilSystem, M_DEFAULT, &m_TabModelResult);
MmodRestore(TAB_MODEL, MilSystem, M_DEFAULT, &m_TabModel);
MmodPreprocess(m_TabModel, M_DEFAULT);
}
void CContinuousCanInspection::FreeProcessingObjects()
{
MbufFree(m_Remapped8BitImage);
MmodFree(m_CanModel);
MmodFree(m_CanModelResult);
MmodFree(m_TabModel);
MmodFree(m_TabModelResult);
m_CanFoundSoFar = false;
}