介绍

在这篇文章中,我们将学习如何执行图像处理。在整篇文章中,我们使用到的库是Scikit Image。

基础知识

1、什么是图像?

图像数据可能是文本之后最常见的数据。那么,电脑如何理解你在埃菲尔铁塔前的自拍呢?

它使用一个称为像素的小正方形网格。像素覆盖一个小区域,并具有表示颜色的值。图像中的像素越多,其质量越高,存储所需的内存越多。

就是这样。图像处理主要是处理这些单独的像素(有时是像素组),以便计算机视觉算法可以从中提取更多信息。

2、NumPy和Skimage的图像基础

在Matplotlib和Skimage中,图像都作为NumPy ndarray加载。

from skimage.io import imread  # pip install scikit-imageimage = imread("images/colorful_scenery.jpg")>>> type(image)
numpy.ndarray

NumPy数组带来灵活性、速度和力量。图像处理也不例外。

Ndarrays可以轻松检索图像的一般详细信息,例如图像的尺寸:

>>> image.shape
(853, 1280, 3)>>> image.ndim
3# The number of pixels
>>> image.size  # 853 * 1280 * 3
3275520

我们的图像高度为853像素,宽度为1280像素。第三维表示RGB(红、绿、蓝)颜色通道的值。最常见的图像格式是3D。

你可以通过常规NumPy索引检索单个像素值。下面,我们尝试索引图像以检索三个颜色通道中的每一个通道:

red = image[:, :, 0]compare(image, red, "Red Channel of the Image", cmap_type="Reds_r")

green = image[:, :, 1]compare(image, green, "Green Channel of the Image", "Greens_r")

blue = image[:, :, 2]compare(image, blue, "Blue Channel of the Image", "Blues_r")

0表示红色,1表示绿色,2表示蓝色通道-非常简单。

创建了两个函数,show和compare,它们显示一个图像或并排显示其中两个进行比较。在整个教程中,我们将广泛使用这两个函数。

按照约定,ndarray的第三维用于颜色通道,但并不总是遵循此约定。Skimage通常提供参数来指定这种行为。

图像与通常的Matplotlib绘图不同。它们的原点不位于左下角,而是位于左上角的位置(0,0)。

>>> show(image, axis=True)

当我们在Matplotlib中绘制图像时,轴表示像素的顺序,但我们通常会隐藏它们。

3、常见转换

我们将要执行的最常见的图像转换是将彩色图像转换为灰度。许多图像处理算法需要灰度图像。因为颜色不是图片的定义特征,没有它,计算机仍然可以提取足够的信息。

from skimage.color import rgb2grayimage = imread("images/grayscale_example.jpg")
# Convert image to grayscale
gray = rgb2gray(image)compare(image, gray, "Grayscale Image")

>>> gray.shape(853, 1280)

当将图像转换为灰度时,它们会丢失其第三维度-颜色通道。相反,图像数组中的每个单元格现在表示uint8类型的整数。它们的范围从0到255,提供256种灰度。

你还可以使用np.flipud或者np.fliplr之类的NumPy函数,随心所欲地以任何方式操纵图像。

kitten = imread("images/horizontal_flip.jpg")
horizontal_flipped = np.fliplr(kitten)compare(kitten, horizontal_flipped, "Horizontally Flipped Image")

ball = imread("images/upside_down.jpg")vertically_flipped = np.flipud(ball)compare(ball, vertically_flipped, "Vertically Flipped Image")

在“颜色”模块中,你可以找到许多其他变换函数来处理图像中的颜色。

4、颜色通道直方图

有时,查看每个颜色通道的强度有助于了解颜色分布。我们可以通过切片每个颜色通道并绘制它们的直方图来实现这一点。以下是执行此操作的函数:

def plot_with_hist_channel(image, channel):channels = ["red", "green", "blue"]channel_idx = channels.index(channel)color = channels[channel_idx]extracted_channel = image[:, :, channel_idx]fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(18, 6))ax1.imshow(image)ax1.axis("off")ax2.hist(extracted_channel.ravel(), bins=256, color=color)ax2.set_title(f"{channels[channel_idx]} histogram")

