1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
// XnMapSequenceListConverter.h
#ifndef _XNMAPSEQUENCELISTCONVERTER_H_
#define _XNMAPSEQUENCELISTCONVERTER_H_
namespace xn
{
template <typename PixelType>
class XnMapSequenceListConverter
{
private:
typedef XnUInt16 ValueType;
struct ValueHeader
{
ValueType nValue;
XnUInt16 nSequences;
};
struct Sequence
{
XnUInt16 nOffset;
XnUInt16 nSequenceCount;
};
XnStatus FillMapTopDown(PixelType* pMap, XnUInt32 nHeight, XnUInt32 nWidth, XnUInt32& nX, XnUInt32& nY, XnUInt32 nPixels, PixelType val)
{
XnUInt32 nCurrIndex = nWidth * nY + nX;
for (XnUInt32 pxl = 0; pxl < nPixels; pxl++ )
{
// Check indexes
if (nX >= nWidth || nY >= nHeight)
{
return XN_STATUS_BAD_PARAM;
}
pMap[nCurrIndex] = val;
nY++;
if (nY == nHeight)
{
// Move to next column start
nY = 0;
nX++;
nCurrIndex = nX;
}
else
{
// Move next row, same column
nCurrIndex += nWidth;
}
}
return XN_STATUS_OK;
}
public:
// We processing the map up down first, because people are more likely to stand next to each other than on top of each other.
XnStatus MapToSequenceList(const PixelType* pMap, XnUInt32 nHeight, XnUInt32 nWidth, XnUChar* pSeqBuffer, XnUInt32& nSeqSize)
{
const PixelType NA_PIXEL = (PixelType)-1;
const PixelType MAX_PIXEL_SIZE = (1 << sizeof(ValueType) * 8) - 1;
// Current sequence related data
XnUInt16 nOffsetCount = 0;
PixelType sequncePixel = NA_PIXEL;
// Value related data
ValueHeader* pCurrValueHeader = NULL;
Sequence* pCurrSeq = NULL;
// Output related data
XnUChar* pCurrOutput = pSeqBuffer;
XnUInt nCurrOutputSize = 0;
const PixelType* pColumn = pMap;
for (XnUInt32 x = 0; x < nWidth; x++)
{
const PixelType* pCurr = pColumn;
for (XnUInt32 y = 0; y < nHeight; y++)
{
// Make sure no pixel uses NA_PIXEL value and that the pixel will fit ValueHeader.nValue
if (*pCurr == NA_PIXEL || *pCurr > MAX_PIXEL_SIZE)
{
return XN_STATUS_BAD_TYPE;
}
// See if the pixel is part of an offset
if (*pCurr == 0)
{
nOffsetCount++;
sequncePixel = NA_PIXEL;
pCurrSeq = NULL;
}
// See if the pixel is in a sequence
else if (*pCurr == sequncePixel)
{
XN_ASSERT(pCurrSeq);
pCurrSeq->nSequenceCount++;
}
// New sequnce start
else
{
// Check if we need to add ValueHeader
if (!pCurrValueHeader || pCurrValueHeader->nValue != *pCurr)
{
// New value in front of us, add value header
nCurrOutputSize += sizeof(ValueHeader);
if (nCurrOutputSize > nSeqSize)
return XN_STATUS_INVALID_BUFFER_SIZE;
pCurrValueHeader = (ValueHeader*)pCurrOutput;
pCurrOutput += sizeof(ValueHeader);
pCurrValueHeader->nValue = (ValueType)*pCurr;
pCurrValueHeader->nSequences = 1;
}
else
{
pCurrValueHeader->nSequences++;
}
// Store new sequence pixel
sequncePixel = *pCurr;
// Add sequence data
nCurrOutputSize += sizeof(Sequence);
if (nCurrOutputSize > nSeqSize)
return XN_STATUS_INVALID_BUFFER_SIZE;
pCurrSeq = (Sequence*)pCurrOutput;
pCurrSeq->nOffset = nOffsetCount;
pCurrSeq->nSequenceCount = 1;
nOffsetCount = 0;
pCurrOutput += sizeof(Sequence);
}
// Move to next row
pCurr += nWidth;
}
pColumn++;
}
nSeqSize = nCurrOutputSize;
return XN_STATUS_OK;
}
XnStatus SequenceListToMap(XnUChar* pSeqBuffer, XnUInt32 nSeqSize, PixelType* pMap, XnUInt32 nHeight, XnUInt32 nWidth)
{
XnUInt32 nCurrProcessed = 0;
XnUInt32 nX = 0;
XnUInt32 nY = 0;
XnUChar* pCurr = pSeqBuffer;
// Default all pixels
xnOSMemSet(pMap, 0, sizeof(PixelType) * nHeight * nWidth);
while (nCurrProcessed != nSeqSize)
{
nCurrProcessed += sizeof(ValueHeader);
if (nCurrProcessed > nSeqSize)
return XN_STATUS_INVALID_BUFFER_SIZE;
// Get the value header
ValueHeader* pCurrValue = (ValueHeader*)pCurr;
pCurr += sizeof(ValueHeader);
// Loop on value sequences
for (XnUInt16 nSeq = 0; nSeq < pCurrValue->nSequences; nSeq++ )
{
nCurrProcessed += sizeof(Sequence);
if (nCurrProcessed > nSeqSize)
return XN_STATUS_INVALID_BUFFER_SIZE;
Sequence* pSeq = (Sequence*)pCurr;
pCurr += sizeof(Sequence);
// Add offset to x,y
XnUInt nNaiveY = nY + pSeq->nOffset;
nX += nNaiveY / nHeight;
if (nX >= nWidth)
return XN_STATUS_BAD_PARAM;
nY = nNaiveY % nHeight;
// Fill value
XnStatus rc = FillMapTopDown(pMap, nHeight, nWidth, nX, nY, pSeq->nSequenceCount, (PixelType)pCurrValue->nValue);
XN_IS_STATUS_OK(rc);
}
}
return XN_STATUS_OK;
}
};
}
#endif
|