效果:将二值化图像的连通区域划分出来
前
后:
优点:
1.图像尺寸大的也能用
2.提供一个思路
原理:
1.逐行遍历原图像,将当前第n行连接的部分放到一起并分组,然后在n-1行寻找连通的部分,如果找到就归入该组,如果没找到就列为新组
2.在向上寻找的时候可能遇到有:当前行n的某一连通区域在n-1行找到2个或2个以上对应的区域、当前行n有多个区域在n-1行找到同一个区域的问题,这些解决起来也不算难,就不提了
被我pass的方案:
逐个点遍历图像,通过递归的方式寻找连通区域(用这个方法记得copy一个图像出来,并且在遍历的时候记得修改像素,不然会死循环)。
pass原因:我要处理的图像比较大,会出现堆栈空间不够的问题,我试过增加堆栈空间,确实可行,但是这不灵活。
代码:
//连通区域提取
std::vector<std::vector<cv::Point>> getArea(Mat mat) {
std::vector<int> last_row_countour_indexs;//上一行白色块所在的contours的索引,提高效率
std::vector<std::vector<cv::Point>> contours;
for (int i = 0; i < mat.rows; i++) {
std::vector<int> row_countour_indexs;//这一行白色块所在的contours的索引,提高效率
//本行连续区块
std::vector<std::vector<int>> continue_pos;
bool newflag = true;
std::vector<int> temp_block;
for (int j = 0; j < mat.cols; j++) {
uchar *data = mat.ptr<uchar>(i, j);
if (newflag) {
temp_block.clear();
}
if (data[0] == 255 && data[1] == 255 && data[2] == 255) {
temp_block.push_back(j);
newflag = false;
}
else {
newflag = true;
if (temp_block.size() > 0) {
continue_pos.push_back(temp_block);
}
}
}
if (!newflag) {
if (temp_block.size() > 0) {
continue_pos.push_back(temp_block);
}
}
//用上一行的信息判断这一行每个区块是属于哪个contours的,如果同一个区块属于不同contours,那就把那不同的contours合并
for (int j = 0; j < mat.cols; j++) {
uchar *data = mat.ptr<uchar>(i, j);
if (data[0] == 255 && data[1] == 255 && data[2] == 255) {
//白色像素,遍历已有的区域,判断是否建立新区域
bool find = false;
std::vector<int> find_indexs;
//在上一行里找
int temp = 0;
int temp2 = 0;
if (last_row_countour_indexs.size() > 0) {
int index = -1;
if (last_row_countour_indexs[j] >= 0) {
//找到就在当前行对应的白块上标记contours的索引
index = last_row_countour_indexs[j];
temp++;
}
if (j + 1<mat.cols&&last_row_countour_indexs[j + 1] >= 0) {
index = last_row_countour_indexs[j + 1];
temp++;
temp2++;
}
if (j - 1 >= 0 && last_row_countour_indexs[j - 1] >= 0) {
index = last_row_countour_indexs[j - 1];
temp++;
temp2++;
}
if (temp2 == 2&&(last_row_countour_indexs[j + 1]!= last_row_countour_indexs[j - 1])) {
//一点连接两个区域
index = -2;
}
row_countour_indexs.push_back(index);
}
else {
row_countour_indexs.push_back(-1);
}
}
else {
row_countour_indexs.push_back(-1);
}
}
//要合并的contours索引
std::vector<std::vector<int>> join_indexs;
for (int m = 0; m < continue_pos.size(); m++) {
std::vector<int> temp;
for (int n = 0; n < continue_pos[m].size(); n++) {
bool find = false;
if (row_countour_indexs[continue_pos[m][n]] >= 0) {
for (int z = 0; z < temp.size(); z++) {
if (row_countour_indexs[continue_pos[m][n]] == temp[z]) {
find = true;
break;
}
}
if (!find) {
temp.push_back(row_countour_indexs[continue_pos[m][n]]);
}
}
//一个点连接多个
if (row_countour_indexs[continue_pos[m][n]] == -2) {
row_countour_indexs[continue_pos[m][n]] = last_row_countour_indexs[continue_pos[m][n] - 1];
temp.push_back(last_row_countour_indexs[continue_pos[m][n] + 1]);
temp.push_back(last_row_countour_indexs[continue_pos[m][n] - 1]);
}
}
join_indexs.push_back(temp);
}
/*
if (i>=253&&i<=256) {
cout << endl;
for (int m = 0; m < row_countour_indexs.size(); m++) {
cout << m << ":" << row_countour_indexs[m] << "||";
}
cout << endl;
for (int m = 0; m < join_indexs.size(); m++) {
cout << m << ":" << join_indexs[m].size() << "||";
}
cout << endl;
}
*/
//合并contours或者新建
for (int m = 0; m < join_indexs.size(); m++) {
if (join_indexs[m].size() == 0) {
//新建
std::vector<cv::Point> newBlock;
for (int n = 0; n < continue_pos[m].size(); n++) {
//将当前行新区块添加到contours里
newBlock.push_back(cv::Point(continue_pos[m][n], i));
row_countour_indexs[continue_pos[m][n]] = contours.size();
}
contours.push_back(newBlock);
}
if (join_indexs[m].size() > 1) {
//合并
int index = join_indexs[m][0];
//将要合并的合并到第一个
for (int n = 1; n < join_indexs[m].size(); n++) {
if (join_indexs[m][n] == index) {
continue;
}
contours[index].insert(contours[index].begin(), contours[join_indexs[m][n]].begin(), contours[join_indexs[m][n]].end());
/*for (int x = 0; x < contours[join_indexs[m][n]].size(); x++) {
contours[index].push_back(contours[join_indexs[m][n]][x]);
}*/
contours[join_indexs[m][n]].clear();
//修改所有和这个contours有关的新点
for (int x = m+1; x < join_indexs.size(); x++) {
for (int y = 0; y < join_indexs[x].size(); y++) {
if (join_indexs[x][y] == join_indexs[m][n]) {
join_indexs[x][y] = index;
}
}
}
//修改所有已记录的row_countour_indexs和join_indexs[m][n]相关的都要换成index
for (int x = 0; x < row_countour_indexs.size(); x++) {
if (row_countour_indexs[x] == join_indexs[m][n]) {
row_countour_indexs[x] = index;
}
}
}
//将这一行的内容添加到新的集合里,并修改对应索引
for (int n = 0; n < continue_pos[m].size(); n++) {
contours[index].push_back(cv::Point(continue_pos[m][n], i));
row_countour_indexs[continue_pos[m][n]] = index;
}
}
if (join_indexs[m].size() == 1) {
//将这一行的内容添加到新的集合里,并修改对应索引
for (int n = 0; n < continue_pos[m].size(); n++) {
contours[join_indexs[m][0]].push_back(cv::Point(continue_pos[m][n], i));
row_countour_indexs[continue_pos[m][n]] = join_indexs[m][0];
}
}
}
/*
for (int x = 0; x < join_indexs.size(); x++) {
for (int y = 0; y < join_indexs[y].size(); y++) {
cout << join_indexs[x][y] << endl;
}
}
for (int x = 0; x < row_countour_indexs.size(); x++) {
cout << row_countour_indexs[x] << endl;
}
*/
last_row_countour_indexs = row_countour_indexs;
}
return contours;
}