首先,输入的矩阵binImg连通区域都用1表示,剩余的都是0
函数实现:
//两遍扫描法 八领域
void CPointCloud::Two_Pass( cv::Mat binImg, cv::Mat &lableImg) //两遍扫描法
{
if (binImg.empty() ||
binImg.type() != CV_8UC1)
{
return;
}
// 第一个通路
lableImg.release();
lableImg = binImg;
int label = 1;
std::vector<int> labelSet;
labelSet.push_back(0);
labelSet.push_back(1);
int rows = binImg.rows - 1;
int cols = binImg.cols - 1;
uchar *data = lableImg.ptr<uchar>(0);
if (data[0]==1)
{
labelSet.push_back(++label);
data[0] = label;
labelSet[label] = label;
}
for (int i=1;i<lableImg.cols;i++)
{
if (data[i] == 1)
{
if (data[i-1] != 0)
{
data[i] = label;
}
else
{
labelSet.push_back(++label);
data[i] = label;
labelSet[label] = label;
}
}
}
for (int i=1;i<lableImg.rows;i++)
{
uchar *ndatafront = lableImg.ptr<uchar>(i-1);
uchar *ndata = lableImg.ptr<uchar>(i);
if (ndatafront[0]!=0)
{
ndata[0]=ndatafront[0];
}
else
{
labelSet.push_back(++label);
ndata[0] = label;
labelSet[label] = label;
}
}
for (int i = 1; i < rows+1; i++)
{
uchar* data_preRow = lableImg.ptr<uchar>(i-1);
uchar* data_curRow = lableImg.ptr<uchar>(i);
for (int j = 1; j < cols+1; j++)
{
if (data_curRow[j] == 1)
{
std::vector<int> neighborLabels;
neighborLabels.reserve(2);
int leftPixel = data_curRow[j-1];
int upPixel = data_preRow[j];
int upleftpixel = data_preRow[j-1];
if ( leftPixel >1)
{
neighborLabels.push_back(leftPixel);
}
if (upPixel >1)
{
neighborLabels.push_back(upPixel);
}
if (upleftpixel >1)
{
neighborLabels.push_back(upleftpixel);
}
if (neighborLabels.empty())
{
labelSet.push_back(++label); // 不连通,标签+1
data_curRow[j] = label;
labelSet[label] = label;
}
else
{
std::sort(neighborLabels.begin(), neighborLabels.end());
int smallestLabel = neighborLabels[0];
data_curRow[j] = smallestLabel;
// 保存最小等价表
for (size_t k = 1; k < neighborLabels.size(); k++)
{
int tempLabel = neighborLabels[k];
int& oldSmallestLabel = labelSet[tempLabel];
if (oldSmallestLabel > smallestLabel)
{
labelSet[oldSmallestLabel] = smallestLabel;
oldSmallestLabel = smallestLabel;
}
else if (oldSmallestLabel < smallestLabel)
{
labelSet[smallestLabel] = oldSmallestLabel;
}
}
}
}
}
}
// 更新等价对列表
// 将最小标号给重复区域
for (size_t i = 2; i < labelSet.size(); i++)
{
int curLabel = labelSet[i];
int preLabel = labelSet[curLabel];
while (preLabel != curLabel)
{
curLabel = preLabel;
preLabel = labelSet[preLabel];
}
labelSet[i] = curLabel;
}
for (int i = 0; i < rows; i++)
{
uchar* data = lableImg.ptr<uchar>(i);
for (int j = 0; j < cols; j++)
{
int pixelLabel = data[j];
data[j] = labelSet[pixelLabel];
}
}
}