除了Matplotlib的一些细节之外,你还应该注意hist函数的调用。提取颜色通道及其数组后,我们将其展平为1D数组,并将其传递给hist函数。

bin数量应该是256个,每个像素值对应一个-0表示黑色,255表示完全白色。

让我们使用彩色风景图像:

colorful_scenery = imread("images/colorful_scenery.jpg")plot_with_hist_channel(colorful_scenery, "red")

>>> plot_with_hist_channel(colorful_scenery, "green")

>>> plot_with_hist_channel(colorful_scenery, "blue")

还可以使用直方图在将图像转换为灰度后找出图像中的亮度:

gray_color_scenery = rgb2gray(colorful_scenery)plt.hist(gray_color_scenery.ravel(), bins=256);

大多数像素的值较低,因为景物图像较暗。

我们将在以下部分探讨直方图的更多应用。

过滤器

1、手动阈值

现在,我们来看看有趣的东西——过滤图像。我们将学习的第一个操作是阈值化。让我们加载一个示例图像:

stag = imread("images/binary_example.jpg")>>> show(stag)

阈值分割在图像分割、目标检测、边缘或轮廓提取等方面有着广泛的应用,它主要用于区分图像的背景和前景。

阈值处理在高对比度灰度图像上效果最好:

# Convert to graysacle
stag_gray = rgb2gray(stag)>>> show(stag_gray)

我们将从基本的手动阈值设置开始,然后转到自动阈值设置。

首先,我们查看灰度图像中所有像素的平均值:

>>> stag_gray.mean()0.20056262759859955

请注意,通过将所有灰度图像的值除以256,上述灰度图像的像素在0和1之间归一化。

我们得到的平均值为0.2,这为我们提供了可能要使用的阈值的初步想法。

现在,我们使用这个阈值来进行掩码操作。如果像素值低于阈值,否则其值将变为0-黑色或1-白色。换句话说,我们得到一个黑白二值图像:

# Set threshold
threshold = 0.35
# Binarize
binary_image = stag_gray > thresholdcompare(stag, binary_image, "Binary image")

在这个版本中,我们可以更清楚地区分鹿的轮廓。我们可以反转遮罩,使背景变为白色:

inverted_binary = stag_gray <= threshold>>> compare(stag, inverted_binary, "Binary image inverted")

2、阈值-全局

虽然尝试不同的阈值并观察它们对图像的影响可能很有趣,但我们通常使用比我们的眼球估计更稳健的算法来执行阈值分割。

有很多阈值算法,所以可能很难选择一种。在这种情况下,skimage具有try_all_threshold函数,该函数在给定的灰度图像上运行七种阈值算法。让我们加载一个示例并进行转换:

flower = imread("images/global_threshold_ex.jpg")flower_gray = rgb2gray(flower)compare(flower, flower_gray)

我们将看看是否可以使用阈值优化郁金香的特征:

from skimage.filters import try_all_thresholdfig, ax = try_all_threshold(flower_gray, figsize=(10, 8), verbose=False)

正如你所看到的,一些算法在这张图像上工作得更好,而其他算法则很糟糕。otsu算法看起来更好,所以我们将继续使用它。

在这一点上,我想提请你注意郁金香的原始图像:

>>> show(flower)

图像背景不均匀,因为有太多光线从后面的窗口射进来。我们可以通过绘制灰色郁金香的直方图来证实这一点:

>>> plt.hist(flower_gray.ravel(), bins=256);

正如预期的那样,大多数像素的值都位于直方图的远端,这证实了它们大部分都是明亮的。

为什么这很重要?根据图像的亮度,阈值算法的性能也会发生变化。因此,阈值算法通常有两种类型:

  1. 全局-适用于具有均匀、统一背景的照片

  2. 局部-用于不同图片区域中具有不同亮度级别的图像。

郁金香图像属于第二类,因为右侧部分比另一半亮得多,使其背景不均匀。我们不能在其上使用全局阈值算法,这就是为什么try_all_threshold中所有算法的性能都很差的原因。

