一文概述用 python 的 scikit-image 模块进行图像分割

一文概述用 python 的 scikit-image 模块进行图像分割

雷锋网

发布时间:19-02-1910:40深圳英鹏信息技术股份有限公司

雷锋网 AI 科技评论按,随着人工智能技术的逐年火热,越来越多的人投入到计算机视觉领域的相关研究中。而图像分割是图像处理中非常重要的一个步骤,它是把图像分成若干个特定的、具有独特性质的区域,并提取出感兴趣目标的技术。

近日,工程师 Parul Pandey 发表了一篇博文,在博文中,她介绍了用 python 的 scikit-image 库进行图像分割的方法。具体涉及 scikit-image 的安装,图像导入以及用监督算法和无监督算法进行图像分割的方法。雷锋网 AI 科技评论编译整理如下。

fd039245d688d43f691fc06365ceb71f0cf43bc5.jpeg?token=491643ea2d38d53d453f79b72536d825&s=90B450DE561235DEF8AFEBBE0300901Fuploading.4e448015.gif正在上传…重新上传取消

迟早有一天,所有的一切都是数字,包括图像。

看过《终结者》的人肯定会认为这是那个时代最伟大的科幻电影。在这部电影中,James Cameron 引入了一个有趣的视觉效果概念,它可以使观众有可能躲在被称为终结者的电子人的眼睛后面。这种效应被称为「终结者视觉」,在某种程度上,它将人与背景分割开来。在当时,这听起来完全是天方夜谭,但在如今,图像分割已经成为了许多图像处理技术的重要组成部分。

图像分割

我们都很清楚,Photoshop 或类似的图形编辑器提供了无限的可能性,可以将一个人从一张图片中带到另一张图片中。然而,要这样做,首先需要确定那个人在源图像中的位置,这就需要用到图像分割技术了。有许多库是为图像分析而编写的。在本文中,我们将详细讨论基于 python 的图像处理库 scikit-image。

完整的代码也可以从与本文关联的 Github 存储库中访问。

Scikit-image

ac345982b2b7d0a21273e419d33f130d49369ad4.png?token=8b31a5a4397cdcd1dd7ee5f3c80f9d37&s=71167E9ACDA46E1352F5C9D403005033uploading.4e448015.gif转存失败重新上传取消

 

SciKit Image 是一个专门用于图像处理的 python 包。

安装

可以按如下方式安装 scikit-image:

pip install -U scikit-image(Linux and OSX)pip install scikit-image(Windows)# For Conda-based distributionsconda install scikit-image

python 中的图像处理概述

在使用图像分割技术之前,有必要先了解 scikit image 以及它是如何处理图像的。

从 skimage 库导入灰度图像

skimage 数据模块包含一些内置示例数据集,这些数据集通常以 jpeg 或 png 格式存储。

from skimage import dataimport numpy as npimport matplotlib.pyplot as pltimage = data.binary_blobs()plt.imshow(image, cmap='gray')

94cad1c8a786c917e50fc49fd0ed15cb3ac75758.png?token=1322bf081e0cf48e4714e53146be7ce5&s=4BE43A62DEF227B340946D130000C091uploading.4e448015.gif转存失败重新上传取消

从 skimage 库导入彩色图像

from skimage import dataimport numpy as npimport matplotlib.pyplot as pltimage = data.astronaut()plt.imshow(image)

b999a9014c086e06df5fd49b18d81ef008d1cb44.png?token=ecf47c99cb303b9a09462c82a13b7f4a&s=0740D20646623DBF1E17DDA403000015uploading.4e448015.gif转存失败重新上传取消

从外部源导入图像

# The I/O module is used for importing the imagefrom skimage import dataimport numpy as npimport matplotlib.pyplot as pltfrom skimage import ioimage = io.imread('skimage_logo.png')plt.imshow(image);

