并查集是个什么概念也是通过刷题刷到的,然后就稍微了解了下
小白记录并查集自己实现图像连通区域问题
完整代码放在最后面
并查集可以自己谷歌,目前有点被搞得头晕
在图像里面经常性的需要用连通区域这个概念,尤其是对图像分割,跟踪以及一些需要用到图像基本处理的地方,不过使用OpenCV的话很简单,一个API解决一切问题findContours,不过既然遇到了,就更应该去了解下更底层的东西以及原理性的东西吧!
可能对于连通区域用DFS更好理解吧,DFS:简单点理解就是不撞南墙不回头的那种算法
搞了一下午,被弄得头有点晕了,先记录下来,等清醒了再来理一理思路
- 首先自己生成简单的连通图像
此处有两个白色的连通区域,目的是将他们分割出来
生成图像的代码
Mat Image = Mat::zeros(500, 500, CV_8UC1);
Mat gray(200, 200, CV_8UC1);
gray.setTo(255);
gray.copyTo(Image(Rect(100, 100, 200, 200)));
Image(Rect(0, 0, 10, 20)).setTo(255);
- 然后需要生成的分割图为
总共分为三个区域的连通区域,其实这个有点像是图像分割了,在图像中加个KMeans的话或许就可以了,不过Kmeans原理也不难,有写过这样的博客,转这里
- 如何才能生成上面的图像呢,就是并查集算法了
class Solution {
public:
int director[4][2] = { {0,-1},{-1,0},{0,1},{1,0} };
map<int, int> m;
int find(int x)
{
auto it = m.find(x);
if (it == m.end())
{
m[x] = x;
}
if (m[x] != x)
{
m[x] = find(m[x]);
}
return m[x];
}
void con_union(int x, int y)
{
m[find(y)] = find(x);
}
void solve(vector<vector<int>>& board)
{
int row = board.size();
if (row == 0) return;
int col = board[0].size();
int total_num = row * col;
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
if (board[i][j] == 255)
{
for (int k = 0; k < 4; ++k)
{
int ROW = i + director[k][0];
int COL = j + director[k][1];
if (ROW >= 0 && ROW < row && COL >= 0 && COL < col && board[ROW][COL] == 255)
{
con_union(i*col + j, ROW*col + COL);
}
}
}
}
}
}
};
这里是主要的并查集算法,主要的原理,还是通过find函数进行操作的,对每个坐标位置进行他们之间连通邻点的根值做索引,通过根值进行连通区域的分割操作
先记录下来,完整代码在这里
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
class Solution {
public:
int director[4][2] = { {0,-1},{-1,0},{0,1},{1,0} };
map<int, int> m;
int findx(int x)
{
auto it = m.find(x);
if (it == m.end())
{
m[x] = x;
}
if (m[x] != x)
{
m[x] = findx(m[x]);
}
return m[x];
}
void con_union(int x, int y)
{
m[findx(y)] = findx(x);
}
void solve(vector<vector<int>>& board)
{
int row = board.size();
if (row == 0) return;
int col = board[0].size();
int total_num = row * col;
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
if (board[i][j] == 255)
{
for (int k = 0; k < 4; ++k)
{
int ROW = i + director[k][0];
int COL = j + director[k][1];
if (ROW >= 0 && ROW < row && COL >= 0 && COL < col && board[ROW][COL] == 255)
{
con_union(i*col + j, ROW*col + COL);
}
}
}
}
}
//set s; // 连通区域的数量
//int index = 0;
//for (map::iterator it = m.begin(); it != m.end(); it++)
//{
// index++;
// s.insert(it->second);
//}
//cout << "index=" << index << endl;
//cout << "s.size=" << s.size() << endl;
//int s_size = s.size();
//vector V(s_size, 0);
//int v_begin = 0;
//for (set::iterator s_it = s.begin(); s_it != s.end(); s_it++)
//{
// V[v_begin++] = *s_it;
// cout << *s_it << endl;
//}
vector<int> V_1;
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
int temp = it->second;
if (V_1.empty())
{
V_1.push_back(temp);
}
else
{
if (find(V_1.begin(), V_1.end(), temp) == V_1.end())
{
V_1.push_back(temp);
}
}
}
int s_size = V_1.size();
map<int,int>::iterator it = m.begin();
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
int flag_index = i * col + j;
if (it->first == flag_index)
{
for (int l = 0; l < s_size; l++)
{
if (m[flag_index] == V_1[l])
{
board[i][j] = l + 1;
}
}
it++;
}
}
}
}
};
int main(int argc, char* argv[])
{
Mat Image = Mat::zeros(500, 500, CV_8UC1);
Mat gray(200, 200, CV_8UC1);
gray.setTo(255);
imshow("gray", gray);
gray.copyTo(Image(Rect(100, 100, 200, 200)));
Image(Rect(0, 0, 10, 20)).setTo(255);
imshow("Image", Image);
vector<vector<int>> board(Image.rows, vector<int>(Image.cols));
for (int row = 0; row < Image.rows; ++row)
{
for (int col = 0; col < Image.cols; ++col)
{
board[row][col] = (int)Image.at<uchar>(row, col);
}
}
Solution s;
s.solve(board);
// 辅助颜色层
Vec3b ColorTab[] =
{
Vec3b(0, 0, 255),
Vec3b(0, 255, 0),
Vec3b(255, 0, 0),
Vec3b(0, 255, 255),
Vec3b(255, 0, 255),
Vec3b(255, 255, 0)
};
Mat result;
cvtColor(Image, result, COLOR_GRAY2BGR);
for (int row = 0; row < Image.rows; ++row)
{
for (int col = 0; col < Image.cols; ++col)
{
result.at<Vec3b>(row, col) = ColorTab[board[row][col]];
}
}
imshow("....", result);
waitKey(0);
return 0;
}
不过有些代码肯定是多余的,自行做相应的删减操作吧!
最后有个问题,不知道是不是程序没有释放内存空间还是自己电脑的编译器有问题,前面跑几次还可以,后面总是跑不出来!我也不知道为什么,小白在这里让大佬们解释下呀,感激不尽!
2020-05-28:
重新审了一遍代码:终于知道问题出在了哪里,一个边界越界的问题,vector数组没有先判断下标再去索引相应的值
if (board[ROW][COL] == 255 && ROW >= 0 && ROW < row && COL >= 0 && COL < col)
就这个地方,现在重新改过来了,代码一点问题都没有
这也说明写代码要好好考虑下界限的问题了!!!
后面有时间更新下DFS的连通区域算法!!!
欢迎指正批评!!!
欢迎关注微信公众号–木木夕算法笔记,与博主交流!