稍后我们将回到郁金香示例和局部阈值。现在,我们将加载另一个亮度更精确的实例,并尝试自动设置阈值:

spiral = imread("images/otsu_example.jpg")
spiral_gray = rgb2gray(spiral)compare(spiral, spiral_gray)

我们将在Skimage中使用通用的全局阈值算法threshold_otsu:

from skimage.filters import threshold_otsu# Find optimal threshold with `threshold_otsu`
threshold = threshold_otsu(spiral_gray)# Binarize
binary_spiral = spiral_gray > thresholdcompare(spiral, binary_spiral, "Binarized Image w. Otsu Thresholding")

它工作得更好!

3、阈值-局部

现在,我们将使用局部阈值算法。

局部算法不关注整个图像,而是关注像素邻域,以解释不同区域的亮度不均匀。skimage中常见的局部算法为threshold_local函数:

from skimage.filters import threshold_locallocal_thresh = threshold_local(flower_gray, block_size=3, offset=0.0002)binary_flower = flower_gray > local_threshcompare(flower, binary_flower, "Tresholded flower image")

你必须使用offset参数来找到符合你需要的最佳图像。offset是从局部像素邻域的平均值中减去的常数。该“像素邻域”由local_threshold中的block_size参数确定,该参数表示算法在每个方向上围绕每个点查看的像素数。

显然,同时调整offset和block_size是一个缺点,但局部阈值是唯一比手动或全局阈值产生更好结果的选项。

让我们再举一个例子:

from skimage.filters import threshold_localhandwriting = imread("images/chalk_writing.jpg")
handwriting_gray = rgb2gray(handwriting)# Find optimal threshold using local
local_thresh = threshold_local(handwriting_gray, offset=0.0003)# Binarize
binary_handwriting = handwriting_gray > local_threshcompare(handwriting, binary_handwriting, "Binarized image with local thresholding")

正如你所看到的,经过阈值处理后,黑板上的笔迹更加精细。

4、边缘检测

边缘检测在很多方面都很有用,例如识别对象、从中提取特征、对其进行计数等等。

我们将从基本的Sobel滤波器开始,它在灰度图像中查找对象的边缘。我们将加载一张硬币图片,并对其使用Sobel滤波器:

from skimage.filters import sobelcoins = imread("images/coins_2.jpg")
coins_gray = rgb2gray(coins)coins_edge = sobel(coins_gray)compare(coins, coins_edge, "Images of coins with edges detected")

sobel很直截了当;你只需在灰色图像上调用它即可获得如上所述的输出。我们将在后面的部分中看到Sobel的更复杂版本。

5、平滑

另一种图像过滤技术是平滑。许多像下面的鸡一样的图像可能包含随机噪声,而对ML和DL算法没有任何有价值的信息。

例如,鸡周围的毛发会给图像添加噪声,这可能会使ML模型的注意力偏离主要对象本身。在这种情况下,我们使用平滑来模糊噪声或边缘并降低对比度。

chickens = imread("images/chickens.jpg")>>> show(chickens)

高斯平滑是最流行和最强大的平滑技术之一:

from skimage.filters import gaussiansmoothed = gaussian(chickens, multichannel=True, sigma=2)compare(chickens, smoothed, "An image smoothed with Gaussian smoothing")

你可以通过调整sigma参数来控制模糊的效果。如果你正在处理RGB图像,请不要忘记将multichannel设置为True。

如果图像分辨率太高,平滑效果可能肉眼看不到,但仍然有效。

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