472309f7905298226e11a8f3ce1a1ecf0a46d430.png?token=949fb81581cef51154eb82b38eda97e1&s=21167A968E8C9D0152F5855E03001033uploading.4e448015.gif转存失败重新上传取消

加载多个图像

images = io.ImageCollection('../images/*.png:../images/*.jpg')print('Type:', type(images))images.filesOut[]: Type: <class 『skimage.io.collection.ImageCollection』>

保存图像

#Saving file as 'logo.png'io.imsave('logo.png', logo)

图像分割

现在我们已经了解了 scikit-image,接下来让我们来详细了解图像分割。图像分割本质上是将数字图像分割成多个片段的过程,以简化或将图像的表示方式更改为更有意义和更易于分析的内容。

在本文中,我们结合监督算法和无监督算法来处理分割过程。

50da81cb39dbb6fd68fcf1b912f4ce1c952b37d9.png?token=a2952645e437627f0b876a771f5702df&s=494532669B77209C1DE48414030050D3uploading.4e448015.gif转存失败重新上传取消

scikit-image 库中可用的一些分割算法

监督分割算法:一些可能来自人类输入的先验知识被用来指导算法。

无监督分割算法:不需要先验知识。这些算法试图将图像自动细分到有意义的区域。用户仍然可以通过调整某些设置以获得想要的输出。

让我们从最简单的阈值分割算法开始吧。

阈值算法

通过选择高于或低于某个阈值的像素,将对象从从背景中分割出来是最简单的方法。在北京分割中,这通常是一个非常有用的方法。了解更多可以查看:http://scikit-image.org/docs/dev/auto_examples/xx_applications/plot_thresholding.html

让我们在 scikit-image 数据集的一张教科书图像上试试这个。

基本输入

import numpy as npimport matplotlib.pyplot as pltimport skimage.data as dataimport skimage.segmentation as segimport skimage.filters as filtersimport skimage.draw as drawimport skimage.color as color

绘制图像的简单函数:

defimage_show(image, nrows=1, ncols=1, cmap='gray'):fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(14, 14))ax.imshow(image, cmap='gray')ax.axis('off')return fig, ax

图像

text = data.page()image_show(text)

5d6034a85edf8db108ca148910f3b850544e744f.png?token=a5de82fc289f442ac74d560666d6e091&s=8CE27221185C44CA8E3DA8D6010080B2uploading.4e448015.gif转存失败重新上传取消

这个图像有点暗,但我们仍然可以选择一个值,它可以合理的分割图像,而不需要用到任何先进的算法。为了得到这个分割阈值,我们将使用直方图。

直方图是一种显示图像中不同强度值的像素数的图。简单地说,直方图是一个图表,其中 X 轴显示图像中的所有像素值,而 Y 轴显示这些值的频率。

fig, ax = plt.subplots(1, 1)ax.hist(text.ravel(), bins=32, range=[0, 256])ax.set_xlim(0, 256);

c8ea15ce36d3d539021d130522578c54342ab02c.png?token=bb937fb8f0532a7cbd0eb6ab5dbfe42a&s=4B243A624AD8F00B59DCCDC3020090B9uploading.4e448015.gif转存失败重新上传取消

我们的示例恰好是一张 8-bit 图像,因此在 X 轴上总共有 256 个可能的值。在图像中,0 表示黑色,255 表示白色,我们观察到有些像素值很集中。这很可能是由于我们的文本背景比较淡,而其他部分则有点模糊不清。一个理想的分割直方图应该是有两个峰值,且两个峰值隔的较远,以便我们可以选择在这两个峰值中间选择一个数字作为阈值。现在,让我们试着根据简单的阈值法来分割图像。

有监督阈值

因为阈值是我们自己选择的,所以我们称之为监督阈值。

text_segmented = text > (value concluded from histogram i.e 50,70,120 )image_show(text_segmented);

