java按照灰度值切割_新手学,java使用分水岭算法进行图像切割(一)

近期被图像切割整的天昏地暗的,在此感谢老朋友周洋给我关于分水岭算法的指点!本来打算等彩色图像切割有个完满的结果再写这篇文章,可是考虑到到了这一步也算是一个阶段,所以打算对图像切割做一个系列的博文,于是先写这篇。

啰嗦了这么多!先看效果:

rV577WqV5P

rV577WqV5P

bcd00657785e4859a92cf7b5291ea709.png

效果一般,存在着非常多过切割现象,但比没使用滤波之前的效果好非常多,过切割是分水岭算法的通病。这个兴许博文会继续解决。

本文用java实现的是基于自己主动种子区域的分水岭算法,注意本文是基于单色的切割,所以将输入图片首先进行灰度化处理,这个比較简单,不多提了;因此,对于彩色图像,会存在一些偏差,这个在兴许博文里我会去解决。关于分水岭算法的概念,请自行百度,本系列主讲怎样实现以及实现效果。

算法大致分为四步:图像预处理、 种子区域获取、浸水过程(区域增长)、切割结果的合并处理。另外,算法在分水岭过程中的区域表示上,採用并查集的数据结构表示区域块,这样做的优点在于简化生长过程中的合并处理,关于并查集,參见我这篇博文: http://blog.csdn.net/abcd_d_/article/details/40316455。

1、图像预处理过程:

本文採用二维高斯滤波进行图像(sigma=3.0)的平滑操作,经验证去操平滑效果好于中值滤波,读者能够自己实验其他的滤波。另外,为了简化操作,二维高斯模板可近似为两个一维的高斯模板,也就是在下图中,左边的滤波过程近似为右边的滤波过程。

L3Byb3h5L2h0dHAvbXkuY3Nkbi5uZXQvdXBsb2Fkcy8yMDEyMDQvMjkvMTMzNTYyOTQ4OV8xOTYzLmpwZw==.jpg

L3Byb3h5L2h0dHAvbXkuY3Nkbi5uZXQvdXBsb2Fkcy8yMDEyMDQvMjkvMTMzNTYyOTU3MV85NzgxLmpwZw==.jpg

核心代码为:

/**

* * 将图像进行高斯模糊:先利用模糊函数计算高斯模板矩阵,然后进行卷积运算。

*

*@高斯模糊 :高斯模糊是一种图像滤波器,它使用正态分布(高斯函数)计算模糊模板,并使用该模板与原图像做卷积运算,达到模糊图像的目的。

*在实际应用中,在计算高斯函数的离散近似时,在大概3σ距离之外的像素都能够看作不起作用,这些像素的计算也就能够忽略。

*通常,图像处理程序仅仅须要计算的矩阵就能够保证相关像素影响。

*

* @param source

* @param index 表示不同的sigma相应的模板

* @return double[][] 模糊后的图像信息矩阵

*/

public static double[][] gaussTran(double[][] source,int index){

int height=source.length;

int width=source[0].length;

///保存高斯过滤后的结果

double[][] result=new double[height][width];

double[] template=GaussTemplate1D.gettemplateX_Y(index);

int tWH=template.length;///模板维数

for(int i=0;i

for(int j=0;j

///进行模糊处理——————卷积运算

double sum=0.0;///卷积结果

for(int m=0;m

///计算与模板相应的图像上的位置

int x=j-(int)tWH/2+m;

int y=i;//-(int)tWH/2+m;

//假设模板数据没有超过边界

if(x>=0&&x

sum=sum+source[y][x]*template[m];

}

}

for(int m=0;m

///计算与模板相应的图像上的位置

int x=j;

int y=i-(int)tWH/2+m;//-(int)tWH/2+m;

//假设模板数据没有超过边界

if(y>=0&&y

sum=sum+source[y][x]*template[m];

}

}

result[i][j]=sum/2;

}

}

int i=0;

i++;

return result;

}

