首页 > 编程语言 >分水岭算法的理解和应用

分水岭算法的理解和应用

时间:2023-05-05 21:23:00浏览次数:51  
标签:阈值 区域 cv2 像素 算法 理解 灰度 图像 分水岭

原文:https://blog.csdn.net/Evonnehyf/article/details/104066799

分水岭算法
主要思想
图像的灰度空间很像地球表面的整个地理结构,每个像素的灰度值代表高度。分水岭就是灰度值较大的像素连成的线。二值化阈值可以理解为水平面,比灰度二值化阈值小的像素区域会被淹没。
随着水位线的升高,被淹没的区域越来越多,通过“修建大坝”防止两个区域的水汇集。最终整张图像分成两个部分:一是水坝线(分水岭线像素集),二是水淹区域(像素集)。
1 预备知识
1.1 测地距离
首先,当根据经纬度计算地球上两点间的距离时,使用的是球面距离,而非欧氏距离
相似的,分水岭算法中用到的测地距离,是三维的,即[x,y,h]
测地距离计算方法为:两点间沿着三维表面的曲面走的最短路径
1.2 固定图像二值化:cv2.threshold函数解析
retval, dst = cv2.threshold(src, thresh, maxval, type[, dst])
retval, dst分别表示二值化灰度阈值和二值化后的图像数据
scr:图像数据
thresh:自定义阈值
maxval:最大值,像素超过了阈值,所赋予的值
type:可选择的算法类型
例子
超过阈值的设为maxval,其他为0:ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
超过阈值的设为0,其他未maxval:ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
大于阈值部分设为阈值,其他不变:ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
低于阈值的设置为0,其他保持不变:ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
低于阈值的设置为maxval,其他保持不变ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
1.3 自适应二值化:cv2.adaptiveThreshold
dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, Block Size, C)
thresh_type:
cv2.ADAPTIVE_THRESH_MEAN_C:计算均值时每个像素的权值是相等的
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:计算均值时每个像素的权值根据其到中心点的距离通过高斯方程得到
type:计算均值后,即生成阈值,而后采取固定图像二值化方法
block size:图片分块的大小
C:阈值计算中的所加减的常数项
1.4 图像形态学
原理介绍:需要在二值化后的图像中进行。相当于对图像进行池化操作,膨胀相当于最大池,图像的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更大;腐蚀相当于最小池,将图像中的高亮区域或白色部分进行缩减细化,其运行结果图比原图的高亮区域更小。
卷积核锚点(中心点)值被最亮/暗像素值替换
图像膨胀
dst = cv2.dilate(src, kernel, iterations)
kernel:卷积核,n*n维矩阵
interations:迭代次数
作用:试图找到连通分支(具有相似颜色或强度的像素点的大块互相分离的区域)。因为多数情况下,一个大区域可能被噪声、阴影等分割成多个部分
图像腐蚀
dst = cv2.erode(src, kernel, iterations)
作用:消除图像中“斑点”噪声,且能确保图像内较大区域依然存在
创建核的方法
使用numpy构建结构化元素,都是正方形的核。
np.ones((5,5), np.unit8)
如果要构建圆形或者椭圆形的核,可以使用cv2.getStructuringElement()函数
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
MORPH_RECT:矩形
MORPH_CROSS:交叉十字
MORPH_ELLIPSE:椭圆
(n,n):代表卷积核尺寸
更加通用的形态学
opening = cv2.morphologyEx(data, type, kernel, iterations)

开运算

先腐蚀再膨胀:向上的孤立点被消除,去除小的明亮区域,并且剩余的明亮区域被隔绝,但大小不变
type:cv2.MORPH_OPEN
闭运算

先膨胀后腐蚀:消除低亮度值的孤立点,亮的区域合在一起,但他们的基本大小不变
type:cv2.MORPH_CLOSE
形态学梯度

膨胀后的图像-腐蚀后的图像
可以突出边缘
type:cv2.MORPH_GRADIENT
礼帽和黑帽

礼帽:原图-开运算后的图像
作用:突出比原图中周围区域更明亮的部分,与核的大小相关
黑帽:原图-闭运算后的图像
作用:突出比原图中周围区域更暗的部分,与核的大小相关
2 算法流程
把梯度图像中的所有像素按照灰度值分类,并设定一个测地距离阈值。
找到灰度值最小的像素点(默认标记为灰度值最低点),让threshold从最小值开始增长,这些点为起始点。
水平面在增长的过程中,会碰到周围的邻域像素,测量这些像素到起始点(灰度值最低点)的测地距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。
思考:这个阈值应该如何设定?若设定偏低,则会出现较多杂乱的边缘线,若设定偏高,则往往“防洪”效果不好。
3 opencv实例操作
3.1 导入相关库并读取数据
import numpy as np
import matplotlib.pyplot as plt
import cv2
import os
import pandas as pd

path = r''
origin = cv2.imread(path)
1
2
3
4
5
6
7
8


