141 lines
4.7 KiB
C++
141 lines
4.7 KiB
C++
#include <opencv2/imgproc/types_c.h>
|
||
#include <iostream>
|
||
#include "SG_labelling.h"
|
||
|
||
using namespace std;
|
||
//using namespace cv;
|
||
|
||
/// <summary>
|
||
/// 两步法标注
|
||
/// </summary>
|
||
/// <param name="bwImg"> 目标点为“1”, 空白点为“0”</param>
|
||
/// <param name="labImg"> 标注结果。每个点为rgnID, ID从2开始 </param>
|
||
/// <param name="labelRgns"></param>
|
||
void SG_TwoPassLabel(const cv::Mat& bwImg, cv::Mat& labImg, std::vector<SSG_Region>& labelRgns)
|
||
{
|
||
assert(bwImg.type() == CV_8UC1);
|
||
bwImg.convertTo(labImg, CV_32SC1);
|
||
int rows = bwImg.rows - 1;
|
||
int cols = bwImg.cols - 1;
|
||
|
||
//二值图像像素值为0或1,为了不冲突,label从2开始
|
||
int label = 2;
|
||
std::vector<int> labelSet;
|
||
labelSet.push_back(0);
|
||
labelSet.push_back(1);
|
||
|
||
//第一次扫描
|
||
int* data_prev = (int*)labImg.data;
|
||
int* data_cur = (int*)(labImg.data + labImg.step);
|
||
int left, up;//指针指向的像素点的左方点和上方点
|
||
int neighborLabels[2];
|
||
for (int i = 1; i < rows; i++)// 忽略第一行和第一列,其实可以将labImg的宽高加1,然后在初始化为0就可以了
|
||
{
|
||
data_cur++;
|
||
data_prev++;
|
||
for (int j = 1; j < cols; j++, data_cur++, data_prev++)
|
||
{
|
||
if (*data_cur != 1)//当前点不为1,扫描下一个点
|
||
continue;
|
||
left = *(data_cur - 1);
|
||
up = *data_prev;
|
||
|
||
int count = 0;
|
||
for (int curLabel : {left, up})
|
||
{
|
||
if (curLabel > 1)
|
||
neighborLabels[count++] = curLabel;
|
||
}
|
||
if (!count)//赋予一个新的label
|
||
{
|
||
labelSet.push_back(label);
|
||
*data_cur = label;
|
||
label++;
|
||
continue;
|
||
}
|
||
//将当前点标记设为左点和上点label的最小值
|
||
int smallestLabel = neighborLabels[0];
|
||
if (count == 2 && neighborLabels[1] < smallestLabel)
|
||
smallestLabel = neighborLabels[1];
|
||
*data_cur = smallestLabel;
|
||
//设置等价表,这里可能有点难理解
|
||
//左点有可能比上点小,也有可能比上点大,两种情况都要考虑,例如
|
||
//0 0 1 0 1 0 x x 2 x 3 x
|
||
//1 1 1 1 1 1 -> 4 4 2 2 2 2
|
||
//要将labelSet中3的位置设置为2
|
||
for (int k = 0; k < count; k++)
|
||
{
|
||
int neiLabel = neighborLabels[k];
|
||
int oldSmallestLabel = labelSet[neiLabel];
|
||
if (oldSmallestLabel > smallestLabel)
|
||
{
|
||
labelSet[oldSmallestLabel] = smallestLabel;
|
||
}
|
||
else if (oldSmallestLabel < smallestLabel)
|
||
labelSet[smallestLabel] = oldSmallestLabel;
|
||
}
|
||
}
|
||
data_cur++;
|
||
data_prev++;
|
||
}
|
||
//上面一步中,有的labelSet的位置还未设为最小值,例如
|
||
//0 0 1 0 1 x x 2 x 3
|
||
//0 1 1 1 1 -> x 4 2 2 2
|
||
//1 1 1 0 1 5 4 2 x 2
|
||
//上面这波操作中,把labelSet[4]设为2,但labelSet[5]仍为4
|
||
//这里可以将labelSet[5]设为2
|
||
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;
|
||
}
|
||
//第二次扫描,用labelSet进行更新,最后一列
|
||
std::vector<SSG_Region*> labelInfo;
|
||
labelInfo.resize(labelSet.size(), nullptr);
|
||
|
||
data_cur = (int*)labImg.data;
|
||
for (int i = 0; i < labImg.rows; i++)
|
||
{
|
||
for (int j = 0; j < labImg.cols; j++)
|
||
{
|
||
*data_cur = labelSet[*data_cur];
|
||
if (*data_cur > 1) //有效label
|
||
{
|
||
//统计Region信息
|
||
SSG_Region* info_cur = (SSG_Region*)labelInfo[*data_cur];
|
||
if (nullptr == info_cur)
|
||
{
|
||
SSG_Region new_rgn = { {j,j,i,i}, 1, *data_cur };
|
||
labelRgns.push_back(new_rgn); //push_back()后,vector中内存单元可能会被改动
|
||
for (int m = 0; m < labelRgns.size(); m++)
|
||
{
|
||
info_cur = &labelRgns[m];
|
||
labelInfo[info_cur->labelID] = info_cur;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
assert(*data_cur == info_cur->labelID);
|
||
if (info_cur->roi.left > j)
|
||
info_cur->roi.left = j;
|
||
if (info_cur->roi.right < j)
|
||
info_cur->roi.right = j;
|
||
if (info_cur->roi.top > i)
|
||
info_cur->roi.top = i;
|
||
if (info_cur->roi.bottom < i)
|
||
info_cur->roi.bottom = i;
|
||
info_cur->ptCounter++;
|
||
}
|
||
}
|
||
data_cur++;
|
||
}
|
||
}
|
||
|
||
return;
|
||
} |