e850352ac65c1038ef64dc7fabc1f617b17e894d.png?token=437224e3e06ca3402529357d4f3a2f0c&s=2AAC7A2289CF44C80E5DA1DE000080B1uploading.4e448015.gif转存失败重新上传取消

文本>50

dc54564e9258d109951861a6cc88a9bb6d814d7b.png?token=572c677d9d098918d64bf22d69f5f40c&s=2FAC7A2291CE44E81E7DA0DE000080B0uploading.4e448015.gif转存失败重新上传取消

文本>70

09fa513d269759ee55801c44af2b26126f22df45.png?token=8f670a78c52584de7d0925a2339d051f&s=29E47A2289DC45E90E7DA0DE000080B6uploading.4e448015.gif转存失败重新上传取消

文本>120

我们没有得到理想的结果,因为左边的阴影会造成问题,接下来让我们尝试无监督的阈值。

无监督阈值

scikit-image 有许多自动阈值设定方法,在选择最佳阈值时不需要手动输入。其中常用的方法有 otsu, li, local 等等。

text_threshold = filters.threshold_ # Hit tab with the cursor after the underscore to get all the methods.image_show(text < text_threshold);

86d6277f9e2f07082d608aa6f0f4dd9da801f207.png?token=0afb852bc04eff58dc9044e35d3e3a2e&s=69E03A625AD445EB9E7CA9D2000080B6uploading.4e448015.gif转存失败重新上传取消

otsu 算法分割效果图

0b7b02087bf40ad15f4e97eb4afc74dba8ecce60.png?token=38464c514e4bcc0ad4afe0ad34c279e0&s=69E43A62DADC45EB9E7DA1D2000080B6uploading.4e448015.gif转存失败重新上传取消

li 算法分割效果图

在 local 算法中,我们还需要指定 block 的大小。offset 有助于调整图像,以获得更好的效果。

text_threshold = filters.threshold_local(text,block_size=51, offset=10)image_show(text > text_threshold);

a08b87d6277f9e2f5d70167105e08c20b999f352.png?token=5d75eac830a8c8f919b8efeccd68f150&s=0AE87A22C8DC45EB1E7DA0DE000080B0uploading.4e448015.gif转存失败重新上传取消

local 阈值法分割效果图

这是一种很好的方法,它在很大程度上消除了噪声。

监督分割

阈值分割是一个非常基本的分割方法,但是它在高对比度图像中效果不是很好,因此我们需要采用更加先进的算法。

在本节中,我们将使用一个免费的示例图像,并尝试使用监督分割技术分割图像中人的头部。

# import the imagefrom skimage import ioimage = io.imread('girl.jpg')plt.imshow(image);

9358d109b3de9c82c24edb217451e50e18d8434c.png?token=17684fa128140146ac05595cdae65659&s=6E2012626C794409406475DA0300C0B3uploading.4e448015.gif转存失败重新上传取消

源图像

小 tip:在对图像进行任何分割之前,最好使用一些滤波器对其进行去噪。

但是,在我们的例子中,图像中的噪声很小,因此我们直接对其进行处理。接下来我们将要做的是使用 rgb2gray 将图像转换成灰度图。

image_gray = color.rgb2gray(image)image_show(image_gray);

c8ea15ce36d3d539159a08c21a578c54342ab064.png?token=9d4a05945472330051a939241f8f5fe4&s=7F2A32626A1B40494475F5DA0100C0B1uploading.4e448015.gif转存失败重新上传取消

我们将使用两种原理完全不同的分割方法。

活动轮廓分割(Active Contour segmentation)

活动轮廓分割使用用户定义的轮廓或线在感兴趣的区域周围进行初始化,然后该轮廓慢慢收缩。

对于我们的示例图像,让我们围绕人的头部画一个圈来初始化轮廓。

def circle_points(resolution, center, radius):"""Generate points which define a circle on an image.Centre refers to the centre of the circle"""radians = np.linspace(0, 2*np.pi, resolution)c = center[1] + radius*np.cos(radians)#polar co-ordinatesr = center[0] + radius*np.sin(radians)return np.array([c, r]).T# Exclude last point because a closed path should not have duplicate pointspoints = circle_points(200, [80, 250], 80)[:-1]