关于图像处理和Python深度学习的教程:第一部分相关推荐

  1. 人工智能——图像处理和Python深度学习的全教程(建议收藏)

    介绍 在这篇文章中,我们将学习如何执行图像处理.在整篇文章中,我们使用到的库是Scikit Image. 基础知识 1.什么是图像? 图像数据可能是文本之后最常见的数据.那么,电脑如何理解你在埃菲尔铁 ...

  2. [Python从零到壹] 三十三.图像处理基础篇之什么是图像处理和OpenCV配置

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  3. Python 深度学习架构实用指南:第一、二部分

    原文:Hands-On Deep Learning Architectures with Python 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自[ApacheCN 深度学习 译文集] ...

  4. Python深度学习-快速指南

    Python深度学习-快速指南 (Python Deep Learning - Quick Guide) Python深度学习-简介 (Python Deep Learning - Introduct ...

  5. 《Python深度学习》第一章笔记

    <Python深度学习>第一章笔记 1.1人工智能.机器学习.深度学习 人工智能 机器学习 深度学习 深度学习的工作原理 1.2深度学习之前:机器学习简史 概率建模 早期神经网络 核方法 ...

  6. Python深度学习篇

    Python深度学习篇一<什么是深度学习> Excerpt 在过去的几年里,人工智能(AI)一直是媒体大肆炒作的热点话题.机器学习.深度学习 和人工智能都出现在不计其数的文章中,而这些文章 ...

  7. 我最喜欢的9个 Python深度学习库

    本文为数盟原创译文 如果你对深度学习和卷积神经网络感兴趣,但是并不知道从哪里开始,也不知道使用哪种库,那么这里就为你提供了许多帮助. 在这篇文章里,我详细解读了9个我最喜欢的Python深度学习库. ...

  8. Python深度学习篇五《深度学习用于计算机视觉》

    前言 前期回顾:Python深度学习篇四<机器学习基础> 上面这篇里面写了关于向量数据最常见的机器学习任务. 好,接下来切入正题. 本章包括以下内容: 理解卷积神经网络(convnet) ...

  9. Python深度学习篇六《深度学习用于文本和序列》

    前言 前期回顾: Python深度学习篇五<深度学习用于计算机视觉> 上面这篇里面写了计算机视觉相关. 卷积神经网络是解决视觉分类问题的最佳工具. 卷积神经网络通过学习模块化模式和概念的层 ...

最新文章

  1. 地图漫游功能的具体体现_骏谷科技|数据中心三维可视化管理系统功能亮点
  2. ZhuGongpu CloudX-for-Android
  3. maven+springmvc+dubbo+zookeeper
  4. element -ui 表单验证 如果 需要验证的v-model 是对象中的对象 总是提示没有填写....
  5. 【时间序列】Github最受欢迎的10大深度学习时间序列项目!
  6. qt linux 鼠标事件,QT学习笔记5:QMouseEvent鼠标事件简介
  7. arm引脚复用linux,ARM知识分享-i.MX6Q GPIO复用修改方法
  8. 浅析MySQL JDBC连接配置上的两个误区
  9. 数据结构--Dijkstra算法最清楚的讲解
  10. OCA第1部分中的Java难题
  11. 统计信息在数据库中的作用_统计在行业中的作用
  12. Hadoop生态系统学习路线
  13. enum mysql byte_九、臭名昭著的 MySQL ENUM 类型 ( 上 )
  14. 易语言word模板复制粘贴_请给你的Word“打底妆”(让Word跑快些系列)
  15. 例题-Quota 实作:
  16. 【MIMO通信】基于matlab空时分组编码MIMO_OFDM通信系统仿真【含Matlab源码 663期】
  17. Java代码规范之编程规约
  18. 计算机房装修对门的要求,机房建设标准要求
  19. 国家计算机考试报名照片编辑器,电脑的证件照制作软件推荐
  20. Javascript设计模式-00-说明

热门文章

  1. 滑动式折叠菜单 - Slashdot's Menu
  2. 方向不对,努力白费(好文章)
  3. python接口自动化实战(框架)
  4. RocketMQ一:快速入门和集群架构
  5. linux 常用命令搜集 —— 筑梦之路
  6. vue中props的默认写法
  7. win10 系统IE浏览器自动转Edge如何设置
  8. Spark2.1 内存管理详解
  9. 深入理解电容器的等效串联电阻(ESR),多个小电容并联取代大电解电容的作用
  10. smart license简单使用感想