Python 深入了解opencv图像分割算法

  • 使用 OpenCV 函数 cv::filter2D 执行一些拉普拉斯滤波以进行图像锐化
  • 使用 OpenCV 函数 cv::distanceTransform 以获得二值图像的派生(derived)表示,其中每个像素的值被替换为其到最近背景像素的距离
  • 使用 OpenCV 函数 cv::watershed 将图像中的对象与背景隔离

加载源图像并检查它是否加载没有任何问题,然后显示它:

# Load the image
parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\
    Sample code showing how to segment overlapping objects using Laplacian filtering, \
    in addition to Watershed and Distance Transformation')
parser.add_argument('--input', help='Path to input image.', default='cards.png')
args = parser.parse_args()
src = cv.imread(cv.samples.findFile(args.input))
if src is None:
    print('Could not open or find the image:', args.input)
    exit(0)
# Show source image
cv.imshow('Source Image', src)

原图

将背景从白色更改为黑色,因为这将有助于稍后在使用距离变换(Distance Transform)期间提取更好的结果

src[np.all(src == 255, axis=2)] = 0

如果不太理解numpy.all的的用法,可以参考这里

之后,我们将锐化(sharpen)我们的图像,以锐化前景对象(the foreground objects)的边缘。 我们将应用具有相当强过滤器的拉普拉斯(laplacian)过滤器(二阶导数的近似值):

# 创建一个内核,我们将用它来锐化我们的图像
# 一个二阶导数的近似值,一个非常强大的内核
kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32)
# do the laplacian filtering as it is
# well, we need to convert everything in something more deeper then CV_8U
# because the kernel has some negative values,
# and we can expect in general to have a Laplacian image with negative values
# BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
# so the possible negative number will be truncated
imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel)
sharp = np.float32(src)
imgResult = sharp - imgLaplacian
# convert back to 8bits gray scale
imgResult = np.clip(imgResult, 0, 255)
imgResult = imgResult.astype('uint8')
imgLaplacian = np.clip(imgLaplacian, 0, 255)
imgLaplacian = np.uint8(imgLaplacian)
#cv.imshow('Laplace Filtered Image', imgLaplacian)
cv.imshow('New Sharped Image', imgResult)

锐化处理的主要目的是突出灰度的过度部分。由于拉普拉斯是一种微分算子,如果所使用的定义具有负的中心系数,那么必须将原图像减去经拉普拉斯变换后的图像,而不是加上它,从而得到锐化结果。----摘自《数字图像处理(第三版)》

现在我们将新的锐化源图像分别转换为灰度和二值图像(binary):

# Create binary image from source image
bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY)
_, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow('Binary Image', bw)

我们现在准备在二值图像(binary image)上应用距离变换。 此外,我们对输出图像进行归一化,以便能够对结果进行可视化和阈值处理:

# Perform the distance transform algorithm
dist = cv.distanceTransform(bw, cv.DIST_L2, 3)
# 对范围 = {0.0, 1.0} 的距离图像(the distance image)进行归一化(Normalize),
# 以便我们可以对其进行可视化和阈值处理
cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX)
cv.imshow('Distance Transform Image', dist)

distanceTransform用法

cv.distanceTransform( src, distanceType, maskSize[, dst[, dstType]] )
src:输入图像,数据类型为CV_8U的单通道图像
dst: 输出图像,与输入图像具有相同的尺寸,数据类型为CV_8U或者CV_32F的单通道图像。
distanceType:选择计算两个像素之间距离方法的标志,其常用的距离度量方法, DIST_L1(distance = |x1-x2| + |y1-y2| 街区距离), DIST_L2 (Euclidean distance 欧几里得距离,欧式距离) 。
maskSize:距离变换掩码矩阵的大小,参数可以选择的尺寸为DIST_MASK_3(3×3)和DIST_MASK_5(5×5).

我们对 dist 图像进行阈值处理,然后执行一些形态学操作(即膨胀)以从上述图像中提取峰值:

# Threshold to obtain the peaks
# This will be the markers for the foreground objects
_, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY)
# Dilate a bit the dist image
kernel1 = np.ones((3,3), dtype=np.uint8)
dist = cv.dilate(dist, kernel1)
cv.imshow('Peaks', dist)