上面对圆环边缘点的 x 坐标和 y 坐标进行了计算。我们设置分辨率值的为 200,那么将计算 200 个这样的点。

fig, ax = image_show(image)ax.plot(points[:, 0], points[:, 1], '--r', lw=3)

bd315c6034a85edf1c66457c50846c27df5475df.png?token=5935550fd5047393e30974c4012abfda&s=3E2252236A0F404D4064F5DA0300C0B3uploading.4e448015.gif转存失败重新上传取消

然后,该算法通过将闭合曲线拟合到人脸的边缘,将人脸与图像的其余部分分割开来。

snake = seg.active_contour(image_gray, points)fig, ax = image_show(image)ax.plot(points[:, 0], points[:, 1], '--r', lw=3)ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3);

738b4710b912c8fca42820ffe6d3f741d7882179.png?token=07636f98c87f22992ecd1955db9e818e&s=3E225223420F414D4064FDDE0300C0B3uploading.4e448015.gif转存失败重新上传取消

我们可以调整参数 alpha 和 beta。alpha 值越高,轮廓的收缩速度越快,而 beta 越大收缩越缓慢。

snake = seg.active_contour(image_gray, points,alpha=0.06,beta=0.3)fig, ax = image_show(image)ax.plot(points[:, 0], points[:, 1], '--r', lw=3)ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3);

a2cc7cd98d1001e916a0ef78a1de1ee855e79779.png?token=541f45a2d05298001c1cbc45f2af0600&s=3E2252236A0F414D4064FDCE0300D0B3uploading.4e448015.gif转存失败重新上传取消

随机 walker 分割

在这种方法中,用户以交互方式标记少量的像素,这些像素称为标签。然后假设每个未标记的像素释放一个随机 walker,然后可以确定随机 walker 从每个未标记像素开始到达一个预标记像素的概率。通过将每个像素分配给计算出来的概率值最大的标签,可以获得高质量的分割图像。

更多相关资料可以阅读参考文献:https://ieeexplore.ieee.org/document/1704833。

我们将在这里重新使用前面示例中的种子值。为了简单起见,让我们继续使用圆。

image_labels = np.zeros(image_gray.shape, dtype=np.uint8)

随机 Walker 算法需要一个标签图像作为输入。所以我们会有一个更大的圆,它包围了人的整个脸,还有一个靠近脸中间的小圆。

indices = draw.circle_perimeter(80, 250,20)#from hereimage_labels[indices] = 1image_labels[points[:, 1].astype(np.int), points[:, 0].astype(np.int)] = 2image_show(image_labels);

71cf3bc79f3df8dc50dc0745d2c1178f45102851.png?token=7e8b7bd2d0b6a35411bd33ea6632360a&s=6B61736E7BA4B3784C719C0F0000E0C1uploading.4e448015.gif转存失败重新上传取消

现在,让我们使用随机 walker,并观察发生了什么。

image_segmented = seg.random_walker(image_gray, image_labels)# Check our resultsfig, ax = image_show(image_gray)ax.imshow(image_segmented == 1, alpha=0.3);

cefc1e178a82b9012486e305685dcc733912ef35.png?token=e3b5b54206655da32f173224ac98eef2&s=9F821263620B61685CA577DA0300C096uploading.4e448015.gif转存失败重新上传取消

它并没有如我们所预期的那样描绘出脸的边缘。为了解决这个问题,我们可以调整 beta 参数,直到得到所需的结果。经过几次尝试后,可以得到,当 beta 值为 3000 时,分割效果不错。

image_segmented = seg.random_walker(image_gray, image_labels, beta = 3000)# Check our resultsfig, ax = image_show(image_gray)ax.imshow(image_segmented == 1, alpha=0.3);

