Hi,
I want to implement the same functionality as the "block visible" button in Motive, using the camera SDK. I can see the methods available (SetEnableBlockingMask and the ones underneath), but I cannot find any documentation or examples.
Is the functionality I want available using the SDK? Or do I have to implement it myself? If so, I guess I have to detect the visible markers in precision mode, and then iterate over the markers' masks to block them?
Greetings,
JeDi
Block visible markers using SDK
-
- NaturalPoint Employee
- Posts: 720
- Joined: Mon Jan 19, 2015 11:52 am
Re: Block visible markers using SDK
Hello JeDi,
Our Camera SDK provides all of the low level functionality to create masks and apply them to the cameras.
We don't have a sample application that demonstrates how to create images, but we can describe some details here:
Based on the location & size of centroids on the camera image, you can call
camera->AddBlockingRectangle for each rectangular region you would like to mask. Then call
camera->UpdateBlockingMask() to apply the updated mask to the camera.
In order to draw something besides rectangles, the approach is to create a 'mask image' which is 1 byte per mask pixel. The mask image is a lower image than the camera's resolution. You can determine how much lower by using
camera->BlockingMaskWidth and camera->BlockingMaskHeight.
If you want to leverage the Camera SDK's Bitmap class to prepare the image and also give easy access to drawing things like lines, rectangles, and circles then you can instantiate one with something like:
blockBitmap = new CameraLibrary::Bitmap(camera->BlockingMaskWidth(),camera->BlockingMaskHeight(),0,CameraLibrary::Bitmap::EightBit, ,0));
Then you can draw on this bitmap using the CameraLibrary::Bitmap pixel, line, rectangle, and circle functions. Then apply the mask with:
camera->SetBlockingMask(blockBitmap->GetBits(),blockBitmap->PixelWidth()*blockBitmap->PixelHeight());
camera->UpdateBlockingMask();
You would likely want to have the camera in SegmentMode or PrecisionMode to observe the shape of the centroids. Camera centroids are reported by the Camera SDK as cObjects. When the camera is in SegmentMode or PrecisionMode, the objects also expose a linked list of line segments that describes the shape of the centroid. Calling object->Segments() will give you the head of the linked list. You can then walk through that list to get a list of line segments that accurately describes the shape of the centroid. Presumably that could be used to draw a similar shape on the mask.
I hope this information helps with your attempts to create camera masks.
Best regards,
Steven
--
Steven Andrews
OptiTrack | Customer Support Engineer
Our Camera SDK provides all of the low level functionality to create masks and apply them to the cameras.
We don't have a sample application that demonstrates how to create images, but we can describe some details here:
Based on the location & size of centroids on the camera image, you can call
camera->AddBlockingRectangle for each rectangular region you would like to mask. Then call
camera->UpdateBlockingMask() to apply the updated mask to the camera.
In order to draw something besides rectangles, the approach is to create a 'mask image' which is 1 byte per mask pixel. The mask image is a lower image than the camera's resolution. You can determine how much lower by using
camera->BlockingMaskWidth and camera->BlockingMaskHeight.
If you want to leverage the Camera SDK's Bitmap class to prepare the image and also give easy access to drawing things like lines, rectangles, and circles then you can instantiate one with something like:
blockBitmap = new CameraLibrary::Bitmap(camera->BlockingMaskWidth(),camera->BlockingMaskHeight(),0,CameraLibrary::Bitmap::EightBit, ,0));
Then you can draw on this bitmap using the CameraLibrary::Bitmap pixel, line, rectangle, and circle functions. Then apply the mask with:
camera->SetBlockingMask(blockBitmap->GetBits(),blockBitmap->PixelWidth()*blockBitmap->PixelHeight());
camera->UpdateBlockingMask();
You would likely want to have the camera in SegmentMode or PrecisionMode to observe the shape of the centroids. Camera centroids are reported by the Camera SDK as cObjects. When the camera is in SegmentMode or PrecisionMode, the objects also expose a linked list of line segments that describes the shape of the centroid. Calling object->Segments() will give you the head of the linked list. You can then walk through that list to get a list of line segments that accurately describes the shape of the centroid. Presumably that could be used to draw a similar shape on the mask.
I hope this information helps with your attempts to create camera masks.
Best regards,
Steven
--
Steven Andrews
OptiTrack | Customer Support Engineer
Re: Block visible markers using SDK
Thanks a lot for the detailed info, that will get me going.
When I finish the code, I will share it here, because I think a simple "block visible" method would be helpful for a lot of people.
Greetings, JeDi
When I finish the code, I will share it here, because I think a simple "block visible" method would be helpful for a lot of people.
Greetings, JeDi
-
- NaturalPoint Employee
- Posts: 720
- Joined: Mon Jan 19, 2015 11:52 am
Re: Block visible markers using SDK
Thanks JeDi, that would be incredible.
If we could have your permission, I would also like to suggest we include it with the samples we provide.
Steven
If we could have your permission, I would also like to suggest we include it with the samples we provide.
Steven
Re: Block visible markers using SDK
Of course, that will be no problem.
Re: Block visible markers using SDK
OK, this method seems to work (I only did a quick test with one camera though):
I use a synchronized frame group, and this is how I get the frames (this is temporary code, but you'll figure it out):
drainCameraFrames() is just a while loop to get rid of all frames still hanging around, if any. I had to write that because a frame group lacks a GetLastFrames method.
When you don't use a synchronized frame group, you have to iterate over the cameras and query the frames directly.
I hope this is useful to someone. Please let me know if anything looks weird.
Greetings,
JeDi
Code: Select all
void CameraManager::blockVisibleMarkers(CameraLibrary::Camera *pCamera, CameraLibrary::Frame *pFrame)
{
assert(pCamera && pFrame);
// Make sure the hardware mask is enabled
pCamera->SetEnableBlockingMask(true);
// Determine hardware mask size (can be different than image resolution)
int maskWidth = pCamera->BlockingMaskWidth();
int maskHeight = pCamera->BlockingMaskHeight();
float scaleWidth = maskWidth / (float) pCamera->Width();
float scaleHeight = maskHeight / (float) pCamera->Height();
int nObjects = pFrame->ObjectCount();
#if DEBUG_BLOCK_VISIBLE_MARKERS
cerr << "[CameraManager::blockVisibleMarkers] Camera #" << pCamera->CameraID() << " blocking mask size: ";
cerr << maskWidth << " x " << maskHeight << " - mask scale: " << scaleWidth << " x " << scaleHeight << endl;
cerr << " " << nObjects << " object(s) found" << endl;
#endif
for(int i = 0; i < nObjects; ++i)
{
CameraLibrary::cObject *pObject = pFrame->Object(i);
assert(pObject);
#if DEBUG_BLOCK_VISIBLE_MARKERS
cerr << " object #" << i << ":" << endl;
#endif
// Traverse the segments (scanlines) of the object
CameraLibrary::Segment *pSegment = pObject->Segments();
while(pSegment)
{
int startX = pSegment->StartX();
int startY = pSegment->StartY();
int length = pSegment->Length();
#if DEBUG_BLOCK_VISIBLE_MARKERS
cerr << " segment: (" << startX << "; " << startY << "; " << length << ")" << endl;
#endif
// Add the segment to the (scaled) blocking mask
for(int x = startX; x <= (startX + length); ++x)
pCamera->SetBitMaskPixel(x * scaleWidth, startY * scaleHeight, true);
// Next segment
pSegment = pSegment->Next();
}
}
// Update the blocking mask
pCamera->UpdateBlockingMask();
}
Code: Select all
void CameraManager::blockVisibleMarkers()
{
// Drain the current frames
drainCameraFrames();
// Wait for synced frame group
//! @todo Timeout
CameraLibrary::FrameGroup *pFrameGroup = nullptr;
while(!pFrameGroup)
pFrameGroup = _pSyncModule->GetFrameGroup();
if(pFrameGroup)
{
int numCameras = pFrameGroup->Count();
for(int i = 0; i < numCameras; ++i)
{
CameraLibrary::Frame *pFrame = pFrameGroup->GetFrame(i);
blockVisibleMarkers(pFrame->GetCamera(), pFrame);
pFrame->Release();
}
}
}
When you don't use a synchronized frame group, you have to iterate over the cameras and query the frames directly.
I hope this is useful to someone. Please let me know if anything looks weird.
Greetings,
JeDi
Re: Block visible markers using SDK
Although the code above works, it only blocks lights that are actually part of a detected marker. When smears of light are visible for example, they won't always be blocked.
I guess this is OK, because the other light is not detected as a marker anyway. But is this also how the block visible button in Motive:Tracker works? Or is the grayscale image used there, in combination with a treshold for the light intensity?
Did anyone else try the code yet, or had a look at it? Thanks!
Greetings,
JeDi
I guess this is OK, because the other light is not detected as a marker anyway. But is this also how the block visible button in Motive:Tracker works? Or is the grayscale image used there, in combination with a treshold for the light intensity?
Did anyone else try the code yet, or had a look at it? Thanks!
Greetings,
JeDi
-
- NaturalPoint Employee
- Posts: 720
- Joined: Mon Jan 19, 2015 11:52 am
Re: Block visible markers using SDK
Hi JeDi,
Motive uses its own high-level methods for masking, but it is essentially equivalent to masking in segment or precision mode. This allows masks to be created over light that is not circular enough to circle fit as objects.
Steven
Motive uses its own high-level methods for masking, but it is essentially equivalent to masking in segment or precision mode. This allows masks to be created over light that is not circular enough to circle fit as objects.
Steven