从每个 blob 中,我们在 cv::findContours 函数的帮助下为分水岭算法创建一个种子/标记:

# Create the CV_8U version of the distance image
# It is needed for findContours()
dist_8u = dist.astype('uint8')
# Find total markers
contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# Create the marker image for the watershed algorithm
markers = np.zeros(dist.shape, dtype=np.int32)
# Draw the foreground markers
for i in range(len(contours)):
    cv.drawContours(markers, contours, i, (i+1), -1)
# Draw the background marker
cv.circle(markers, (5,5), 3, (255,255,255), -1)
markers_8u = (markers * 10).astype('uint8')
cv.imshow('Markers', markers_8u)

最后,我们可以应用分水岭算法,并将结果可视化:

# Perform the watershed algorithm
cv.watershed(imgResult, markers)
#mark = np.zeros(markers.shape, dtype=np.uint8)
mark = markers.astype('uint8')
mark = cv.bitwise_not(mark)
# uncomment this if you want to see how the mark
# image looks like at that point
#cv.imshow('Markers_v2', mark)
# Generate random colors
colors = []
for contour in contours:
    colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)))
# Create the result image
dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8)
# Fill labeled objects with random colors
for i in range(markers.shape[0]):
    for j in range(markers.shape[1]):
        index = markers[i,j]
        if index > 0 and index <= len(contours):
            dst[i,j,:] = colors[index-1]
# Visualize the final image
cv.imshow('Final Result', dst)

代码

基于机器学习的图像分割

Pixellib是一个用于对图像和视频中的对象进行分割的库。 它支持两种主要类型的图像分割:

1.语义分割
2.实例分割
PixelLib 支持两个用于图像分割的深度学习库,分别是 Pytorch 和 Tensorflow

以上就是Python 深入了解opencv图像分割算法的详细内容,更多关于Python的资料请关注我们其它相关文章!

(0)

