图像处理 Random Walks分割——基于随机游走的图像分割算法

基于随机游走的图像分割算法是属于图论分割方法中的一种,其实这个算法的原理就是通过求解一个邻接矩阵方程组

  1. 算法开始前,先简单描述一下随机游走模型

一维随机游走问题:设一个质点(随机游走者)沿着一条直线运动,单位时间内只能运动一个单位长度,且只能停留在该直线上的整数点,假设在时刻t,该质点位于直线上的点i,那么在时刻t +1,该质点的位置有三种可能:①以p 的概率跳到整数点i-1,②或以q的概率跳到点i+1,③或以r=1-p-q的概率继续停留在点i ,由于每一步的结果都是独立的,且每种情况发生的概率之和都为1,则该过程服从伯努利分布,称为贝努利随机游走过程。当 p=q=0.5时,即质点在下一时刻到达其相邻点的概率是相等的,称为简单的随机游走。

例子1:如下图所示,假设某一时刻一质点位于刻度2的位置,质点左右游走的概率各为0.5,那么下一时刻该质点既有可能往左走,也有可能往右走,当质点运动到位置0、5位置时,质点停止运动,求质点到最后运动到位置5的概率?该问题便是随机游走问题。

对于一维的简单随机游走问题,满足:

其中,x为当前的位置点,x-1、x+1为位置x的左右邻接顶点。根据该公式,我们可以列出由n个未知数组成的n个方程组,可以发现该方程组的系数矩阵即为拉普拉斯邻接矩阵。拉普拉斯矩阵是非满秩矩阵,需要添加边界约束条件,方程组才有唯一解。

如例子1的问题,设添加边界约束条件:

则最后可以列出如下方程组,求出各点到位置5的概率。

  1. 基于随机游走的图像分割算法

①参考文献:《Random Walks for Image Segmentation》

②文献概述:随机游走算法是一种基于图论的分割算法,属于一种交互式的图像分割。它的分割思想是,以图像的像素为图的顶点,相邻像素之间的四邻域或八邻域关系为图的边,并根据像素属性及相邻像素之间特征的相似性定义图中各边的权值,以此构建网络图,然后由通过用户手工指定前景和背景标记,即前景物体和背景物体的种子像素,以边上的权重为转移概率,未标记像素节点为初始点,计算每个未标记节点首次到达各种子像素的概率,根据概率大小,划分未标记节点,得到最终分割结果。

例子2:如图下所示,图中的小圆圈代表图像上的每个像素点。L1,L2,L3三个种子点分别由用户交互输入,作为标记的种子点。现要把图像分割成对应的三部分。

③算法流程:

A.计算图中任意一点vi与其各个邻接顶点连接边的权重:

其中,表示个像素点的灰度值、或纹理信息等参数;

  1. 对于图中任意一点vi的概率,其满足随机游走概率公式:

其中,Ni为vi点的邻接顶点(可为四邻接顶点或八邻接顶点),根据上式,可构建图的拉普拉斯矩阵,然而拉普拉斯是非满秩矩阵,需要添加边界约束条件,才可根据方程组解出个各未知点的概率。也就是将图像分割问题转换为Dirichlet问题进行求解。

  1. 添加边界约束条件:以已标记的K类顶点作为边界约束条件,求解未知点到各个类的概率。如下图所示:求解各未知点游走到L1的概率,则以,作为约束条件,可求得个未知点的概率,如下图所示:

到达L1的概率

到达L2的概率

到达L3的概率

  1.  每一个未标记点,根据获得的对 K 类标记的隶属度值进行判断,若未标记点到达第k类的概率最大,则将未标记节点vi判别为属于类别k,完成分割。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
