#include <Mil.h>
#include <math.h>
#include "DepthDataMgr.h"
#define M_Round(x) ((MIL_INT)((x) + ((x) >= 0 ? 0.5 : -0.5)))
static const MIL_INT DEFAULT_FILL_HOLES_CLOSE_ITER = 2;
template void CDepthDataMgr::CalculateWorldPoints<true>(MIL_ID MilDepthImage);
template void CDepthDataMgr::CalculateWorldPoints<false>(MIL_ID MilDepthImage);
CDepthDataMgr::CDepthDataMgr(MIL_ID MilSystem,
MIL_INT DepthImageSizeX,
MIL_INT DepthImageSizeY,
MIL_INT DepthMapSizeX,
MIL_INT DepthMapSizeY,
MIL_INT ColorImageSizeX,
MIL_INT ColorImageSizeY)
: m_MilSystem(MilSystem),
m_DepthImageSizeX(DepthImageSizeX),
m_DepthImageSizeY(DepthImageSizeY),
m_DepthValid(false),
m_NbWorld(0),
m_FillHolesCloseIter(DEFAULT_FILL_HOLES_CLOSE_ITER)
{
MIL_INT MaxNbWorldPoints = DepthImageSizeX * DepthImageSizeY;
m_pXWorld = new MIL_DOUBLE[MaxNbWorldPoints];
m_pYWorld = new MIL_DOUBLE[MaxNbWorldPoints];
m_pZWorld = new MIL_DOUBLE[MaxNbWorldPoints];
m_pDepthXPixel = new MIL_UINT16[MaxNbWorldPoints];
m_pDepthYPixel = new MIL_UINT16[MaxNbWorldPoints];
m_pColorXPixel = new MIL_DOUBLE[MaxNbWorldPoints];
m_pColorYPixel = new MIL_DOUBLE[MaxNbWorldPoints];
m_pXMultipliers = new MIL_DOUBLE[MaxNbWorldPoints];
m_pYMultipliers = new MIL_DOUBLE[MaxNbWorldPoints];
MbufAlloc2d(MilSystem, DepthMapSizeX, DepthMapSizeY, 16 + M_UNSIGNED, M_IMAGE + M_PROC, &m_MilDepthFilledHoles);
MbufAllocColor(MilSystem, 3, DepthMapSizeX, DepthMapSizeY, 8 + M_UNSIGNED, M_IMAGE + M_PROC, &m_MilColorFilledHoles);
MbufAlloc2d(MilSystem, DepthImageSizeX, DepthImageSizeY, 16+M_SIGNED, M_LUT, &m_MilColorToDepthLutX);
MbufAlloc2d(MilSystem, DepthImageSizeX, DepthImageSizeY, 16+M_SIGNED, M_LUT, &m_MilColorToDepthLutY);
MbufAlloc1d(MilSystem, MaxNbWorldPoints, 16+M_SIGNED, M_LUT, &m_MilColorToWorldLutXContainer);
MbufAlloc1d(MilSystem, MaxNbWorldPoints, 16+M_SIGNED, M_LUT, &m_MilColorToWorldLutYContainer);
MbufChild1d(m_MilColorToWorldLutXContainer, 0, 1, &m_MilColorToWorldLutX);
MbufChild1d(m_MilColorToWorldLutYContainer, 0, 1, &m_MilColorToWorldLutY);
MIL_DOUBLE MaxAbsValue = (MIL_DOUBLE)(ColorImageSizeX > ColorImageSizeY ? ColorImageSizeX: ColorImageSizeY);
m_LutNbFixedPoint = Calculate16BitNbFixedPoint(MaxAbsValue);
}
CDepthDataMgr::~CDepthDataMgr()
{
MbufFree(m_MilColorToWorldLutY);
MbufFree(m_MilColorToWorldLutX);
MbufFree(m_MilColorToWorldLutYContainer);
MbufFree(m_MilColorToWorldLutXContainer);
MbufFree(m_MilColorToDepthLutY);
MbufFree(m_MilColorToDepthLutX);
MbufFree(m_MilColorFilledHoles);
MbufFree(m_MilDepthFilledHoles);
delete [] m_pYMultipliers;
delete [] m_pXMultipliers;
delete [] m_pColorYPixel;
delete [] m_pColorXPixel;
delete [] m_pDepthYPixel;
delete [] m_pDepthXPixel;
delete [] m_pZWorld;
delete [] m_pYWorld;
delete [] m_pXWorld;
}
void CDepthDataMgr::CalculateMultipliers(MIL_ID MilCalibration)
{
MIL_INT TotalNbPixels = m_DepthImageSizeX * m_DepthImageSizeY;
MIL_DOUBLE* XPixel = new MIL_DOUBLE[TotalNbPixels];
MIL_DOUBLE* YPixel = new MIL_DOUBLE[TotalNbPixels];
MIL_DOUBLE* XUnitVec = new MIL_DOUBLE[TotalNbPixels];
MIL_DOUBLE* YUnitVec = new MIL_DOUBLE[TotalNbPixels];
MIL_DOUBLE* ZUnitVec = new MIL_DOUBLE[TotalNbPixels];
for(MIL_INT Y = 0, i = 0; Y < m_DepthImageSizeY; Y++)
{
for(MIL_INT X =0; X <m_DepthImageSizeX; X++, i++)
{
XPixel[i] = (MIL_DOUBLE)X;
YPixel[i] = (MIL_DOUBLE)Y;
}
}
McalTransformCoordinate3dList(MilCalibration,
M_PIXEL_COORDINATE_SYSTEM,
M_CAMERA_COORDINATE_SYSTEM,
TotalNbPixels,
XPixel,
YPixel,
M_NULL,
XUnitVec,
YUnitVec,
ZUnitVec,
M_UNIT_DIRECTION_VECTOR);
for(MIL_INT PixelIdx = 0; PixelIdx < TotalNbPixels; PixelIdx++)
{
m_pXMultipliers[PixelIdx] = XUnitVec[PixelIdx] / ZUnitVec[PixelIdx];
m_pYMultipliers[PixelIdx] = YUnitVec[PixelIdx] / ZUnitVec[PixelIdx];
}
delete [] ZUnitVec;
delete [] YUnitVec;
delete [] XUnitVec;
delete [] YPixel;
delete [] XPixel;
}
template <bool GenAssociatedDepthPixel>
void CDepthDataMgr::CalculateWorldPoints(MIL_ID MilDepthImage)
{
MIL_UINT16* pDepthData = (MIL_UINT16*)MbufInquire(MilDepthImage, M_HOST_ADDRESS, M_NULL);
MIL_INT DepthPitch = MbufInquire(MilDepthImage, M_PITCH, M_NULL);
m_NbWorld = 0;
MIL_INT MultIdx = 0;
MIL_INT DepthIdx = 0;
for(MIL_UINT16 Y = 0; Y < m_DepthImageSizeY; Y++)
{
for(MIL_UINT16 X = 0; X < m_DepthImageSizeX; X++)
{
if(pDepthData[DepthIdx] != 0)
{
m_pXWorld[m_NbWorld] = pDepthData[DepthIdx] * m_pXMultipliers[MultIdx];
m_pYWorld[m_NbWorld] = pDepthData[DepthIdx] * m_pYMultipliers[MultIdx];
m_pZWorld[m_NbWorld] = (MIL_DOUBLE)pDepthData[DepthIdx];
if(GenAssociatedDepthPixel)
{
m_pDepthXPixel[m_NbWorld] = X;
m_pDepthYPixel[m_NbWorld] = Y;
}
m_NbWorld++;
}
MultIdx++;
DepthIdx++;
}
DepthIdx += DepthPitch - m_DepthImageSizeX;
}
}
void CDepthDataMgr::MoveWorldPoints(MIL_ID MilCalibration, MIL_INT SrcCoordinateSystem, MIL_INT DstCoordinateSystem)
{
McalTransformCoordinate3dList(MilCalibration,
SrcCoordinateSystem,
DstCoordinateSystem,
m_NbWorld,
m_pXWorld,
m_pYWorld,
m_pZWorld,
m_pXWorld,
m_pYWorld,
m_pZWorld,
M_DEFAULT);
}
void CDepthDataMgr::WarpColorImage(MIL_ID MilColorImage, MIL_ID MilWarpedColorImage, bool UseWorldLut) const
{
if(UseWorldLut)
MimWarp(MilColorImage, MilWarpedColorImage, m_MilColorToWorldLutX, m_MilColorToWorldLutY,
M_WARP_LUT + M_FIXED_POINT + m_LutNbFixedPoint, M_BILINEAR+M_OVERSCAN_CLEAR);
else
MimWarp(MilColorImage, MilWarpedColorImage, m_MilColorToDepthLutX, m_MilColorToDepthLutY,
M_WARP_LUT + M_FIXED_POINT + m_LutNbFixedPoint, M_BILINEAR+M_OVERSCAN_CLEAR);
}
void CDepthDataMgr::GenColorLuts(MIL_ID MilColorCameraCalibration, bool GenWorldLut)
{
if(m_NbWorld)
{
McalTransformCoordinate3dList(MilColorCameraCalibration,
M_TOOL_COORDINATE_SYSTEM,
M_PIXEL_COORDINATE_SYSTEM,
m_NbWorld,
m_pXWorld,
m_pYWorld,
m_pZWorld,
m_pColorXPixel,
m_pColorYPixel,
M_NULL,
M_DEFAULT);
if(GenWorldLut)
{
MbufChildMove(m_MilColorToWorldLutX, 0, 0, m_NbWorld, 1, M_DEFAULT);
MbufChildMove(m_MilColorToWorldLutY, 0, 0, m_NbWorld, 1, M_DEFAULT);
FillColorToWorldLuts();
}
else
FillColorToDepthLuts();
}
}
void CDepthDataMgr::FillColorToDepthLuts()
{
MIL_INT16* pLutXData = (MIL_INT16*)MbufInquire(m_MilColorToDepthLutX, M_HOST_ADDRESS, M_NULL);
MIL_INT16* pLutYData = (MIL_INT16*)MbufInquire(m_MilColorToDepthLutY, M_HOST_ADDRESS, M_NULL);
MIL_INT LutPitch = MbufInquire(m_MilColorToDepthLutX, M_PITCH, M_NULL);
MIL_DOUBLE LutMultFactor = (MIL_DOUBLE)(1 << m_LutNbFixedPoint);
MbufClear(m_MilColorToDepthLutX, -1*LutMultFactor);
MbufClear(m_MilColorToDepthLutY, -1*LutMultFactor);
for(MIL_INT WorldIdx = 0; WorldIdx < m_NbWorld; WorldIdx++)
{
MIL_INT Offset = m_pDepthXPixel[WorldIdx] + m_pDepthYPixel[WorldIdx]*LutPitch;
pLutXData[Offset] = (MIL_INT16)M_Round(m_pColorXPixel[WorldIdx] * LutMultFactor);
pLutYData[Offset] = (MIL_INT16)M_Round(m_pColorYPixel[WorldIdx] * LutMultFactor);
}
}
void CDepthDataMgr::FillColorToWorldLuts()
{
MIL_INT16* pLutXData = (MIL_INT16*)MbufInquire(m_MilColorToWorldLutX, M_HOST_ADDRESS, M_NULL);
MIL_INT16* pLutYData = (MIL_INT16*)MbufInquire(m_MilColorToWorldLutY, M_HOST_ADDRESS, M_NULL);
MIL_DOUBLE LutMultFactor = (MIL_DOUBLE)(1 << m_LutNbFixedPoint);
for(MIL_INT WorldIdx = 0; WorldIdx < m_NbWorld; WorldIdx++)
{
pLutXData[WorldIdx] = (MIL_INT16)M_Round(m_pColorXPixel[WorldIdx] * LutMultFactor);
pLutYData[WorldIdx] = (MIL_INT16)M_Round(m_pColorYPixel[WorldIdx] * LutMultFactor);
}
}
void CDepthDataMgr::CreateDepthMap(MIL_ID MilWorldPackedColorImage,
MIL_ID MilDepthMapImage,
MIL_ID MilColorDepthMapImage,
const SDepthMapGenParam& rGenParam) const
{
if(MilColorDepthMapImage == M_NULL)
ExtractDepthMapNoFill<false>(MilWorldPackedColorImage, MilDepthMapImage, MilColorDepthMapImage, rGenParam);
else
ExtractDepthMapNoFill<true>(MilWorldPackedColorImage, MilDepthMapImage, MilColorDepthMapImage, rGenParam);
FillDepthMapHoles(MilDepthMapImage, MilColorDepthMapImage, MilColorDepthMapImage != M_NULL);
}
template <bool GenColorDepthMap>
void CDepthDataMgr::ExtractDepthMapNoFill(MIL_ID MilWorldPackedColorImage,
MIL_ID MilDepthMapImage,
MIL_ID MilColorDepthMapImage,
const SDepthMapGenParam& rGenParam) const
{
MIL_UINT16* pDepthMap = (MIL_UINT16*)MbufInquire(MilDepthMapImage, M_HOST_ADDRESS, M_NULL);
MIL_INT DepthMapPitch = MbufInquire(MilDepthMapImage, M_PITCH, M_NULL);
MIL_INT DepthMapSizeX = MbufInquire(MilDepthMapImage, M_SIZE_X, M_NULL);
MIL_INT DepthMapSizeY = MbufInquire(MilDepthMapImage, M_SIZE_Y, M_NULL);
MbufClear(MilDepthMapImage, MIL_UINT16_MAX);
MIL_UINT32* pColorMap;
MIL_INT ColorMapPitch;
MIL_UINT32* pWorldPackedColor;
if(GenColorDepthMap)
{
pColorMap = (MIL_UINT32*)MbufInquire(MilColorDepthMapImage, M_HOST_ADDRESS, M_NULL);
ColorMapPitch = MbufInquire(MilColorDepthMapImage, M_PITCH, M_NULL);
MbufClear(MilColorDepthMapImage, 0);
pWorldPackedColor = (MIL_UINT32*)MbufInquire(MilWorldPackedColorImage, M_HOST_ADDRESS, M_NULL);
}
for(MIL_INT WorldIdx = 0; WorldIdx < m_NbWorld; WorldIdx++)
{
MIL_INT DrawX = M_Round((m_pXWorld[WorldIdx] - rGenParam.WorldPosX) / rGenParam.PixelSizeX);
if(DrawX >=0 && DrawX < DepthMapSizeX)
{
MIL_INT DrawY = M_Round((m_pYWorld[WorldIdx] - rGenParam.WorldPosY) / rGenParam.PixelSizeY);
if(DrawY >=0 && DrawY < DepthMapSizeY)
{
MIL_INT DrawZ = M_Round((m_pZWorld[WorldIdx] - rGenParam.WorldPosZ) / rGenParam.GrayLevelSizeZ);
if(DrawZ < 0)
DrawZ = 0;
else if(DrawZ > MIL_UINT16_MAX-1)
DrawZ = MIL_UINT16_MAX-1;
if(pDepthMap[DrawX + DrawY*DepthMapPitch] == MIL_UINT16_MAX || DrawZ < pDepthMap[DrawX + DrawY*DepthMapPitch])
{
pDepthMap[DrawX + DrawY*DepthMapPitch] = (MIL_UINT16)DrawZ;
if(GenColorDepthMap)
pColorMap[DrawX + DrawY*ColorMapPitch] = pWorldPackedColor[WorldIdx];
}
}
}
}
McalUniform(MilDepthMapImage, rGenParam.WorldPosX, rGenParam.WorldPosY,
rGenParam.PixelSizeX, rGenParam.PixelSizeY, 0.0, M_DEFAULT);
McalControl(MilDepthMapImage, M_GRAY_LEVEL_SIZE_Z, rGenParam.GrayLevelSizeZ);
McalControl(MilDepthMapImage, M_WORLD_POS_Z, rGenParam.WorldPosZ);
}
void CDepthDataMgr::FillDepthMapHoles(MIL_ID MilDepthMapImage, MIL_ID MilColorDepthMapImage, bool GenColorDepthMap) const
{
MimOpen(MilDepthMapImage, m_MilDepthFilledHoles, m_FillHolesCloseIter, M_GRAYSCALE);
if(GenColorDepthMap)
{
MimClose(MilColorDepthMapImage, m_MilColorFilledHoles, m_FillHolesCloseIter, M_GRAYSCALE);
MbufCopyCond(m_MilColorFilledHoles, MilColorDepthMapImage, MilDepthMapImage, M_EQUAL, MIL_UINT16_MAX);
}
MbufCopyCond(m_MilDepthFilledHoles, MilDepthMapImage, MilDepthMapImage, M_EQUAL, MIL_UINT16_MAX);
}
MIL_INT Calculate16BitNbFixedPoint(MIL_DOUBLE MaxAbsValue)
{
MIL_INT MaxIntValue = (MIL_INT)ceil(MaxAbsValue);
MIL_INT NbFixedPoint = 14;
if (MaxIntValue > 0x7F) { MaxIntValue >>= 8; NbFixedPoint -= 8;}
if (MaxIntValue > 0x7) { MaxIntValue >>= 4; NbFixedPoint -= 4;}
if (MaxIntValue > 0x3) { MaxIntValue >>= 2; NbFixedPoint -= 2;}
if (MaxIntValue > 0x1) { MaxIntValue >>= 1; NbFixedPoint -= 1;}
return NbFixedPoint;
}