539 lines
17 KiB
C++
539 lines
17 KiB
C++
#include "ComponentLabeling.h"
|
|
|
|
CompLabeler::CompLabeler(cv::Mat& binImage, BlobContour** lab, cv::Point start, cv::Point end)
|
|
: m_binaryImage(binImage)
|
|
, m_startPoint(start)
|
|
, m_endPoint(end)
|
|
{
|
|
m_parent = NULL;
|
|
m_labels = lab;
|
|
m_r = 0;
|
|
m_c = 0;
|
|
m_dir = 0;
|
|
}
|
|
|
|
CompLabeler::~CompLabeler()
|
|
{
|
|
|
|
}
|
|
|
|
void CompLabeler::reset()
|
|
{
|
|
m_blobs.clear();
|
|
}
|
|
|
|
void CompLabeler::label()
|
|
{
|
|
m_ptrDataBinary = m_binaryImage.data;
|
|
m_ptrDataLabels = m_labels;
|
|
m_currentBlob = NULL;
|
|
|
|
m_h = m_binaryImage.size().height;
|
|
m_w = m_binaryImage.size().width;
|
|
BlobContour* label = NULL;
|
|
for (m_r = m_startPoint.y; m_r < m_endPoint.y; ++m_r) {
|
|
//First col
|
|
m_pos = m_r * m_w;
|
|
m_c = m_startPoint.x;
|
|
if (m_ptrDataBinary[m_pos]) {
|
|
label = m_ptrDataLabels[m_pos];
|
|
if (label) {
|
|
m_currentBlob = label->m_parent;
|
|
}
|
|
//Else if so to not check for label==NULL
|
|
else if (m_ptrDataBinary[m_pos] /*&& ptrDataLabels[pos]==NULL*/) {
|
|
m_currentBlob = new Blob(m_currentLabel, cv::Point(m_c, m_r), cv::Size(m_w, m_h));
|
|
m_blobs.push_back(m_currentBlob);
|
|
tracerExt();
|
|
}
|
|
if (!m_ptrDataBinary[m_pos + 1] && !m_ptrDataLabels[m_pos + 1]) {
|
|
tracerInt();
|
|
}
|
|
}
|
|
//Other cols
|
|
for (m_c = m_startPoint.x+1; m_c < m_endPoint.x-1; ++m_c) {
|
|
m_pos = m_r * m_w + m_c;
|
|
if (m_ptrDataBinary[m_pos]) {
|
|
label = m_ptrDataLabels[m_pos];
|
|
if (label != 0) {
|
|
m_currentBlob = label->m_parent;
|
|
}
|
|
else if (!m_ptrDataBinary[m_pos - 1]) {
|
|
m_currentBlob = new Blob(m_currentLabel, cv::Point(m_c, m_r), cv::Size(m_w, m_h));
|
|
m_blobs.push_back(m_currentBlob);
|
|
tracerExt();
|
|
}
|
|
if (!m_ptrDataBinary[m_pos+1] && m_ptrDataLabels[m_pos+1] == 0) {
|
|
tracerInt();
|
|
}
|
|
}
|
|
}
|
|
m_pos = m_r * m_w + m_c;
|
|
//Last column
|
|
if (m_ptrDataBinary[m_pos]) {
|
|
label = m_ptrDataLabels[m_pos];
|
|
if (label != 0) {
|
|
m_currentBlob = label->m_parent;
|
|
}
|
|
else if (!m_ptrDataBinary[m_pos - 1]) {
|
|
m_currentBlob = new Blob(m_currentLabel, cv::Point(m_c, m_r), cv::Size(m_w, m_h));
|
|
m_blobs.push_back(m_currentBlob);
|
|
tracerExt();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void* CompLabeler::threadLabeling(void* o)
|
|
{
|
|
CompLabeler* obj = (CompLabeler*)o;
|
|
obj->label();
|
|
return 0;
|
|
}
|
|
|
|
void CompLabeler::tracerExt()
|
|
{
|
|
//Dir:
|
|
//321
|
|
//4-0
|
|
//567
|
|
//cout << "tracerExt\t" << c<<","<<r<<endl;
|
|
m_currentContour = &m_currentBlob->m_externalContour;
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
std::cout << "tracerExt\t" << m_c << ", "<< m_r << std::endl;
|
|
bool debugDraw = true;
|
|
#endif
|
|
int sR = m_r, sC = m_c;
|
|
int startPos = sR * m_w + sC;
|
|
m_dir = 6;
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 150; //Debug
|
|
#endif
|
|
getNextPointCCW();
|
|
if (m_singlePixBlob) {
|
|
m_r = sR;
|
|
m_c = sC;
|
|
m_pos = m_r * m_w + m_c;
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
return;
|
|
}
|
|
ChainCodeList* cont = &m_currentBlob->m_externalContour.m_contour[0];
|
|
while (m_pos != startPos) {
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 150;
|
|
#endif
|
|
cont->push_back(m_dir);
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
getNextPointCCW();
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
if (debugDraw) {
|
|
cv::namedWindow("im", CV_WINDOW_NORMAL + CV_GUI_EXPANDED + CV_WINDOW_KEEPRATIO);
|
|
cv::imshow("im", m_binaryImage);
|
|
std::stringstream ss;
|
|
ss << m_c << ", " << m_r;
|
|
cv::displayOverlay("im", ss.str());
|
|
int k = cv::waitKey();
|
|
if (k == ' ') {
|
|
debugDraw = false;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
cont->push_back(m_dir);
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
//For blobs in which the starting point must be crossed many times
|
|
for (int i = 0; i < 3; ++i) {
|
|
getNextPointCCW();
|
|
if (m_ptrDataLabels[m_pos] == 0) {
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 150;
|
|
#endif
|
|
while (m_pos != startPos) {
|
|
//cout << r << "," << c << endl;
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
cont->push_back(m_dir);
|
|
getNextPointCCW();
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos]= 150;
|
|
if (debugDraw) {
|
|
cv::namedWindow("im", CV_WINDOW_NORMAL + CV_GUI_EXPANDED + CV_WINDOW_KEEPRATIO);
|
|
cv::imshow("im", m_binaryImage);
|
|
int k = cv::waitKey();
|
|
if (k == ' ') {
|
|
debugDraw = false;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
cont->push_back(m_dir);
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
}
|
|
else {
|
|
m_r = sR;
|
|
m_c = sC;
|
|
m_pos = m_r * m_w + m_c;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CompLabeler::tracerInt(int startDir /*= 5*/)
|
|
{
|
|
//Dir:
|
|
//321
|
|
//4-0
|
|
//567
|
|
//cout << "tracerInt\t" << c<<","<<r<<endl;
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
std::cout << "tracerInt\t" << m_c << ", " << m_r << std::endl;
|
|
bool debugDraw=true;
|
|
#endif
|
|
int sR = m_r, sC = m_c;
|
|
int startPos = sR * m_w + sC;
|
|
m_currentContour = new BlobContour(cv::Point(m_c, m_r), cv::Size(m_w, m_h));
|
|
m_currentContour->m_parent = m_currentBlob;
|
|
ChainCodeList* cont = &m_currentContour->m_contour[0];
|
|
m_dir = startDir;
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 50;
|
|
#endif
|
|
getNextPointCW();
|
|
//uchar firstDir = m_dir;
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 100;
|
|
#endif
|
|
cont->push_back(m_dir);
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
while (m_pos != startPos) {
|
|
// cout << r << "," << c << endl;
|
|
getNextPointCW();
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
cont->push_back(m_dir);
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 100;
|
|
if (debugDraw) {
|
|
cv::namedWindow("im", CV_WINDOW_NORMAL + CV_GUI_EXPANDED + CV_WINDOW_KEEPRATIO);
|
|
cv::imshow("im", m_binaryImage);
|
|
std::stringstream ss;
|
|
ss << m_c << ", " << m_r;
|
|
cv::displayOverlay("im", ss.str());
|
|
int k = cv::waitKey();
|
|
if (k == ' ') {
|
|
debugDraw = false;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//For internal contours in which the starting point must be crossed many times, like:
|
|
// ooooooooooooooo
|
|
// ooooos o
|
|
// ooooo o o
|
|
// ooooo o o
|
|
// ooooo o
|
|
// ooooooooooooooo
|
|
for (int i = 0; i < 3; ++i) {
|
|
getNextPointCW();
|
|
//In tracerExt i check for label==0, beacuse there can not be situations in which a pixel belongs to 2 contours.
|
|
//This can happen with internal contorus, so I have to modify the condition.
|
|
if (m_ptrDataLabels[m_pos] != m_currentContour) {
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 100;
|
|
#endif
|
|
while (m_pos != startPos) {
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
cont->push_back(m_dir);
|
|
getNextPointCW();
|
|
#ifdef DEBUG_COMPONENT_LABELLING
|
|
m_ptrDataBinary[m_pos] = 100;
|
|
if (debugDraw) {
|
|
cv::namedWindow("im",CV_WINDOW_NORMAL + CV_GUI_EXPANDED + CV_WINDOW_KEEPRATIO);
|
|
cv::imshow("im", m_binaryImage);
|
|
int k = cv::waitKey();
|
|
if (k == ' ') {
|
|
debugDraw = false;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
cont->push_back(m_dir);
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
}
|
|
else {
|
|
m_r = sR;
|
|
m_c = sC;
|
|
m_pos = m_r * m_w + m_c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//If labeler has m_parent it means that I'm using more than 1 thread.
|
|
//Then I must check for collisions when adding internal contours to the same blob.
|
|
if (m_parent) {
|
|
std::lock_guard<std::mutex> lock(m_parent->m_mutexBlob);
|
|
//m_parent->acquireMutex();
|
|
m_currentBlob->m_internalContours.push_back(m_currentContour);
|
|
//m_parent->releaseMutex();
|
|
}
|
|
else {
|
|
m_currentBlob->m_internalContours.push_back(m_currentContour);
|
|
}
|
|
}
|
|
|
|
void CompLabeler::getNextPointCCW()
|
|
{
|
|
//Dir:
|
|
//321
|
|
//4-0
|
|
//567
|
|
|
|
m_dir = (m_dir + 6) % 8;
|
|
int i = 0;
|
|
for (; i < 8; i++, m_dir = (m_dir + 1) % 8) {
|
|
m_tempR = m_r + m_freemanR[m_dir];
|
|
m_tempC = m_c + m_freemanC[m_dir];
|
|
if (!(m_tempR < 0 || m_tempR >= m_h || m_tempC < 0 || m_tempC >= m_w)) {
|
|
m_pos = m_tempR * m_w + m_tempC;
|
|
if (m_ptrDataBinary[m_pos]) {
|
|
m_r = m_tempR;
|
|
m_c = m_tempC;
|
|
break;
|
|
}
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
}
|
|
}
|
|
m_singlePixBlob = i == 8;
|
|
m_pos = m_r * m_w + m_c;
|
|
|
|
/*
|
|
// I tried to pre-create all the various direction vectors in order to avoid checking too many times for the boundary of the image.
|
|
// However, there was no gain in performance.
|
|
//It's useless (in terms of performance) to create the direction vectors according to all cases.
|
|
8 directions
|
|
|
|
cases:
|
|
0-r=0
|
|
1-r=0,c=0
|
|
2-r=0,c=w
|
|
3-r=h
|
|
4-r=h,c=0
|
|
5-r=h,c=w
|
|
6-c=0
|
|
7-c=w
|
|
8-otherwise
|
|
total:9
|
|
*/
|
|
|
|
//static uchar directions[8][9][8] = {{{0,4,5,6,7,0,0,0},{0,6,7,0,0,0,0,0},{5,6,7,0,0,0,0,0},{0,1,2,3,4,0,0,0},{0,1,2,0,0,0,0,0},{2,3,4,0,0,0,0,0},{0,1,2,6,7,0,0,0},{2,3,4,5,6,0,0,0},{0,1,2,3,4,5,6,7}},{{4,5,6,7,0,0,0,0},{6,7,0,0,0,0,0,0},{5,6,7,0,0,0,0,0},{1,2,3,4,0,0,0,0},{1,2,0,0,0,0,0,0},{2,3,4,0,0,0,0,0},{1,2,6,7,0,0,0,0},{2,3,4,5,6,0,0,0},{1,2,3,4,5,6,7,0}},{{4,5,6,7,0,0,0,0},{6,7,0,0,0,0,0,0},{5,6,7,0,0,0,0,0},{2,3,4,0,1,0,0,0},{2,0,1,0,0,0,0,0},{2,3,4,0,0,0,0,0},{2,6,7,0,1,0,0,0},{2,3,4,5,6,0,0,0},{2,3,4,5,6,7,0,1}},{{4,5,6,7,0,0,0,0},{6,7,0,0,0,0,0,0},{5,6,7,0,0,0,0,0},{3,4,0,1,2,0,0,0},{0,1,2,0,0,0,0,0},{3,4,2,0,0,0,0,0},{6,7,0,1,2,0,0,0},{3,4,5,6,2,0,0,0},{3,4,5,6,7,0,1,2}},{{4,5,6,7,0,4,0,0},{6,7,0,0,0,0,0,0},{5,6,7,0,0,0,0,0},{4,0,1,2,3,0,0,0},{0,1,2,0,0,0,0,0},{4,2,3,0,0,0,0,0},{6,7,0,1,2,0,0,0},{4,5,6,2,3,0,0,0},{4,5,6,7,0,1,2,3}},{{5,6,7,0,4,5,0,0},{6,7,0,0,0,0,0,0},{5,6,7,0,0,0,0,0},{0,1,2,3,4,0,0,0},{0,1,2,0,0,0,0,0},{2,3,4,0,0,0,0,0},{6,7,0,1,2,0,0,0},{5,6,2,3,4,0,0,0},{5,6,7,0,1,2,3,4}},{{6,7,0,4,5,6,0,0},{6,7,0,0,0,0,0,0},{6,7,5,0,0,0,0,0},{0,1,2,3,4,0,0,0},{0,1,2,0,0,0,0,0},{2,3,4,0,0,0,0,0},{6,7,0,1,2,0,0,0},{6,2,3,4,5,0,0,0},{6,7,0,1,2,3,4,5}},{{7,0,4,5,6,7,0,0},{7,0,6,0,0,0,0,0},{7,5,6,0,0,0,0,0},{0,1,2,3,4,0,0,0},{0,1,2,0,0,0,0,0},{2,3,4,0,0,0,0,0},{7,0,1,2,6,0,0,0},{2,3,4,5,6,0,0,0},{7,0,1,2,3,4,5,6}}};
|
|
//static uchar nDirs[8][9] = {{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8},{5,3,3,5,3,3,5,5,8}};
|
|
//static uchar* dirVec;
|
|
//int p =-1;
|
|
//if (r== 0) {
|
|
// if (c= =0)
|
|
// p = 1;
|
|
// else if (c == (w-1))
|
|
// p = 2;
|
|
// else
|
|
// p = 0;
|
|
//}
|
|
//else if (r== (h-1)) {
|
|
// if (c == 0)
|
|
// p = 4;
|
|
// else if (c == (w-1))
|
|
// p = 5;
|
|
// else
|
|
// p = 3;
|
|
//}
|
|
//else if (c == 0)
|
|
// p = 6;
|
|
//else if (c == (w-1))
|
|
// p = 7;
|
|
//else
|
|
// p = 8;
|
|
//
|
|
//dirVec = directions[dir][p];
|
|
//int i = 0;
|
|
//int d = dir;
|
|
//for (i; i < nDirs[d][p]; ++i) {
|
|
// tempR = r + freemanR[dirVec[i]];
|
|
// tempC = c + freemanC[dirVec[i]];
|
|
// pos = tempR*w +tempC;
|
|
// if (ptrDataBinary[pos]) {
|
|
// r = tempR;
|
|
// c = tempC;
|
|
// dir = dirVec[i];
|
|
// break;
|
|
// }
|
|
// ptrDataLabels[pos] = (int)currentBlob;
|
|
//}
|
|
//singlePixBlob = i == nDirs[d][p];
|
|
//pos = r*w+c;
|
|
|
|
}
|
|
|
|
void CompLabeler::getNextPointCW()
|
|
{
|
|
//Dir:
|
|
//321
|
|
//4-0
|
|
//567
|
|
m_dir = (m_dir + 2) % 8;
|
|
for (int i = 0; i < 8; ++i) {
|
|
m_tempR = m_r + m_freemanR[m_dir];
|
|
m_tempC = m_c + m_freemanC[m_dir];
|
|
if (!(m_tempR < 0 || m_tempR >= m_h || m_tempC < 0 || m_tempC >= m_w)) {
|
|
m_pos = m_tempR * m_w + m_tempC;
|
|
if (m_ptrDataBinary[m_pos]) {
|
|
m_r = m_tempR;
|
|
m_c = m_tempC;
|
|
break;
|
|
}
|
|
m_ptrDataLabels[m_pos] = m_currentContour;
|
|
}
|
|
m_dir--;
|
|
m_dir = m_dir % 8; //To cycle through values 7->0
|
|
}
|
|
m_pos = m_r * m_w + m_c;
|
|
}
|
|
|
|
int CompLabeler::m_freemanC[8] = {1, 1, 0, -1, -1, -1, 0, 1};
|
|
|
|
int CompLabeler::m_freemanR[8] = {0, -1, -1, -1, 0, 1, 1, 1};
|
|
|
|
void CompLabelerGroup::doLabeling(BlobVector& blobs)
|
|
{
|
|
LabelID label = 0;
|
|
if (m_numThreads > 1) {
|
|
//Preliminary step in order to pre-compute all the blobs crossing the border
|
|
for (int i = 1; i < m_numThreads; i++) {
|
|
cv::Point offset(m_img.size().width, 1);
|
|
CompLabeler lbl(m_img, m_labels, m_labelers[i]->m_startPoint, m_labelers[i]->m_startPoint + offset);
|
|
lbl.m_parent = this;
|
|
lbl.label();
|
|
//cout << "Single pass\t" << lbl.blobs.size()<<endl;
|
|
for (unsigned int i = 0; i < lbl.m_blobs.size(); i++) {
|
|
lbl.m_blobs[i]->setID(label);
|
|
label++;
|
|
blobs.push_back(lbl.m_blobs[i]);
|
|
}
|
|
}
|
|
std::vector<std::thread> ths;
|
|
for (int i = 0; i < m_numThreads; i++) {
|
|
//pthread_create(&tIds[i], NULL, CompLabeler::thread_Labeling, labelers[i]);
|
|
ths.emplace_back(std::thread([label = m_labelers[i]]() {
|
|
CompLabeler::threadLabeling(label);
|
|
}));
|
|
}
|
|
for (int i = 0; i < m_numThreads; i++) {
|
|
//pthread_join(tIds[i], 0);
|
|
if (ths[i].joinable()) {
|
|
ths[i].join();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
m_labelers[0]->label();
|
|
}
|
|
|
|
for (int i = 0; i < m_numThreads; ++i) {
|
|
//cout << "MT pass " <<i<<"\t" << labelers[i]->blobs.size()<<endl;
|
|
for (unsigned int j = 0; j < m_labelers[i]->m_blobs.size(); ++j) {
|
|
m_labelers[i]->m_blobs[j]->setID(label);
|
|
label++;
|
|
blobs.push_back(m_labelers[i]->m_blobs[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
CompLabelerGroup::CompLabelerGroup()
|
|
{
|
|
//m_mutexBlob = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
|
|
m_labels = NULL;
|
|
m_labelers = NULL;
|
|
//m_tIds = NULL;
|
|
}
|
|
|
|
CompLabelerGroup::~CompLabelerGroup()
|
|
{
|
|
if (m_labelers) {
|
|
for (int i = 0; i < m_numThreads; ++i) {
|
|
delete m_labelers[i];
|
|
}
|
|
delete []m_labelers;
|
|
}
|
|
//if (m_tIds) {
|
|
// delete [] m_tIds;
|
|
//}
|
|
if (m_labels) {
|
|
delete [] m_labels;
|
|
}
|
|
}
|
|
|
|
void CompLabelerGroup::set(int nThreads, const cv::Mat& binImg)
|
|
{
|
|
this->m_numThreads = nThreads;
|
|
if (binImg.isContinuous()) {
|
|
this->m_img = binImg;
|
|
}
|
|
else {
|
|
this->m_img = binImg.clone();
|
|
}
|
|
//this->labels = Mat_<int>::zeros(img.size());
|
|
if (m_labels) {
|
|
delete [] m_labels;
|
|
}
|
|
int nPts = binImg.size().width * binImg.size().height;
|
|
m_labels = new BlobContour*[nPts];
|
|
memset(m_labels, 0, nPts*sizeof(Blob*));
|
|
|
|
//if (m_tIds) {
|
|
// delete [] m_tIds;
|
|
//}
|
|
if (m_labelers) {
|
|
for (int i = 0; i < nThreads; ++i) {
|
|
delete m_labelers[i];
|
|
}
|
|
delete [] m_labelers;
|
|
}
|
|
//m_tIds = new pthread_t[nThreads];
|
|
m_labelers = new CompLabeler*[nThreads];
|
|
cv::Size sz = binImg.size();
|
|
//int numPx = sz.width*sz.width;
|
|
int i = 0;
|
|
for (; i < nThreads-1; ++i) {
|
|
int yStart = (int)((float)i / nThreads * sz.height);
|
|
int yEnd = (int)((float)(i + 1) / nThreads * sz.height);
|
|
cv::Point st(0, yStart);
|
|
cv::Point en(sz.width, yEnd);
|
|
m_labelers[i] = new CompLabeler(m_img, m_labels, st, en);
|
|
m_labelers[i]->m_parent = this;
|
|
}
|
|
cv::Point st(0, (int)((float)i / nThreads * sz.height));
|
|
cv::Point en(sz.width, sz.height);
|
|
//st = Point(0,187);
|
|
m_labelers[i] = new CompLabeler(m_img, m_labels, st, en);
|
|
m_labelers[i]->m_parent = this;
|
|
}
|
|
|
|
void CompLabelerGroup::reset()
|
|
{
|
|
if (m_labels) {
|
|
delete [] m_labels;
|
|
m_labels = NULL;
|
|
}
|
|
for (int i = 0; i < m_numThreads; ++i) {
|
|
m_labelers[i]->reset();
|
|
}
|
|
}
|
|
|
|
void CompLabelerGroup::acquireMutex()
|
|
{
|
|
//pthread_mutex_lock(&m_mutexBlob);
|
|
}
|
|
|
|
void CompLabelerGroup::releaseMutex()
|
|
{
|
|
//pthread_mutex_unlock(&m_mutexBlob);
|
|
}
|
|
|