效果为(左边是原图):

rV577WqV5P

9416bc7ed9c553b665ea3c980351ca97.png

rV577WqV5P

2、种子区域选取:

首先,获取梯度图像:高斯滤波图像使用sobel算子求取梯度图像。

然后,种子区域获取以及标记:梯度图像中,将梯度值小于预先设置的阈值THRESHOLD的像素点的灰度值设置为0,而其它像素点的灰度值等于其梯度值。这样每个像素都标记之后就開始进行区域增长,採用同一区域属于一个并查集的方法,将灰度值为0的区域进行分类标记(这些信息存储在blockData里)。如图,每个黑色块属于一个类(也就是一个种子区域)。

rV577WqV5P

10979da3a2ee48d8929ed65f70092894.png

rV577WqV5P

3、浸水过程(也就是区域生长过程):

參照周洋告诉我的方法:三层循环,第一层是梯度值从阈值到最大值,里面两层是二维图像数据的遍历。採用八领域的推断方法,假设某个未被标记为0(未知)的点周围仅仅有一个被标记为零的点(种子),则该点归并到该种子区域中,假设有两个以上被标记的点,而且属于不同的区域,那么该点标记为山脊(轮廓线)。对于外层循环的每个梯度值,区域生长的停止条件:没有新的点被并入到某个区域。这样事实上就有四层循环,由于须要一层来推断是否有新点被并入到种子区域。

效果图例如以下:

rV577WqV5P

8d7954f978f6db8dd14143202f96b45b.png

rV577WqV5P

能够看出,分水岭算法的优点在于能够得到一个个封闭区域,这个一般的二值化的轮廓图像是得不到的。

另外,经过对照发现,高斯滤波对降低过切割有着比較理想的作用,可是也不能消除过切割,因此须要有第四步——区域合并。这部分在兴许博文中我会继续讲。

由于还未写完,所以代码可能显得比較乱,比方程序中有个map成员变量,实际没多大意义,但考虑到測试用,还望见谅!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以给您提供Python实现的代码。请确保已经安装了OpenCV和NumPy库。 ```python import cv2 import numpy as np # 读取灰度图像 img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE) # 对图像进行中值滤波 img = cv2.medianBlur(img, 5) # 使用Sobel算子计算图像的梯度幅值 grad_x = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=3) grad_y = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=3) grad = cv2.subtract(grad_x, grad_y) grad = cv2.convertScaleAbs(grad) # 对梯度幅值图像进行二值化处理 _, thresh = cv2.threshold(grad, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) # 对二值化图像进行开运算和闭运算操作 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2) sure_bg = cv2.dilate(opening, kernel, iterations=3) closing = cv2.morphologyEx(sure_bg, cv2.MORPH_CLOSE, kernel, iterations=3) # 计算图像的距离变换 dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 5) _, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0) # 计算未知区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg, sure_fg) # 使用连通组件算法对未知区域进行标记 _, markers = cv2.connectedComponents(sure_fg) # 对标记进行加一操作,使得背景标记为1,未知区域标记为2,前景标记为3 markers = markers + 1 markers[unknown == 255] = 0 # 应用分水岭算法进行图像分割 markers = cv2.watershed(img, markers) # 对分割结果进行可视化展示 img[markers == -1] = [255, 0, 0] # 将分割线标记为红色 cv2.imshow("Segmented Image", img) cv2.waitKey(0) ``` 在这个代码中,我们首先使用 `cv2.imread()` 函数读取了一张灰度图像,并对其进行了中值滤波。然后,我们使用Sobel算子计算了图像的梯度幅值,对其进行了二值化处理,并使用开运算和闭运算操作对其进行了预处理。 接下来,我们计算了图像的距离变换,并使用连通组件算法对未知区域进行了标记。最后,我们应用分水岭算法进行图像分割,并将分割线标记为红色,以便于可视化展示。 希望这个代码对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值