f31fbe096b63f6249221dcd19e948efc1b4ca33d.png?token=92dea6ddd65ca9d6b2211bbe7abd9f6e&s=9F821263721B416854A577DA0300C096uploading.4e448015.gif转存失败重新上传取消

以上就是监督分割,在这种算法中,我们必须提供某些输入,也必须调整某些参数。然而,我们不可能总是让人先看一张图像,然后再决定输入什么或者从哪里开始。幸运的是,对于这种情况,我们可以采用无监督分割技术。

无监督分割

无监督分割不需要事先了解图像。在一张图像太大的情况下,同时考虑所有像素是不可能的。因此,在这种情况下,无监督分割可以将图像分解为几个子区域,你可以使用数十到数百个区域来代替数百万像素。下面是两个无监督分割算法:

SLIC(简单线性迭代聚类)

SLIC 算法实际上使用了一种叫做 k-means 的机器学习算法。它接收图像的所有像素值,并尝试将它们分离到给定数量的子区域中。

更多相关内容可以阅读相关资料:https://ieeexplore.ieee.org/document/6205760。

SLIC 是处理彩色图像的,所以我们将使用原始图像。

image_slic = seg.slic(image,n_segments=155)

我们所做的只是将图像的每个子图像或子区域像素设置为该区域像素的平均值。

# label2rgb replaces each discrete label with the average interior colorimage_show(color.label2rgb(image_slic, image, kind='avg'));

6a600c338744ebf83204f7c2c129b22e6159a72e.png?token=7be1d0e2b61dc70365f333d4241f833c&s=3E225223627F40284044F5DA0300C0B3uploading.4e448015.gif转存失败重新上传取消

我们已经将此图像从 512*512=262000 个像素减少到 155 个区域。

Felzenszwalb 算法

该算法也使用了一种机器学习算法,即最小生成树聚类算法。Felzenszwaib 算法并没有告诉我们图像将被分割成多少个集群。它将运行并生成尽可能多的适合它的集群。相关的参考文件可以在这里查阅。

image_felzenszwalb = seg.felzenszwalb(image)image_show(image_felzenszwalb);

b21c8701a18b87d63207e0431ad84d3c1e30fd7d.png?token=f567ce6559c430c171683026db16a5ad&s=CCC27A23E1FE012C6E15D48E0100C091uploading.4e448015.gif转存失败重新上传取消

有很多区域,我们计算相互独立的区域数。

np.unique(image_felzenszwalb).size3368

现在让我们使用区域像素平均值对它们重新着色,就像我们在 SLIC 算法中所做的那样。

image_felzenszwalb_colored = color.label2rgb(image_felzenszwalb, image, kind='avg')image_show(image_felzenszwalb_colored);

现在我们将图像分成了合适的小区域。如果我们想要将图像分成更少的区域,可以更改比例参数或者继续组合它们。这种方法有时被称为过度分割。

8601a18b87d6277f4b92c53332e87a34e824fc0a.png?token=9891748325af7f9872265fe8af38779f&s=3E225221623F40294064F5DA0300C0B3uploading.4e448015.gif转存失败重新上传取消

这看起来更像是一个拆分后的图像,其本质上只是减少了颜色的数量。要再次组合它们,可以使用区域邻接图(RAG),但这超出了本文的范围。

结论

图像分割是图像处理中非常重要的一个步骤。它是一个热门的研究领域,应用非常广泛,从计算机视觉到医学图像、从交通和视频监控等领域都有涉及。Python scikit-image 提供了一个非常强大的库,该库具有大量用于图像处理的算法。它是免费的,没有任何限制,在其背后有一个活跃的社区。你可以查看他们的文档,了解关于库及其用例的更多信息。

