Click here to show toolbars of the Web Online Help System: show toolbars |
'*************************************************************************** ' ' File name: M3dmap.vb ' Location: See Matrox Example Launcher in the MIL Control Center ' ' ' Synopsis: This program inspects a wood surface using ' sheet-of-light profiling (laser) to find any depth defects. ' ' Printable calibration grids in PDF format can be found in your ' "Matrox Imaging/Images/" directory. ' ' When considering a laser-based 3D reconstruction system, the file "3D Setup Helper.xls" ' can be used to accelerate prototyping by choosing an adequate hardware configuration ' (angle, distance, lens, camera, ...). The file is located in your ' "Matrox Imaging/Tools/" directory. ' ' Copyright (C) Matrox Electronic Systems Ltd., 1992-2016. ' All Rights Reserved '*************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Collections.Generic Imports System.Text Imports System.Runtime.InteropServices Imports Matrox.MatroxImagingLibrary Namespace M3dmap Friend Class Program ' Function declarations for DirectX display <DllImport("mdispd3d.dll", CallingConvention:=CallingConvention.Cdecl)> _ Public Shared Function MdepthD3DAlloc(ByVal DepthBuffer As MIL_ID, _ ByVal IntensityBuffer As MIL_ID, _ ByVal DisplaySizeX As MIL_INT, _ ByVal DisplaySizeY As MIL_INT, _ ByVal ScaleX As Double, _ ByVal ScaleY As Double, _ ByVal ScaleZ As Double, _ ByVal MinZ As Double, _ ByVal MaxZ As Double, _ ByVal MaxDistanceZ As Double, _ ByVal WindowHandle As IntPtr) As IntPtr End Function <DllImport("mdispd3d.dll", CallingConvention:=CallingConvention.Cdecl)> _ Public Shared Sub MdispD3DFree(ByVal DispHandle As IntPtr) End Sub <DllImport("mdispd3d.dll", CallingConvention:=CallingConvention.Cdecl)> _ Public Shared Sub MdispD3DShow(ByVal DispHandle As IntPtr) End Sub <DllImport("mdispd3d.dll", CallingConvention:=CallingConvention.Cdecl)> _ Public Shared Sub MdispD3DHide(ByVal DispHandle As IntPtr) End Sub <DllImport("mdispd3d.dll", CallingConvention:=CallingConvention.Cdecl)> _ Public Shared Sub MdispD3DPrintHelp(ByVal DispHandle As IntPtr) End Sub Shared Sub Main(ByVal args() As String) '**************************************************************************** ' Main. '**************************************************************************** Dim MilApplication As MIL_ID = MIL.M_NULL ' Application identifier. Dim MilSystem As MIL_ID = MIL.M_NULL ' System identifier. Dim MilDisplay As MIL_ID = MIL.M_NULL ' Display identifier. ' Allocate defaults. MIL.MappAllocDefault(MIL.M_DEFAULT, MilApplication, MilSystem, MilDisplay, CType(MIL.M_NULL, IntPtr), CType(MIL.M_NULL, IntPtr)) ' Run the depth correction example. DepthCorrectionExample(MilSystem, MilDisplay) ' Run the calibrated camera example. CalibratedCameraExample(MilSystem, MilDisplay) ' Free defaults. MIL.MappFreeDefault(MilApplication, MilSystem, MilDisplay, MIL.M_NULL, MIL.M_NULL) End Sub '*************************************************************************** ' Depth correction example. '*************************************************************************** ' Input sequence specifications. Private Const REFERENCE_PLANES_SEQUENCE_FILE As String = MIL.M_IMAGE_PATH & "ReferencePlanes.avi" Private Const OBJECT_SEQUENCE_FILE As String = MIL.M_IMAGE_PATH & "ScannedObject.avi" ' Peak detection parameters. Private Const PEAK_WIDTH_NOMINAL As Integer = 10 Private Const PEAK_WIDTH_DELTA As Integer = 8 Private Const MIN_CONTRAST As Integer = 140 ' Calibration heights in mm. Private Shared ReadOnly CORRECTED_DEPTHS() As Double = {1.25, 2.5, 3.75, 5.0} Private Const SCALE_FACTOR As Double = 10000.0 ' (depth in world units) * SCALE_FACTOR gives gray levels ' Annotation position. Private Const CALIB_TEXT_POS_X As Double = 400 Private Const CALIB_TEXT_POS_Y As Double = 15 Private Shared Sub DepthCorrectionExample(ByVal MilSystem As MIL_ID, ByVal MilDisplay As MIL_ID) Dim MilOverlayImage As MIL_ID = MIL.M_NULL ' Overlay image buffer identifier. Dim MilImage As MIL_ID = MIL.M_NULL ' Image buffer identifier (for processing). Dim MilDepthMap As MIL_ID = MIL.M_NULL ' Image buffer identifier (for results). Dim MilLaser As MIL_ID = MIL.M_NULL ' 3dmap laser profiling context identifier. Dim MilCalibScan As MIL_ID = MIL.M_NULL ' 3dmap result buffer identifier for ' laser line calibration. Dim MilScan As MIL_ID = MIL.M_NULL ' 3dmap result buffer identifier. Dim SizeX As MIL_INT = 0 ' Width of grabbed images. Dim SizeY As MIL_INT = 0 ' Height of grabbed images. Dim NbReferencePlanes As MIL_INT = 0 ' Number of reference planes of known heights. Dim NbObjectImages As MIL_INT = 0 ' Number of frames for scanned objects. Dim n As MIL_INT = 0 ' Counter. Dim FrameRate As Double = 0.0 ' Number of grabbed frames per second (in AVI). Dim StartTime As Double = 0.0 ' Time at the beginning of each iteration. Dim EndTime As Double = 0.0 ' Time after processing for each iteration. Dim WaitTime As Double = 0.0 ' Time to wait for next frame. ' Inquire characteristics of the input sequences. MIL.MbufDiskInquire(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_SIZE_X, SizeX) MIL.MbufDiskInquire(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_SIZE_Y, SizeY) MIL.MbufDiskInquire(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_NUMBER_OF_IMAGES, NbReferencePlanes) MIL.MbufDiskInquire(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_FRAME_RATE, FrameRate) MIL.MbufDiskInquire(OBJECT_SEQUENCE_FILE, MIL.M_NUMBER_OF_IMAGES, NbObjectImages) ' Allocate buffer to hold images. MIL.MbufAlloc2d(MilSystem, SizeX, SizeY, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_DISP + MIL.M_PROC, MilImage) MIL.MbufClear(MilImage, 0.0) Console.WriteLine() Console.WriteLine("DEPTH ANALYSIS:") Console.WriteLine("---------------") Console.WriteLine() Console.WriteLine("This program performs a surface inspection to detect depth") Console.WriteLine("defects on a wood surface using a laser (sheet-of-light) profiling system.") Console.WriteLine() Console.WriteLine("Press <Enter> to continue.") Console.WriteLine() Console.ReadKey() ' Select display. MIL.MdispSelect(MilDisplay, MilImage) ' Prepare for overlay annotations. MIL.MdispControl(MilDisplay, MIL.M_OVERLAY, MIL.M_ENABLE) MIL.MdispInquire(MilDisplay, MIL.M_OVERLAY_ID, MilOverlayImage) MIL.MgraControl(MIL.M_DEFAULT, MIL.M_BACKGROUND_MODE, MIL.M_TRANSPARENT) MIL.MgraColor(MIL.M_DEFAULT, MIL.M_COLOR_WHITE) ' Allocate 3dmap objects. MIL.M3dmapAlloc(MilSystem, MIL.M_LASER, MIL.M_DEPTH_CORRECTION, MilLaser) MIL.M3dmapAllocResult(MilSystem, MIL.M_LASER_CALIBRATION_DATA, MIL.M_DEFAULT, MilCalibScan) ' Set laser line extraction options. Dim MilPeakLocator As MIL_ID = MIL.M_NULL MIL.M3dmapInquire(MilLaser, MIL.M_DEFAULT, MIL.M_LOCATE_PEAK_1D_CONTEXT_ID + MIL.M_TYPE_MIL_ID, MilPeakLocator) MIL.MimControl(MilPeakLocator, MIL.M_PEAK_WIDTH_NOMINAL, PEAK_WIDTH_NOMINAL) MIL.MimControl(MilPeakLocator, MIL.M_PEAK_WIDTH_DELTA, PEAK_WIDTH_DELTA) MIL.MimControl(MilPeakLocator, MIL.M_MINIMUM_CONTRAST, MIN_CONTRAST) ' Open the calibration sequence file for reading. MIL.MbufImportSequence(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, CType(MIL.M_NULL, IntPtr), MIL.M_NULL, MIL.M_NULL, MIL.M_OPEN) ' Read and process all images in the input sequence. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, StartTime) For n = 0 To NbReferencePlanes - 1 Dim CalibString As String ' Read image from sequence. MIL.MbufImportSequence(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_LOAD, MIL.M_NULL, MilImage, MIL.M_DEFAULT, 1, MIL.M_READ) ' Annotate the image with the calibration height. MIL.MdispControl(MilDisplay, MIL.M_OVERLAY_CLEAR, MIL.M_DEFAULT) CalibString = String.Format("Reference plane {0}: {1:0.00} mm", n + 1, CORRECTED_DEPTHS(CType(n, Integer))) MIL.MgraText(MIL.M_DEFAULT, MilOverlayImage, CALIB_TEXT_POS_X, CALIB_TEXT_POS_Y, CalibString) ' Set desired corrected depth of next calibration plane. MIL.M3dmapControl(MilLaser, MIL.M_DEFAULT, MIL.M_CORRECTED_DEPTH, CORRECTED_DEPTHS(CType(n, Integer)) * SCALE_FACTOR) ' Analyze the image to extract laser line. MIL.M3dmapAddScan(MilLaser, MilCalibScan, MilImage, MIL.M_NULL, MIL.M_NULL, MIL.M_DEFAULT, MIL.M_DEFAULT) ' Wait to have a proper frame rate, if necessary. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, EndTime) WaitTime = (1.0 / FrameRate) - (EndTime - StartTime) If WaitTime > 0 Then MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_WAIT, WaitTime) End If MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, StartTime) Next n ' Close the calibration sequence file. MIL.MbufImportSequence(REFERENCE_PLANES_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, CType(MIL.M_NULL, IntPtr), MIL.M_NULL, MIL.M_NULL, MIL.M_CLOSE) ' Calibrate the laser profiling context using reference planes of known heights. MIL.M3dmapCalibrate(MilLaser, MilCalibScan, MIL.M_NULL, MIL.M_DEFAULT) Console.WriteLine("The laser profiling system has been calibrated using 4 reference") Console.WriteLine("planes of known heights.") Console.WriteLine() Console.WriteLine("Press <Enter> to continue.") Console.WriteLine() Console.ReadKey() Console.WriteLine("The wood surface is being scanned.") Console.WriteLine() ' Free the result buffer used for calibration because it will not be used anymore. MIL.M3dmapFree(MilCalibScan) MilCalibScan = MIL.M_NULL ' Allocate the result buffer for the scanned depth corrected data. MIL.M3dmapAllocResult(MilSystem, MIL.M_DEPTH_CORRECTED_DATA, MIL.M_DEFAULT, MilScan) ' Open the object sequence file for reading. MIL.MbufDiskInquire(OBJECT_SEQUENCE_FILE, MIL.M_FRAME_RATE, FrameRate) MIL.MbufImportSequence(OBJECT_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, CType(MIL.M_NULL, IntPtr), MIL.M_NULL, MIL.M_NULL, MIL.M_OPEN) ' Read and process all images in the input sequence. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, StartTime) MIL.MdispControl(MilDisplay, MIL.M_OVERLAY_CLEAR, MIL.M_DEFAULT) For n = 0 To NbObjectImages - 1 ' Read image from sequence. MIL.MbufImportSequence(OBJECT_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_LOAD, MIL.M_NULL, MilImage, MIL.M_DEFAULT, 1, MIL.M_READ) ' Analyze the image to extract laser line and correct its depth. MIL.M3dmapAddScan(MilLaser, MilScan, MilImage, MIL.M_NULL, MIL.M_NULL, MIL.M_DEFAULT, MIL.M_DEFAULT) ' Wait to have a proper frame rate, if necessary. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, EndTime) WaitTime = (1.0 / FrameRate) - (EndTime - StartTime) If WaitTime > 0 Then MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_WAIT, WaitTime) End If MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, StartTime) Next n ' Close the object sequence file. MIL.MbufImportSequence(OBJECT_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, CType(MIL.M_NULL, IntPtr), MIL.M_NULL, MIL.M_NULL, MIL.M_CLOSE) ' Allocate the image for a partially corrected depth map. MIL.MbufAlloc2d(MilSystem, SizeX, NbObjectImages, 16 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC + MIL.M_DISP, MilDepthMap) ' Get partially corrected depth map from accumulated information in the result buffer. MIL.M3dmapExtract(MilScan, MilDepthMap, MIL.M_NULL, MIL.M_CORRECTED_DEPTH_MAP, MIL.M_DEFAULT, MIL.M_DEFAULT) ' Show partially corrected depth map and find defects. SetupColorDisplay(MilSystem, MilDisplay, MIL.MbufInquire(MilDepthMap, MIL.M_SIZE_BIT, MIL.M_NULL)) ' Display partially corrected depth map. MIL.MdispSelect(MilDisplay, MilDepthMap) MIL.MdispInquire(MilDisplay, MIL.M_OVERLAY_ID, MilOverlayImage) Console.WriteLine("The pseudo-color depth map of the surface is displayed.") Console.WriteLine() Console.WriteLine("Press <Enter> to continue.") Console.WriteLine() Console.ReadKey() PerformBlobAnalysis(MilSystem, MilDisplay, MilOverlayImage, MilDepthMap) Console.WriteLine("Press <Enter> to continue.") Console.WriteLine() Console.ReadKey() ' Disassociates display LUT and clear overlay. MIL.MdispLut(MilDisplay, MIL.M_DEFAULT) MIL.MdispControl(MilDisplay, MIL.M_OVERLAY_CLEAR, MIL.M_DEFAULT) ' Free all allocations. MIL.M3dmapFree(MilScan) MIL.M3dmapFree(MilLaser) MIL.MbufFree(MilDepthMap) MIL.MbufFree(MilImage) End Sub ' Values used for binarization. Private Const EXPECTED_HEIGHT As Double = 3.4 ' Inspected surface should be at this height (in mm) Private Const DEFECT_THRESHOLD As Double = 0.2 ' Max acceptable deviation from expected height (mm) Private Const SATURATED_DEFECT As Double = 1.0 ' Deviation at which defect will appear red (in mm) ' Radius of the smallest particles to keep. Private Const MIN_BLOB_RADIUS As Integer = 3 ' Pixel offset for drawing text. Private Const TEXT_H_OFFSET_1 As Double = -50 Private Const TEXT_V_OFFSET_1 As Double = -6 Private Const TEXT_H_OFFSET_2 As Double = -30 Private Const TEXT_V_OFFSET_2 As Double = 6 ' Find defects in corrected depth map, compute max deviation and draw contours. Private Shared Sub PerformBlobAnalysis(ByVal MilSystem As MIL_ID, ByVal MilDisplay As MIL_ID, ByVal MilOverlayImage As MIL_ID, ByVal MilDepthMap As MIL_ID) Dim MilBinImage As MIL_ID = MIL.M_NULL ' Binary image buffer identifier. Dim MilBlobContext As MIL_ID = MIL.M_NULL ' Blob context identifier. Dim MilBlobResult As MIL_ID = MIL.M_NULL ' Blob result buffer identifier. Dim SizeX As MIL_INT = 0 ' Width of depth map. Dim SizeY As MIL_INT = 0 ' Height of depth map. Dim TotalBlobs As MIL_INT = 0 ' Total number of blobs. Dim n As MIL_INT = 0 ' Counter. Dim MinPixels() As MIL_INT = Nothing ' Maximum height of defects. Dim DefectThreshold As Double = 0.0 ' A gray level below it is a defect. Dim CogX() As Double = Nothing ' X coordinate of center of gravity. Dim CogY() As Double = Nothing ' Y coordinate of center of gravity. ' Get size of depth map. MIL.MbufInquire(MilDepthMap, MIL.M_SIZE_X, SizeX) MIL.MbufInquire(MilDepthMap, MIL.M_SIZE_Y, SizeY) ' Allocate a binary image buffer for fast processing. MIL.MbufAlloc2d(MilSystem, SizeX, SizeY, 1 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC, MilBinImage) ' Binarize image. DefectThreshold = (EXPECTED_HEIGHT - DEFECT_THRESHOLD) * SCALE_FACTOR MIL.MimBinarize(MilDepthMap, MilBinImage, MIL.M_FIXED + MIL.M_LESS_OR_EQUAL, DefectThreshold, MIL.M_NULL) ' Remove small particles. MIL.MimOpen(MilBinImage, MilBinImage, MIN_BLOB_RADIUS, MIL.M_BINARY) ' Allocate a blob context. MIL.MblobAlloc(MilSystem, MIL.M_DEFAULT, MIL.M_DEFAULT, MilBlobContext) ' Enable the Center Of Gravity and Min Pixel features calculation. MIL.MblobControl(MilBlobContext, MIL.M_CENTER_OF_GRAVITY + MIL.M_GRAYSCALE, MIL.M_ENABLE) MIL.MblobControl(MilBlobContext, MIL.M_MIN_PIXEL, MIL.M_ENABLE) ' Allocate a blob result buffer. MIL.MblobAllocResult(MilSystem, MIL.M_DEFAULT, MIL.M_DEFAULT, MilBlobResult) ' Calculate selected features for each blob. MIL.MblobCalculate(MilBlobContext, MilBinImage, MilDepthMap, MilBlobResult) ' Get the total number of selected blobs. MIL.MblobGetResult(MilBlobResult, MIL.M_DEFAULT, MIL.M_NUMBER + MIL.M_TYPE_MIL_INT, TotalBlobs) Console.WriteLine("Number of defects: {0}", TotalBlobs) ' Read and print the blob characteristics. CogX = New Double(CType(TotalBlobs, Integer) - 1) {} CogY = New Double(CType(TotalBlobs, Integer) - 1) {} MinPixels = New MIL_INT(CType(TotalBlobs, Integer) - 1) {} If CogX IsNot Nothing AndAlso CogY IsNot Nothing AndAlso MinPixels IsNot Nothing Then ' Get the results. MIL.MblobGetResult(MilBlobResult, MIL.M_DEFAULT, MIL.M_CENTER_OF_GRAVITY_X + MIL.M_GRAYSCALE, CogX) MIL.MblobGetResult(MilBlobResult, MIL.M_DEFAULT, MIL.M_CENTER_OF_GRAVITY_Y + MIL.M_GRAYSCALE, CogY) MIL.MblobGetResult(MilBlobResult, MIL.M_DEFAULT, MIL.M_MIN_PIXEL + MIL.M_TYPE_MIL_INT, MinPixels) ' Draw the defects. MIL.MgraColor(MIL.M_DEFAULT, MIL.M_COLOR_RED) MIL.MblobDraw(MIL.M_DEFAULT, MilBlobResult, MilOverlayImage, MIL.M_DRAW_BLOBS, MIL.M_INCLUDED_BLOBS, MIL.M_DEFAULT) MIL.MgraColor(MIL.M_DEFAULT, MIL.M_COLOR_WHITE) ' Print the depth of each blob. For n = 0 To TotalBlobs - 1 Dim DepthOfDefect As Double Dim DepthString As String ' Write the depth of the defect in the overlay. DepthOfDefect = EXPECTED_HEIGHT - (CType(MinPixels(CType(n, Integer)), Double) / SCALE_FACTOR) DepthString = String.Format("{0:0.00} mm", DepthOfDefect) Console.WriteLine("Defect #{0}: depth ={1,5:0.00} mm", n, DepthOfDefect) Console.WriteLine() MIL.MgraText(MIL.M_DEFAULT, MilOverlayImage, CogX(CType(n, Integer)) + TEXT_H_OFFSET_1, CogY(CType(n, Integer)) + TEXT_V_OFFSET_1, "Defect depth") MIL.MgraText(MIL.M_DEFAULT, MilOverlayImage, CogX(CType(n, Integer)) + TEXT_H_OFFSET_2, CogY(CType(n, Integer)) + TEXT_V_OFFSET_2, DepthString) Next n Else Console.WriteLine("Error: Not enough memory.") End If ' Free all allocations. MIL.MblobFree(MilBlobResult) MIL.MblobFree(MilBlobContext) MIL.MbufFree(MilBinImage) End Sub ' Color constants for display LUT. Private Const BLUE_HUE As Double = 171.0 ' Expected depths will be blue. Private Const RED_HUE As Double = 0.0 ' Worst defects will be red. Private Const FULL_SATURATION As Integer = 255 ' All colors are fully saturated. Private Const HALF_LUMINANCE As Integer = 128 ' All colors have half luminance. ' Creates a color display LUT to show defects in red. Private Shared Sub SetupColorDisplay(ByVal MilSystem As MIL_ID, ByVal MilDisplay As MIL_ID, ByVal SizeBit As MIL_INT) Dim MilRampLut1Band As MIL_ID = MIL.M_NULL ' LUT containing hue values. Dim MilRampLut3Band As MIL_ID = MIL.M_NULL ' RGB LUT used by display. Dim MilColorImage As MIL_ID = MIL.M_NULL ' Image used for HSL to RGB conversion. Dim DefectGrayLevel As MIL_INT = 0 ' Gray level under which all is red. Dim ExpectedGrayLevel As MIL_INT = 0 ' Gray level over which all is blue. Dim NbGrayLevels As MIL_INT ' Number of possible gray levels in corrected depth map. NbGrayLevels = CType(1 << CType(SizeBit, Integer), MIL_INT) ' Allocate 1-band LUT that will contain hue values. MIL.MbufAlloc1d(MilSystem, NbGrayLevels, 8 + MIL.M_UNSIGNED, MIL.M_LUT, MilRampLut1Band) ' Compute limit gray values. DefectGrayLevel = CType((EXPECTED_HEIGHT - SATURATED_DEFECT) * SCALE_FACTOR, MIL_INT) ExpectedGrayLevel = CType(EXPECTED_HEIGHT * SCALE_FACTOR, MIL_INT) ' Create hue values for each possible gray level. MIL.MgenLutRamp(MilRampLut1Band, 0, RED_HUE, DefectGrayLevel, RED_HUE) MIL.MgenLutRamp(MilRampLut1Band, DefectGrayLevel, RED_HUE, ExpectedGrayLevel, BLUE_HUE) MIL.MgenLutRamp(MilRampLut1Band, ExpectedGrayLevel, BLUE_HUE, NbGrayLevels - 1, BLUE_HUE) ' Create a HSL image buffer. MIL.MbufAllocColor(MilSystem, 3, NbGrayLevels, 1, 8 + MIL.M_UNSIGNED, MIL.M_IMAGE, MilColorImage) MIL.MbufClear(MilColorImage, MIL.M_RGB888(0, FULL_SATURATION, HALF_LUMINANCE)) ' Set its H band (hue) to the LUT contents and convert the image to RGB. MIL.MbufCopyColor2d(MilRampLut1Band, MilColorImage, 0, 0, 0, 0, 0, 0, NbGrayLevels, 1) MIL.MimConvert(MilColorImage, MilColorImage, MIL.M_HSL_TO_RGB) ' Create RGB LUT to give to display and copy image contents. MIL.MbufAllocColor(MilSystem, 3, NbGrayLevels, 1, 8 + MIL.M_UNSIGNED, MIL.M_LUT, MilRampLut3Band) MIL.MbufCopy(MilColorImage, MilRampLut3Band) ' Associates LUT to display. MIL.MdispLut(MilDisplay, MilRampLut3Band) ' Free all allocations. MIL.MbufFree(MilRampLut1Band) MIL.MbufFree(MilRampLut3Band) MIL.MbufFree(MilColorImage) End Sub '*************************************************************************** ' Calibrated camera example. '*************************************************************************** ' Input sequence specifications. Private Const GRID_FILENAME As String = MIL.M_IMAGE_PATH & "GridForLaser.mim" Private Const LASERLINE_FILENAME As String = MIL.M_IMAGE_PATH & "LaserLine.mim" Private Const OBJECT2_SEQUENCE_FILE As String = MIL.M_IMAGE_PATH & "Cookie.avi" ' Camera calibration grid parameters. Private Shared ReadOnly GRID_NB_ROWS As MIL_INT = 13 Private Shared ReadOnly GRID_NB_COLS As MIL_INT = 12 Private Const GRID_ROW_SPACING As Double = 5.0 ' in mm Private Const GRID_COL_SPACING As Double = 5.0 ' in mm ' Laser device setup parameters. Private Const CONVEYOR_SPEED As Double = -0.2 ' in mm/frame ' Fully corrected depth map generation parameters. Private Shared ReadOnly DEPTH_MAP_SIZE_X As MIL_INT = 480 ' in pixels Private Shared ReadOnly DEPTH_MAP_SIZE_Y As MIL_INT = 480 ' in pixels Private Const GAP_DEPTH As Double = 1.5 ' in mm ' D3D display parameters Private Shared ReadOnly D3D_DISPLAY_SIZE_X As MIL_INT = 640 Private Shared ReadOnly D3D_DISPLAY_SIZE_Y As MIL_INT = 480 ' Peak detection parameters. Private Shared ReadOnly PEAK_WIDTH_NOMINAL_2 As MIL_INT = 9 Private Shared ReadOnly PEAK_WIDTH_DELTA_2 As MIL_INT = 7 Private Shared ReadOnly MIN_CONTRAST_2 As MIL_INT = 75 ' Everything below this is considered as noise. Private Const MIN_HEIGHT_THRESHOLD As Double = 1.0 ' in mm Private Shared Sub CalibratedCameraExample(ByVal MilSystem As MIL_ID, ByVal MilDisplay As MIL_ID) Dim MilOverlayImage As MIL_ID = MIL.M_NULL ' Overlay image buffer identifier. Dim MilImage As MIL_ID = MIL.M_NULL ' Image buffer identifier (for processing). Dim MilCalibration As MIL_ID = MIL.M_NULL ' Calibration context. Dim DepthMapId As MIL_ID = MIL.M_NULL ' Image buffer identifier (for results). Dim LaserId As MIL_ID = MIL.M_NULL ' 3dmap laser profiling context identifier. Dim CalibScanId As MIL_ID = MIL.M_NULL ' 3dmap result buffer identifier for ' laser line calibration. Dim ScanId As MIL_ID = MIL.M_NULL ' 3dmap result buffer identifier. Dim CalibrationStatus As MIL_INT = 0 ' Used to ensure if McalGrid() worked. Dim SizeX As MIL_INT = 0 ' Width of grabbed images. Dim SizeY As MIL_INT = 0 ' Height of grabbed images. Dim NumberOfImages As MIL_INT = 0 ' Number of frames for scanned objects. Dim n As MIL_INT = 0 ' Counter. Dim FrameRate As Double = 0.0 ' Number of grabbed frames per second (in AVI). Dim StartTime As Double = 0.0 ' Time at the beginning of each iteration. Dim EndTime As Double = 0.0 ' Time after processing for each iteration. Dim WaitTime As Double = 0.0 ' Time to wait for next frame. Dim Volume As Double = 0.0 ' Volume of scanned object. Dim VolumeError As Double = 0.0 ' Volume of region outside the object. Console.WriteLine() Console.WriteLine("3D PROFILING AND VOLUME ANALYSIS:") Console.WriteLine("---------------------------------") Console.WriteLine() Console.WriteLine("This program generates fully corrected 3d data of a") Console.WriteLine("scanned cookie and computes its volume.") Console.WriteLine("The laser (sheet-of-light) profiling system uses a") Console.WriteLine("3d-calibrated camera.") Console.WriteLine() ' Load grid image for camera calibration. MIL.MbufRestore(GRID_FILENAME, MilSystem, MilImage) ' Select display. MIL.MdispSelect(MilDisplay, MilImage) Console.WriteLine("Calibrating the camera...") Console.WriteLine() MIL.MbufInquire(MilImage, MIL.M_SIZE_X, SizeX) MIL.MbufInquire(MilImage, MIL.M_SIZE_Y, SizeY) ' Allocate calibration context in 3D mode. MIL.McalAlloc(MilSystem, MIL.M_TSAI_BASED, MIL.M_DEFAULT, MilCalibration) ' Calibrate the camera. MIL.McalGrid(MilCalibration, MilImage, 0.0, 0.0, 0.0, GRID_NB_ROWS, GRID_NB_COLS, GRID_ROW_SPACING, GRID_COL_SPACING, MIL.M_DEFAULT, MIL.M_CHESSBOARD_GRID) MIL.McalInquire(MilCalibration, MIL.M_CALIBRATION_STATUS + MIL.M_TYPE_MIL_INT, CalibrationStatus) If CalibrationStatus <> MIL.M_CALIBRATED Then MIL.McalFree(MilCalibration) MIL.MbufFree(MilImage) Console.WriteLine("Camera calibration failed.") Console.WriteLine("Press <Enter> to end.") Console.WriteLine() Console.ReadLine() Return End If ' Prepare for overlay annotations. MIL.MdispControl(MilDisplay, MIL.M_OVERLAY, MIL.M_ENABLE) MIL.MdispInquire(MilDisplay, MIL.M_OVERLAY_ID, MilOverlayImage) MIL.MgraColor(MIL.M_DEFAULT, MIL.M_COLOR_GREEN) ' Draw camera calibration points. MIL.McalDraw(MIL.M_DEFAULT, MilCalibration, MilOverlayImage, MIL.M_DRAW_IMAGE_POINTS, MIL.M_DEFAULT, MIL.M_DEFAULT) Console.WriteLine("The camera was calibrated using a chessboard grid.") Console.WriteLine() Console.WriteLine("Press <Enter> to continue.") Console.WriteLine() Console.ReadKey() ' Disable overlay. MIL.MdispControl(MilDisplay, MIL.M_OVERLAY, MIL.M_DISABLE) ' Load laser line image. MIL.MbufLoad(LASERLINE_FILENAME, MilImage) ' Allocate 3dmap objects. MIL.M3dmapAlloc(MilSystem, MIL.M_LASER, MIL.M_CALIBRATED_CAMERA_LINEAR_MOTION, LaserId) MIL.M3dmapAllocResult(MilSystem, MIL.M_LASER_CALIBRATION_DATA, MIL.M_DEFAULT, CalibScanId) ' Set laser line extraction options. Dim MilPeakLocator As MIL_ID = MIL.M_NULL MIL.M3dmapInquire(LaserId, MIL.M_DEFAULT, MIL.M_LOCATE_PEAK_1D_CONTEXT_ID + MIL.M_TYPE_MIL_ID, MilPeakLocator) MIL.MimControl(MilPeakLocator, MIL.M_PEAK_WIDTH_NOMINAL, PEAK_WIDTH_NOMINAL_2) MIL.MimControl(MilPeakLocator, MIL.M_PEAK_WIDTH_DELTA, PEAK_WIDTH_DELTA_2) MIL.MimControl(MilPeakLocator, MIL.M_MINIMUM_CONTRAST, MIN_CONTRAST_2) ' Calibrate laser profiling context. MIL.M3dmapAddScan(LaserId, CalibScanId, MilImage, MIL.M_NULL, MIL.M_NULL, MIL.M_DEFAULT, MIL.M_DEFAULT) MIL.M3dmapCalibrate(LaserId, CalibScanId, MilCalibration, MIL.M_DEFAULT) Console.WriteLine("The laser profiling system has been calibrated using the image") Console.WriteLine("of one laser line.") Console.WriteLine() Console.WriteLine("Press <Enter> to continue.") Console.WriteLine() Console.ReadKey() ' Free the result buffer used for calibration because it will not be used anymore. MIL.M3dmapFree(CalibScanId) CalibScanId = MIL.M_NULL ' Allocate the result buffer for the scanned depth corrected data. MIL.M3dmapAllocResult(MilSystem, MIL.M_POINT_CLOUD_CONTAINER, MIL.M_DEFAULT, ScanId) ' Set speed of scanned object (speed in mm/frame is constant). MIL.M3dmapControl(LaserId, MIL.M_DEFAULT, MIL.M_SCAN_SPEED, CONVEYOR_SPEED) ' Inquire characteristics of the input sequence. MIL.MbufDiskInquire(OBJECT2_SEQUENCE_FILE, MIL.M_NUMBER_OF_IMAGES, NumberOfImages) MIL.MbufDiskInquire(OBJECT2_SEQUENCE_FILE, MIL.M_FRAME_RATE, FrameRate) ' Open the object sequence file for reading. MIL.MbufImportSequence(OBJECT2_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, CType(MIL.M_NULL, IntPtr), MIL.M_NULL, MIL.M_NULL, MIL.M_OPEN) Console.WriteLine("The cookie is being scanned to generate 3d data.") Console.WriteLine() ' Read and process all images in the input sequence. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, StartTime) For n = 0 To NumberOfImages - 1 ' Read image from sequence. MIL.MbufImportSequence(OBJECT2_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_LOAD, MIL.M_NULL, MilImage, MIL.M_DEFAULT, 1, MIL.M_READ) ' Analyze the image to extract laser line and correct its depth. MIL.M3dmapAddScan(LaserId, ScanId, MilImage, MIL.M_NULL, MIL.M_NULL, MIL.M_POINT_CLOUD_LABEL(1), MIL.M_DEFAULT) ' Wait to have a proper frame rate, if necessary. MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, EndTime) WaitTime = (1.0 / FrameRate) - (EndTime - StartTime) If WaitTime > 0 Then MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_WAIT, WaitTime) End If MIL.MappTimer(MIL.M_DEFAULT, MIL.M_TIMER_READ + MIL.M_SYNCHRONOUS, StartTime) Next n ' Close the object sequence file. MIL.MbufImportSequence(OBJECT2_SEQUENCE_FILE, MIL.M_DEFAULT, MIL.M_NULL, MIL.M_NULL, CType(MIL.M_NULL, IntPtr), MIL.M_NULL, MIL.M_NULL, MIL.M_CLOSE) ' Allocate image for the fully corrected depth map. MIL.MbufAlloc2d(MilSystem, DEPTH_MAP_SIZE_X, DEPTH_MAP_SIZE_Y, 16 + MIL.M_UNSIGNED, MIL.M_IMAGE + MIL.M_PROC + MIL.M_DISP, DepthMapId) ' Set fully corrected depth map generation parameters. MIL.M3dmapControl(ScanId, MIL.M_DEFAULT, MIL.M_AUTO_SCALE_XY, MIL.M_CLIP) MIL.M3dmapControl(ScanId, MIL.M_DEFAULT, MIL.M_FILL_MODE, MIL.M_X_THEN_Y) MIL.M3dmapControl(ScanId, MIL.M_DEFAULT, MIL.M_FILL_SHARP_ELEVATION, MIL.M_MIN) MIL.M3dmapControl(ScanId, MIL.M_DEFAULT, MIL.M_FILL_SHARP_ELEVATION_DEPTH, GAP_DEPTH) ' Include all points during depth map generation. MIL.M3dmapSetBox(ScanId, MIL.M_EXTRACTION_BOX, MIL.M_BOUNDING_BOX, MIL.M_ALL, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT) ' Get fully corrected depth map from accumulated information in the result buffer. MIL.M3dmapExtract(ScanId, DepthMapId, MIL.M_NULL, MIL.M_CORRECTED_DEPTH_MAP, MIL.M_DEFAULT, MIL.M_DEFAULT) ' Compute the volume of the whole depth map. MIL.M3dmapStat(DepthMapId, MIL.M_NULL, MIL.M_NULL, MIL.M_NULL, MIL.M_VOLUME, MIL.M_DEFAULT, MIL.M_DEFAULT, Volume) ' Compute the volume caused by noise around Z = 0. Use an outlier distance of 1 mm. MIL.M3dmapStat(DepthMapId, MIL.M_NULL, MIL.M_NULL, MIL.M_NULL, MIL.M_VOLUME, MIN_HEIGHT_THRESHOLD, MIL.M_DEFAULT, VolumeError) ' Compute the volume of the cookie. Volume -= VolumeError Console.WriteLine("fully corrected 3d data of the cookie is displayed.") Console.WriteLine() ' Try to allocate D3D display. Dim DispHandle As IntPtr DispHandle = MdepthD3DAlloc(DepthMapId, MIL.M_NULL, D3D_DISPLAY_SIZE_X, D3D_DISPLAY_SIZE_Y, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, MIL.M_DEFAULT, IntPtr.Zero) If DispHandle <> IntPtr.Zero Then ' Hide Mil Display. MIL.MdispControl(MilDisplay, MIL.M_WINDOW_SHOW, MIL.M_DISABLE) MdispD3DShow(DispHandle) Console.WriteLine("D3D display controls:") Console.WriteLine(" .Left click" & Constants.vbTab & "move object") Console.WriteLine(" .Right click" & Constants.vbTab & "rotate object") Console.WriteLine(" .Scroll wheel" & Constants.vbTab & "zoom") Console.WriteLine(" .R" & Constants.vbTab + Constants.vbTab & "start/stop animation") Console.WriteLine(" .P" & Constants.vbTab + Constants.vbTab & "enable/disable point cloud") Console.WriteLine() Else MIL.MdispControl(MilDisplay, MIL.M_VIEW_MODE, MIL.M_AUTO_SCALE) MIL.MdispSelect(MilDisplay, DepthMapId) End If Console.WriteLine("Volume of the cookie is {0,4:0.0} cm^3.", -Volume / 1000.0) Console.WriteLine() Console.WriteLine("Press <Enter> to end.") Console.WriteLine() Console.ReadKey() If DispHandle <> IntPtr.Zero Then MdispD3DHide(DispHandle) MdispD3DFree(DispHandle) End If ' Free all allocations. MIL.M3dmapFree(ScanId) MIL.M3dmapFree(LaserId) MIL.McalFree(MilCalibration) MIL.MbufFree(DepthMapId) MIL.MbufFree(MilImage) End Sub End Class End Namespace