3.2 图像预处理
(一) 转化为灰度图片,并进行二值化处理
gray = cv2.cvtColor(origin, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
1
2
3


(二) 去除杂点:三次膨胀+两次腐蚀+一次膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
opening1 = cv2.dilate(binary, kernel, iterations = 3)
opening2 = cv2.erode(opening1, kernel, iterations = 2)
opening3 = cv2.dilate(opening2, kernel, iterations=1)
1
2
3
4
5


3.3 确定前景和背景和未知区域
下面是我自己的理解啦
前景:确定属于目标的部分
背景:一定包含全部目标的部分,背景包含前景
未知区域:背景-前景,因此包含边缘线
(一) 确定前景
sure_bg = cv2.dilate(opening3, kernel, iterations = 3) # 通过膨胀获取背景区域
1
2


(二)确定背景
dist = cv2.distanceTransform(opening3, cv2.DIST_L2, 5) # 通过距离变换获取前景区域
ret, sure_fg = cv2.threshold(dist, dist.max()*0.45, 255, cv2.THRESH_BINARY) # 0.45根据实际情况来调
1
2
3


(三)确定未知区域
surface_fg = np.uint8(sure_fg) # 背景空间为整型空间,前景为浮点型空间,这里做一下统一
unknown = cv2.subtract(sure_bg, surface_fg)
plt.imshow(unknown, cmap = plt.cm.gray)
1
2
3
4


3.4 创建markers并实现watershed
cv2.watershed函数需要将包含边缘的未知区域设置为0
ret, markers = cv2.connectedComponents(surface_fg) # 所有的前景区域非0
markers = markers + 1 # 此时所有的区域非零,其中包含边缘的未知区域和非背景区域为1
markers[unknown == 255] = 0 # 令包含边缘的位置区域为0

# 注:watershed会将找到的栅栏在markers中设置为-1

markers = cv2.watershed(origin, markers = markers) # 获取栅栏
origin[markers == -1] = [0,0,255] # 根据栅栏,我们对原图像进行操作,对栅栏区域设置为红色
1
2
3
4
5
6
7
8


分水岭算法的简单应用就先到这里啦,想要得到更精细的“水坝线”,还需要自己多多调试
————————————————
版权声明:本文为CSDN博主「Evonne_H」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Evonnehyf/article/details/104066799

标签:阈值,区域,cv2,像素,算法,理解,灰度,图像,分水岭
From: https://www.cnblogs.com/bruce1992/p/17375390.html

相关文章

  • MFC-透明度算法
           ......
  • Python自动寻路算法
    一、题目描述在一个迷宫游戏里,有一些小怪物要去攻击主角,现在希望给这些小怪物加上聪明的AI,让他们可以自动绕过迷宫中的障碍物,寻找到主角所在。二、解题思路迷宫游戏里的场景通常都是由小方格组成。假设我们有一个7*5大小的迷宫,图中红色格子是终点,绿色格子是起点,蓝色格子是一堵墙......
  • 架构师日记-深入理解软件设计模式
    作者:京东零售刘慧卿一设计模式与编程语言1.1什么是设计模式设计模式(Designpattern):由软件开发人员在软件开发中面临常见问题的解决方案,是经过长时间的试验积累总结出来的,它使设计更加灵活和优雅,复用性更好。从实用的角度来看,它代表了某一类问题的最佳实践。设计模式到底解......
  • 迪杰斯特拉算法
    输入可能是边以及权值,将其保存在邻接表之后转为使用邻接矩阵来进行存储。然后需要一个数组来存放从起点到所有点的距离的数组dist,需要一个visited数组来表示是否以访问。算法流程:首先初始化起点到各点的初始距离选择其中最短的一个距离对应的顶点,并且要求该点未被访问......
  • OTSU阈值分割算法
    阈值分割算法二值化首先以灰度图的\(x,y\)坐标为二维坐标系的\(x,y\)坐标,以对应位置的像素灰度值为\(z\)坐标,建立灰度图的三维坐标系,如下图二值化处理就是在对应\(0-255\)范围内找出合适阈值筛选出对我们有用的信息。如果把上图当作一个地形图,阈值分割就是找出合适的水位去淹......
  • C#处理医学影像(四):基于Stitcher算法拼接人体全景脊柱骨骼影像
    在拍摄脊柱或胸片时,经常会遇到因设备高度不够需要分段拍摄的情况,对于影像科诊断查阅影像时希望将分段影像合并成一张影像,有助于更直观的观察病灶,以下图为例的两个分段影像:   我们使用OpenCVSharp中的Stitcher类的Stitch方法,导入两张图像并拼接: 但结果却失败了,返回错误......
  • 从源码深入理解读写锁(golang-RWMutex)
    环境:go1.19.8在读多写少的情况下,即使一段时间内没有写操作,大量并发的读访问也不得不在Mutex的保护下变成串行访问,这种情况下,使用Mutex,对性能影响比较大。所以就要区分读写操作。如果某个读操作的g持有了锁,其他读操作的g就不必等待了,可以并发的访问共享变量,这样就可以将串行的......
  • 一些算法1
    //Seehttps://aka.ms/new-console-templateformoreinformationint[]nums={0,1,1,2,3,4,5};int[]stockes={8,5,6,54,5,6,7,8};int[]b={2,232,4,5,6,8};int[]c={1,2,3,4,5,6,9};varx=newList<A>{};x.Add(null);x.Add(newA{Name="AAAA&quo......
  • m基于遗传优化的时域声辐射模态的振动控制算法的matlab仿真
    1.算法仿真效果matlab2013b仿真结果如下:         2.算法涉及理论知识概要2.1遗传优化        长度为L的n个二进制串bi(i=1,2,…,n)组成了遗传算法的初解群,也称为初始群体。在每个串中,每个二进制位就是个体染色体的基因。根据进化术语,对群体执......
  • ds:顺序表删除重复元素的算法
    算法思想:1.遍历顺序表、移动元素(把未匹配到目标数据的元素前移i-k个位置)intk=0;inti=0;k用来计数,i用来扫描顺序表。当匹配到目标元素时k++,未匹配到目标元素时就i++遍历,并且要将未匹配到的元素前移i-k个位置。2.修改顺序表的length为length-k 例:删除顺序表中值为x的所有......