相关推荐

  • python用opencv完成图像分割并进行目标物的提取

    运行平台: Windows Python版本: Python3.x IDE: Spyder 今天我们想实现的功能是对单个目标图片的提取如图所示: 图片读取 ###############头文件 import matplotlib.pyplot as plt import os import cv2 import numpy as np from PIL import Image #from skimage import io import random from PIL import Image

  • Python使用OpenCV和K-Means聚类对毕业照进行图像分割

    图像分割是将图像分割成多个不同区域(或片段)的过程.目标是将图像的表示变成更容易和更有意义的图像. 在这篇博客中,我们将看到一种图像分割方法,即K-Means Clustering. K-Means 聚类是一种无监督机器学习算法,旨在将N 个观测值划分为K 个聚类,其中每个观测值都属于具有最近均值的聚类.集群是指由于某些相似性而聚合在一起的数据点的集合.对于图像分割,这里的簇是不同的图像颜色. 我们使用的环境是pip install opencv-python numpy matplotlib

  • python+opencv图像分割实现分割不规则ROI区域方法汇总

    在图像分割领域,一个重要任务便是分割出感兴趣(ROI)区域.如果是简易的矩形ROI区域其实是非常容易分割的,opencv的官方python教程里也有教到最简易的矩形ROI分割(剪裁),其本质是多维数组(矩阵)的切片.但是现实情况中,ROI是不规则的多边形,也可能是曲线边界,那么该如何分割出来呢?下面总结几种思路. 可能只提供核心部分的代码示例,具体应用要结合你自己的项目来修正. 一.已知边界坐标,直接画出多边形 例:最基础的画个四边形 # 定义四个顶点坐标 pts = np.array([[10

  • Python 深入了解opencv图像分割算法

    使用 OpenCV 函数 cv::filter2D 执行一些拉普拉斯滤波以进行图像锐化 使用 OpenCV 函数 cv::distanceTransform 以获得二值图像的派生(derived)表示,其中每个像素的值被替换为其到最近背景像素的距离 使用 OpenCV 函数 cv::watershed 将图像中的对象与背景隔离 加载源图像并检查它是否加载没有任何问题,然后显示它: # Load the image parser = argparse.ArgumentParser(descript

  • python中的opencv 图像分割与提取

    目录 图像分割与提取 用分水岭算法实现图像分割与提取 算法原理 相关函数介绍 分水岭算法图像分割实例 交互式前景提取 图像分割与提取 图像中将前景对象作为目标图像分割或者提取出来.对背景本身并无兴趣分水岭算法及GrabCut算法对图像进行分割及提取. 用分水岭算法实现图像分割与提取 分水岭算法将图像形象地比喻为地理学上的地形表面,实现图像分割,该算法非常有效. 算法原理 任何一幅灰度图像,都可以被看作是地理学上的地形表面,灰度值高的区域可以被看成是山峰,灰度值低的区域可以被看成是山谷. 左图是原

  • 详解Python OpenCV图像分割算法的实现

    目录 前言 1.图像二值化 2.自适应阈值分割算法 3.Otsu阈值分割算法 4.基于轮廓的字符分离 4.1轮廓检测 4.2轮廓绘制 4.3包围框获取 4.4矩形绘制 前言 图像分割是指根据灰度.色彩.空间纹理.几何形状等特征把图像划分成若干个互不相交的区域. 最简单的图像分割就是将物体从背景中分割出来 1.图像二值化 cv2.threshold是opencv-python中的图像二值化方法,可以实现简单的分割功能. retval, dst = cv2.threshold(src, thresh

  • OpenCV图像分割中的分水岭算法原理与应用详解

    图像分割是按照一定的原则,将一幅图像分为若干个互不相交的小局域的过程,它是图像处理中最为基础的研究领域之一.目前有很多图像分割方法,其中分水岭算法是一种基于区域的图像分割算法,分水岭算法因实现方便,已经在医疗图像,模式识别等领域得到了广泛的应用. 1.传统分水岭算法基本原理 分水岭比较经典的计算方法是L.Vincent于1991年在PAMI上提出的[1].传统的分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一像素的灰度值表示该点的海

  • C++中实现OpenCV图像分割与分水岭算法

    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征. API介绍 void watershed( InputArray image, InputOutputArray markers ); 参数说明: image: 必须是一个8bit 3通道彩色图像矩阵序列 markers: 在执行分水岭函数watershed之前,必须对第二个参数markers

  • OpenCV图像分割之分水岭算法与图像金字塔算法详解

    目录 前言 一.使用分水岭算法分割图像 1.cv2.distanceTransform()函数 2.cv2.connectedComponents()函数 3.cv2.watershed()函数 二.图像金字塔 1.高斯金字塔向下采样 2.高斯金字塔向上采样 3.拉普拉斯金字塔 4.应用图像金字塔实现图像的分割和融合 前言 主要介绍OpenCV中的分水岭算法.图像金字塔对图像进行分割的方法. 一.使用分水岭算法分割图像 分水岭算法的基本原理为:将任意的灰度图像视为地形图表面,其中灰度值高的部分表

  • Opencv分水岭算法学习

    分水岭算法可以将图像中的边缘转化成"山脉",将均匀区域转化为"山谷",这样有助于分割目标. 分水岭算法是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中的每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭.分水岭的概念和形成可以通过模拟浸入过程来说明:在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响区域慢慢向外扩展,

  • python实现人脸识别经典算法(一) 特征脸法

    近来想要做一做人脸识别相关的内容,主要是想集成一个系统,看到opencv已经集成了三种性能较好的算法,但是还是想自己动手试一下,毕竟算法都比较初级. 操作环境:python2.7 第三方库:opencv for python.numpy 第一种比较经典的算法就是特征脸法,本质上其实就是PCA降维,这种算法的基本思路是,把二维的图像先灰度化,转化为一通道的图像,之后再把它首尾相接转化为一个列向量,假设图像大小是20*20的,那么这个向量就是400维,理论上讲组织成一个向量,就可以应用任何机器学习算

  • 使用python写的opencv实时监测和解析二维码和条形码

    今天,我实现了一个很有趣的demo,它可以在视频里找到并解析二维码,然后把解析的内容实时在屏幕上显示出来. 然后我们直入主题,首先你得确保你装了opencv,python,zbar等环境.然后这个教程对于学过opencv的人可能更好理解,但是没学过也无妨,到时候也可以直接用. 比如我的电脑上的环境是opencv2.4.x,python2.7,和最新的zbar,在Ubuntu 12.12的系统下运行的 假设你的opencv已经安装好了,那么我们就可以安装zbar 你可以先更新一下 sudo apt

随机推荐