Imutils 入门指北 based on OpenCV

Table of Contents

开始进入兔子坑(

Description

imutils literally means "image utils", 所以看名字也知道主要是操作图形图像的 module. See the github link here of the module.

该 module 由 Adrian Rosebrock 开发。整篇文档参考的也是 Github 项目上的 Readme,以及 Adrian 在 pyimagesearch 上写的 入门第一课(这下真进 rabbit hole 了qwq)。

对了,Adrian 还写了他自己的学习的故事 on https://pyimagesearch.com/about/ ,挺好看的(


Before we start, check the OpenCV install tutorials written by Adrian. 不过,用 PyCharm 的只需要依次点击 "File -> Settings -> Python Interpreter",不管是单独的环境还是全局环境,按“+”按钮,搜索 “opencv-python”,install 就行了。至于 imutils,直接 import,PyCharm 报了错再安装这个包就行(自动化 pip)。


imutils 整合了 opencv,主要做图形图像处理,也加入了视频的一些处理。

Usage examples

cv2 读取图片信息

import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    (h, w, d) = image.shape
    print("width={}, height = {}, depth = {}".format(w, h, d))

Just cv2, 读入图片只要 cv2.imread() 就行。

image.shape 给出图片的 height、width,以及 depth。depth 指的是 channel 数,比如一张色深为 24bit 的 jpg 图像,它的 depth 就是 3。

图像平移

在 canvas 不动的情况下,对图像进行二维的平移。封装的是 cv2.warpAffine() + 平移矩阵(在 cv2 中要手动写矩阵 omg)。

由于平移出 canvas 的部分会被截掉,由于平移空出的部分会用黑色填充。

import imutils
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    translated = imutils.translate(image, 100, -100)
    cv2.imwrite("translated.jpg", translated)

用法:imutils.translate(image, x, y),x 和 y 分别表示在两轴上的偏移量。向右向下为正。

图像旋转

在 OpenCV 中旋转图像是通过调用 cv2.getRotationMatrix2D()cv2.warpAffine() 来完成的,并且注意提供图像要旋转的点的 (x, y) 坐标。总之非常繁杂。

import imutils
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    for angle in range(0, 360, 90):
        rotated = imutils.rotate(image, angle)
        cv2.imshow("Angle = %d" % angle, rotated)

之所以用 range 是因为 python3 中将 xrangerange 合并了。

一开始只见 Process finished with exit code 0,但是什么图也没有,还以为是 linux 上这个有点问题,想不到是 imshow 了以后很快就消失导致的。加个 cv2.waitKey() 就可以了。

So, it is a little different from the demo code in the github readme file.

import imutils
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    for angle in range(0, 360, 90):
        rotated = imutils.rotate(image, angle, (0, 0), 0.4)
        cv2.imshow("Angle = %d" % angle, rotated)
        cv2.waitKey()

也可以加上旋转中心,以及缩放比例。

图像缩放

在 OpenCV 中调整图像大小是通过调用 cv2.resize() 来完成的。但是,需要特别注意确保保持纵横比。imutils 会自动保持纵横比,也不用手动计算图像尺寸。另一个可选关键字参数 inter 可用于指定插值方法。

import imutils
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    for height in (400, 300, 200, 100):
        resized = imutils.resize(image, height=height)
        cv2.imshow("height = %d px" % height, resized)
        cv2.waitKey()

imutils.resize(image, width, height, inter),希望用宽度来缩放就直接填,希望用高度的写height=XXX就行了。

Skeletonization 骨架化

骨架化是在图像中构建对象的“拓扑骨架”(topological skeleton)的过程,其中对象被假定为黑色背景上的白色。OpenCV 不提供显式构造骨架的函数,但提供了形态学和二进制函数来执行此操作。

imutils.skeletonize(image, size, structuring),其中 size 是结构元素的尺寸,可以认为是精度,越小处理时间越长。可选参数 structuring 可用于控制结构元素——它默认为 cv2.MORPH_RECT,但可以是任何有效的结构元素。

// 会需要跑一段时间qwq

// 突然想到没有 CUDA. AWSL.

import imutils
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  // BGR 转换为灰度
    skeleton = imutils.skeletonize(gray, (3, 3))
    cv2.imshow("skeleton", skeleton)
    cv2.waitKey()

用 Matplotlib 显示

在 OpenCV 中,图像以 BGR 顺序表示为 NumPy 数组。这在使用 cv2.imshow 时工作正常。但是如果打算使用 Matplotlib,则 plt.imshow 假定图像是 RGB 顺序的。用 cv2.cvtColor 解决此问题,或者用 opencv2matplotlib

demo 中的样例是:

# INCORRECT: show the image without converting color spaces
plt.figure("Incorrect")
plt.imshow(cactus)

# CORRECT: convert color spaces before using plt.imshow
plt.figure("Correct")
plt.imshow(imutils.opencv2matplotlib(cactus))
plt.show()

一开始 Matplotlib 一直报错无法绘图,解决方法:

  1. sudo apt-get install python3-tk 安装 python3-tkinter,别的发行版也差不多
  2. 加上matplotlib.use('TkAgg')

因为 matplotlibbackend 默认渲染器是 agg,没有图形显示界面,所以需要用 TkAgg

import imutils
import cv2
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    plt.figure("incorrect")
    plt.imshow(image)
    plt.show()
    image = imutils.opencv2matplotlib(image)
    plt.figure("correct")
    plt.imshow(image)
    plt.show()

incorrect 的那张图就是因为 RGB 和 BGR 不匹配,所以会造成色偏。通常来说图像会偏蓝。

将图像 URL 转换为图像

url_to_image 接受一个参数:要下载并转换为 OpenCV 格式的 NumPy 数组的图像的 url。该函数在内存中执行下载。

Pyimagesearch 上已有介绍。

import imutils
import cv2

if __name__ == '__main__':
    url = "https://pyimagesearch.com/static/pyimagesearch_logo_github.png"
    logo = imutils.url_to_image(url)
    cv2.imshow("URL to Image", logo)
    cv2.waitKey(0)

检查 OpenCV 版本

多少是个工程向的 API。用法直接看 demo 就行了。以及 Github 上的 demo 还停留在 OpenCV 3的时代。😎

import imutils
import cv2

if __name__ == '__main__':
    print("Your OpenCV version: {}".format(cv2.__version__))
    print("Are you using OpenCV 2.X? {}".format(imutils.is_cv2()))
    print("Are you using OpenCV 3.X? {}".format(imutils.is_cv3()))
    print("Are you using OpenCV 4.X? {}".format(imutils.is_cv4()))

Canny 边缘检测

Wikipedia 警告

Canny edge detector 是一种边缘检测算子,它使用多阶段算法来检测图像中的各种边缘。它由 John F. Canny 于 1986 年开发。Canny 还提出了边缘检测的计算理论,解释了该技术为何有效。

Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:

  • 好的检测 – 算法能够尽可能多地标识出图像中的实际边缘。
  • 好的定位 – 标识出的边缘要与实际图像中的实际边缘尽可能接近。
  • 最小响应 – 图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。

为了满足这些要求 Canny 使用了变分法,这是一种寻找满足特定功能的函数的方法。最优检测使用四个指数函数项的和表示,但是它非常近似于高斯函数的一阶导数

我超,数学!


算法步骤

  1. 降噪

    任何边缘检测算法都不可能在未经处理的原始数据上很好地处理,所以第一步是对原始数据与高斯平滑模板作卷积,得到的图像与原始图像相比有些轻微的模糊(blurred)。这样,单独的一个像素噪声在经过高斯平滑的图像上变得几乎没有影响。

  2. 寻找图像中的亮度梯度

    较高的亮度梯度比较有可能是边缘,但是没有一个确切的值来限定多大的亮度梯度是边缘多大又不是,所以 Canny 使用了滞后阈值。

    滞后阈值需要两个阈值 —— 高阈值与低阈值。假设图像中的重要边缘都是连续的曲线,这样我们就可以跟踪给定曲线中模糊的部分,并且避免将没有组成曲线的噪声像素当成边缘。所以我们从一个较大的阈值开始,这将标识出我们比较确信的真实边缘,使用前面导出的方向信息,我们从这些真正的边缘开始在图像中跟踪整个的边缘。在跟踪的时候,我们使用一个较小的阈值,这样就可以跟踪曲线的模糊部分直到我们回到起点。

    一旦这个过程完成,我们就得到了一个二值图像,每点表示是否是一个边缘点。

  3. 在图像中跟踪边缘


Canny 算法适用于不同的场合。它的参数允许根据不同实现的特定要求进行调整以识别不同的边缘特性。对于 PC 上的实时图像处理来说可能慢得无法使用,尤其是在使用大的 Gaussian filter 的情况下。但是,我们讨论计算能力的时候,也要考虑到随着处理器速度不断提升,有望在未来几年使得这不再成为一个问题。

相关链接:Canny edge detector – WikipediaGaussian filter – Wikipedia


import imutils
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    edgeMap = imutils.auto_canny(gray)
    cv2.imshow("Original", image)
    cv2.waitKey()
    cv2.imshow("Automatic Edge Map", edgeMap)
    cv2.waitKey()

我的评价是,效果比 Skeletonization 好多了,而且快。

四点透视变换

首先介绍 ROI:A region of interest (ROI) is a portion of an image that you want to filter or operate on in some way. You can represent an ROI as a binary mask image. In the mask image, pixels that belong to the ROI are set to 1 and pixels outside the ROI are set to 0. 简单说就是对目标区域打标记。

计算机视觉和图像处理中的一项常见任务是对图像中的 ROI 执行 4 点透视变换,并获得 ROI 的自上而下的“鸟瞰图”。透视模块会为您解决这个问题。应用 4 点透视变换的真实示例可以在此博客中绑定,内容是关于构建出色的移动文档扫描仪

总之就是这么个玩意,扫描仪嘛。

Adrian 给的效果图是:

perspective_transform

import imutils
from imutils import perspective
import numpy as np
import cv2

if __name__ == '__main__':
    image = cv2.imread("example.jpg")
    image = imutils.resize(image, 600)
    cv2.imshow("example.jpg", image)
    clone = image.copy()
    # pts 初始化四个点的坐标
    # 这里偷个懒 直接用 demo 里的坐标了
    pts = np.array([(73, 239), (356, 117), (475, 265), (187, 443)])

    for (x, y) in pts:
        cv2.circle(clone, (x, y), 5, (0, 255, 0), -1)

    # 应用效果,虽然对参数还不是很懂(
    warped = perspective.four_point_transform(image, pts)
    cv2.imshow("Original", image)
    cv2.waitKey()
    cv2.imshow("Warped", warped)
    cv2.waitKey()

递归地寻找路径下的图像文件

imutils 的 path 子模块包含一个基于根目录递归查找图像的功能。

Example:

Assuming we are in the demos directory, let’s list the contents of the ../demo_images:

from imutils import paths
for imagePath in paths.list_images("../demo_images"):
    print imagePath

Output:

../demo_images/bridge.jpg
../demo_images/cactus.jpg
../demo_images/notecard.png
../demo_images/pyimagesearch_logo.jpg
../demo_images/shapes.png
../demo_images/workspace.jpg

就像这样。

End

一直在入门,从来学不会。QAQ

代码寄中寄,概统摆大烂。QAQ

情况,真的是太糟了啊。

Share