via:https://towardsdatascience.com/image-segmentation-using-pythons-scikit-image-module-533a61ecc980

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您可以通过以下步骤安装scikit-image: 1. 打开命令行窗口或终端。 2. 输入以下命令安装pip(如果您已经安装了pip,请跳过此步骤): ``` python -m ensurepip --default-pip ``` 3. 输入以下命令安装scikit-image: ``` pip install -U scikit-image ``` 4. 等待安装完成即可。 ### 回答2: scikit-image是一款Python图像处理库,它能够为我们提供各种各样的图像处理和计算机视觉相关的功能,如图像滤波、变换、分割、特征提取等。scikit-image库底层依赖于NumPy、SciPy和matplotlib等Python科学计算库,因此在安装scikit-image之前,需要确保NumPy、SciPy和matplotlib等库已经安装成功。 下面介绍安装scikit-image的具体步骤: 1.安装Python环境 在安装scikit-image之前,需要先安装Python环境。可以从Python官网(https://www.python.org/)下载对应版本的Python安装包,按照安装向导依次安装即可。 2.安装pip pip是用来安装Python第三方库的包管理工具,可以通过在终端中输入以下命令来安装pip: python get-pip.py 其中get-pip.py是pip的安装文件,可以从官方网站(https://bootstrap.pypa.io/get-pip.py)下载。 3.安装依赖库 由于scikit-image依赖于NumPy、SciPy、matplotlib等库,因此在安装scikit-image之前,需要先安装这些依赖库。可以在终端中输入以下命令来安装: pip install numpy scipy matplotlib 4.安装scikit-image 安装依赖库之后,就可以安装scikit-image了。可以在终端中输入以下命令来安装: pip install scikit-image 安装完成后,可以在Python中导入scikit-image库,如下: import skimage 需要注意的是,由于scikit-image底层是用Cython编写的,因此在安装scikit-image时,需要确保Cython已经安装,否则会出现安装失败的情况。可以在终端中输入以下命令来安装Cython: pip install cython ### 回答3: scikit-image是针对影像处理而设计的Python包。它提供了一整套基于numpy的图像处理和计算机视觉算法,同时该包采用了sklearn、scipy和matplotlib等外部包来实现。这样就使得它在实现特定任务时可以充分利用其他包的强大功能,降低了实现成本。Python标准库中包含的图像处理模块(如pillow)功能较为简单,适合处理基本的图像问题,而scikit-image则具有更为广泛的应用,因为它可以完成更加复杂的图像操作。本篇文章将向你介绍如何在Python中安装scikit-imagescikit-image的安装有两种方式: 方法一: 第一步:安装Python,可以到官网(https://www.python.org/downloads/)下载Python3.6+版本的安装文件。 第二步:安装pip,可以到Python官网下方找到get-pip.py文件,运行该文件即可安装pip。 命令:python get-pip.py 第三步:安装依赖的库 scikit-image依赖于其他的库,需要先安装这些库,命令如下: numpy安装:pip install numpy scipy安装:pip install scipy matplotlib安装:pip install matplotlib imageio安装:pip install imageio 第四步:安装scikit-image库 pip install scikit-image 这样就成功完成了scikit-image库的安装。 方法二: 直接利用Anaconda进行安装: Anaconda是一个比较完整的数据科学和机器学习环境,内置了诸多包。这样的话就不需要再单独安装numpy、scipy、matplotlib、imageio等库了。可以直接打开Anaconda Navigator,选择Environment Tab,然后创建一个新的Python环境。 在这个新的Python环境中安装scikit-image: 打开Anaconda Prompt,输入命令: conda install -c conda-forge scikit-image 等待安装完成即可。 总结: 以上就是在Python中安装scikit-image的两种方法,它们都可以用来完成scikit-image的安装。如果你已经安装了Anaconda,那么采用第二种方法可以更为方便。无论选择哪种方法,需要注意的是依赖库的安装很重要,否则导入scikit-image会出现问题。在使用之前可以先简单的测试一下,如果无法导入,可以使用Anaconda Prompt中的命令进行检查。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值