随机游走图像分割是一种基于算法图像分割方法,其基本思想是将像看作一个,通过随机游走的方式寻找像中不同区域的边界。本文将介绍如何使用OpenCV库和C语言实现随机游走图像分割。 1. 像预处理 首先,需要对输入的像进行预处理,将其转换为灰度像,并进行高斯滤波和边缘检测,以便更好地找到像的边界。这可以通过以下代码实现: ```c Mat src = imread("input.jpg", IMREAD_GRAYSCALE); Mat blur; GaussianBlur(src, blur, Size(5, 5), 0); Mat edges; Canny(blur, edges, 50, 200); ``` 2. 构建像的邻接矩阵 接下来,需要将像转换为一个邻接矩阵,以便进行随机游走。邻接矩阵中的每个元素表示两个像素之间是否存在边。这里使用4邻域连接,即每个像素与其上下左右四个像素相连。邻接矩阵可以通过以下代码实现: ```c int rows = edges.rows; int cols = edges.cols; int num_vertices = rows * cols; Mat adj_matrix = Mat::zeros(num_vertices, num_vertices, CV_32F); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int vertex = i * cols + j; if (i > 0) { adj_matrix.at<float>(vertex, (i - 1) * cols + j) = edges.at<uchar>(i - 1, j) / 255.0; } if (j > 0) { adj_matrix.at<float>(vertex, i * cols + (j - 1)) = edges.at<uchar>(i, j - 1) / 255.0; } if (i < rows - 1) { adj_matrix.at<float>(vertex, (i + 1) * cols + j) = edges.at<uchar>(i + 1, j) / 255.0; } if (j < cols - 1) { adj_matrix.at<float>(vertex, i * cols + (j + 1)) = edges.at<uchar>(i, j + 1) / 255.0; } } } ``` 3. 随机游走 随机游走的过程中,从像中随机选取一个像素作为起点,然后根据邻接矩阵中的权重随机选择下一个像素,直至到达一个边界像素。这个过程可以重复多次,以获得更好的分割结果。 ```c int num_walks = 10000; // 随机游走次数 int num_labels = 2; // 分割结果的类别数 vector<int> labels(num_vertices); for (int i = 0; i < num_walks; i++) { int start_vertex = rand() % num_vertices; int curr_vertex = start_vertex; while (true) { vector<int> neighbors; for (int j = 0; j < num_vertices; j++) { if (adj_matrix.at<float>(curr_vertex, j) > 0) { neighbors.push_back(j); } } if (neighbors.empty()) { break; } int next_vertex = neighbors[rand() % neighbors.size()]; curr_vertex = next_vertex; if (edges.at<uchar>(curr_vertex / cols, curr_vertex % cols) > 0) { labels[start_vertex] = 1; break; } } } ``` 4. 显示分割结果 最后,将分割结果显示出来。可以将分割结果中标记为1的像素显示为白色,其他像素显示为黑色。 ```c Mat result = Mat::zeros(rows, cols, CV_8U); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int vertex = i * cols + j; if (labels[vertex] == 1) { result.at<uchar>(i, j) = 255; } } } imshow("result", result); waitKey(0); ``` 完整代码如下: ```c #include <iostream> #include <vector> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { Mat src = imread("input.jpg", IMREAD_GRAYSCALE); Mat blur; GaussianBlur(src, blur, Size(5, 5), 0); Mat edges; Canny(blur, edges, 50, 200); int rows = edges.rows; int cols = edges.cols; int num_vertices = rows * cols; Mat adj_matrix = Mat::zeros(num_vertices, num_vertices, CV_32F); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int vertex = i * cols + j; if (i > 0) { adj_matrix.at<float>(vertex, (i - 1) * cols + j) = edges.at<uchar>(i - 1, j) / 255.0; } if (j > 0) { adj_matrix.at<float>(vertex, i * cols + (j - 1)) = edges.at<uchar>(i, j - 1) / 255.0; } if (i < rows - 1) { adj_matrix.at<float>(vertex, (i + 1) * cols + j) = edges.at<uchar>(i + 1, j) / 255.0; } if (j < cols - 1) { adj_matrix.at<float>(vertex, i * cols + (j + 1)) = edges.at<uchar>(i, j + 1) / 255.0; } } } int num_walks = 10000; int num_labels = 2; vector<int> labels(num_vertices); for (int i = 0; i < num_walks; i++) { int start_vertex = rand() % num_vertices; int curr_vertex = start_vertex; while (true) { vector<int> neighbors; for (int j = 0; j < num_vertices; j++) { if (adj_matrix.at<float>(curr_vertex, j) > 0) { neighbors.push_back(j); } } if (neighbors.empty()) { break; } int next_vertex = neighbors[rand() % neighbors.size()]; curr_vertex = next_vertex; if (edges.at<uchar>(curr_vertex / cols, curr_vertex % cols) > 0) { labels[start_vertex] = 1; break; } } } Mat result = Mat::zeros(rows, cols, CV_8U); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int vertex = i * cols + j; if (labels[vertex] == 1) { result.at<uchar>(i, j) = 255; } } } imshow("result", result); waitKey(0); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值