Android OpenCV(四十二):图像分割(分水岭法)

分水岭法

分水岭算法介绍,下面这位知乎博主已经讲得非常详细了,详情请自行查阅。

zhuanlan.zhihu.com/p/67741538

分水岭算法的整个过程:

  1. 把梯度图像中的所有像素按照灰度值进行分类,并设定一个测地距离阈值。
  2. 找到灰度值最小的像素点(默认标记为灰度值最低点),让threshold从最小值开始增长,这些点为起始点。
  3. 水平面在增长的过程中,会碰到周围的邻域像素,测量这些像素到起始点(灰度值最低点)的测地距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。
  4. 随着水平面越来越高,会设置更多更高的大坝,直到灰度值的最大值,所有区域都在分水岭线上相遇,这些大坝就对整个图像像素的进行了分区。

过程动画

用上面的算法对图像进行分水岭运算,由于噪声点或其它因素的干扰,可能会得到密密麻麻的小区域,即图像被分得太细(over-segmented,过度分割),这因为图像中有非常多的局部极小值点,每个点都会自成一个小区域。

其中的解决方法:

  1. 对图像进行高斯平滑操作,抹除很多小的最小值,这些小分区就会合并。
  2. 不从最小值开始增长,可以将相对较高的灰度值像素作为起始点(需要用户手动标记),从标记处开始进行淹没,则很多小区域都会被合并为一个区域,这被称为基于图像标记(mark)的分水岭算法

API

public static void watershed(Mat image, Mat markers)

  • 参数一:image,输入图像,必须是CV_8U三通道图像。
  • 参数二:markers,输入/输出32位单通道图像的标记结果。必须与image大小相同。 在将图像传递给第二个参数之前,必须使用大于0的整数索引在图像中粗略标记出所需分割的区域。 因此,每个标记区域表示一个或多个连接分量,像素值分别用1、2、3等来表示。 我们可以通过使用findContoursdrawContours从二值掩码中检索此类标记。 标记是图像处理过程中的“种子”。标记图像中所有没有被标记的像素值为0。在输出图像中,两个区域之间的分割线用-1表示。

操作

/**

  • 图像分割–分水岭法
  • author: yidong
  • 2020/11/9
    */
    class WaterShedActivity : AppCompatActivity() {

private val mBinding: ActivityWaterShedBinding by lazy {
ActivityWaterShedBinding.inflate(
layoutInflater
)
}
private lateinit var mRgb: Mat
private lateinit var mGray: Mat

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)

mRgb = Mat()
mGray = Mat()
val bgr = Utils.loadResource(this, R.drawable.contourpoly)
Imgproc.cvtColor(bgr, mRgb, Imgproc.COLOR_BGR2RGB)
Imgproc.cvtColor(bgr, mGray, Imgproc.COLOR_BGR2GRAY)

mBinding.ivLena.showMat(mGray)

GlobalScope.launch(Dispatchers.IO) {
doWaterShed()
}
}

private fun doWaterShed() {
mBinding.progressBar.setVisible()
val markers = Mat(
mRgb.size(),
CvType.CV_32S,
Scalar.all(0.0)
)
// Imgproc.GaussianBlur(mGray, mGray, Size(13.0, 13.0), 4.0, 4.0
val binary = Mat()
Imgproc.threshold(
mGray,
binary,
20.0,
255.0,
Imgproc.THRESH_BINARY and Imgproc.THRESH_OTSU
)
mBinding.ivResult.showMat(binary)
val contours = mutableListOf()
val hierarchy = Mat()
Imgproc.findContours(
binary,
contours,
hierarchy,
Imgproc.RETR_TREE,
Imgproc.CHAIN_APPROX_SIMPLE
)

for (i in 0 until contours.size) {
Imgproc.drawContours(
markers,
contours,
i,
Scalar.all(i + 1.toDouble()),
-1,
Imgproc.LINE_8,

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

img-NmvoWlda-1719205825034)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值