После кода DXM выше, который предполагает 4-компонентные компоненты, вот версия для 'findCC', которая обнаруживает 8-связанные компоненты.
void findCC(const cv::Mat& src, std::vector<ConnectedComponent>& cc) {
if (src.empty()) return;
CV_Assert(src.type() == CV_8U);
cc.clear();
int total_pix = int(src.total());
int *frame_label = new int[total_pix];
DisjointSet labels(total_pix);
int *root_map = new int[total_pix];
int x, y;
const uchar* cur_p;
const uchar* prev_p = src.ptr<uchar>(0);
int left_val, up_val, up_left_val, up_right_val;
int cur_idx, left_idx, up_idx, up_left_idx, up_right_idx;
cur_idx = 0;
//first logic loop
for (y = 0; y < src.rows; y++) {
cur_p = src.ptr<uchar>(y);
for (x = 0; x < src.cols; x++, cur_idx++) {
left_idx = cur_idx - 1;
up_idx = cur_idx - src.size().width;
up_left_idx = up_idx - 1;
up_right_idx = up_idx + 1;
if (x == 0)
{
left_val = 0;
}
else
{
left_val = cur_p[x - 1];
}
if (y == 0)
{
up_val = 0;
}
else
{
up_val = prev_p[x];
}
if (x == 0 || y == 0)
{
up_left_val = 0;
}
else
{
up_left_val = prev_p[x-1];
}
if (x == src.cols - 1 || y == 0)
{
up_right_val = 0;
}
else
{
up_right_val = prev_p[x+1];
}
if (cur_p[x] > 0) {
//current pixel is foreground and has no connected neighbors
if (left_val == 0 && up_val == 0 && up_left_val == 0 && up_right_val == 0) {
frame_label[cur_idx] = (int)labels.add();
root_map[frame_label[cur_idx]] = -1;
}
//Current pixel is foreground and has at least one neighbor
else
{
vector<int> frame_lbl;
frame_lbl.reserve(4);
//Find minimal label
int min_frame_lbl = INT_MAX;
int valid_entries_num = 0;
if (left_val != 0)
{
frame_lbl.push_back(frame_label[left_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[left_idx]);
valid_entries_num++;
}
if (up_val != 0)
{
frame_lbl.push_back(frame_label[up_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[up_idx]);
valid_entries_num++;
}
if (up_left_val != 0)
{
frame_lbl.push_back(frame_label[up_left_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[up_left_idx]);
valid_entries_num++;
}
if (up_right_val != 0)
{
frame_lbl.push_back(frame_label[up_right_idx]);
min_frame_lbl = min(min_frame_lbl, frame_label[up_right_idx]);
valid_entries_num++;
}
CV_Assert(valid_entries_num > 0);
frame_label[cur_idx] = min_frame_lbl;
//Unite if necessary
if (valid_entries_num > 1)
{
for (size_t i = 0; i < frame_lbl.size(); i++)
{
labels.unite(frame_lbl[i], min_frame_lbl);
}
}
}
}//endif
else {
frame_label[cur_idx] = -1;
}
} //end for x
prev_p = cur_p;
}//end for y
//second loop logic
cur_idx = 0;
int curLabel;
int connCompIdx = 0;
for (y = 0; y < src.size().height; y++) {
for (x = 0; x < src.size().width; x++, cur_idx++) {
curLabel = frame_label[cur_idx];
if (curLabel != -1) {
curLabel = labels.find(curLabel);
if (root_map[curLabel] != -1) {
cc[root_map[curLabel]].addPixel(x, y);
}
else {
cc.push_back(ConnectedComponent(x, y));
root_map[curLabel] = connCompIdx;
connCompIdx++;
}
}
}//end for x
}//end for y
//Free up allocated memory
delete[] frame_label;
delete[] root_map;
}