基于 NumPy 的图像二值化

欢迎关注 “小白玩转Python”,发现更多 “有趣”

在本文中,我们将学习如何使用 NumPy 对图像进行二值化,当然,我们将使用 OpenCV 来读取灰度和 RGB 格式的图像。

要理解二进制是什么ーー二进制是由两种东西组成的东西。在计算机术语中,二进制只是0和1。如果我们要把同样的事情在图像中联系起来,那么就是说黑白图像中:

  • 0 表示黑色

  • 1 表示白色

在学习图像处理的初始阶段,我们通常认为灰度图像是一个二值图像。虽然不是。但是慢慢地,当我们开始谈论这个话题时,我们意识到我们错得有多离谱。因此,接下来,我们将学习如何使用库和不使用库(NumPy 用于矩阵操作,只是为了避免使用规则 for 循环时程序速度缓慢)将图像进行二进制化。除此之外,我们还将利用 Matplotlib 来绘制结果。

RGB 和灰度概述

对于灰度图像来说,二值化运算的效果非常好。彩色(RGB)图像的问题在于,每个像素都是一个矢量,代表3个唯一的值,一个是红色,一个是绿色,一个是蓝色。

一个典型的灰度图像的矩阵看起来像:

array([[162, 162, 162, ..., 170, 155, 128],
       [162, 162, 162, ..., 170, 155, 128],
       [162, 162, 162, ..., 170, 155, 128],
       ...,
       [ 43,  43,  50, ..., 104, 100,  98],
       [ 44,  44,  55, ..., 104, 105, 108],
       [ 44,  44,  55, ..., 104, 105, 108]], dtype=uint8)

一个典型的 RGB 图像的矩阵看起来像:

array([[[226, 137, 125], ..., [200,  99,  90]],
       [[226, 137, 125], ..., [200,  99,  90]],
       [[226, 137, 125], ..., [200,  99,  90]],
       ...,
       [[ 84,  18,  60], ..., [177,  62,  79]],
       [[ 82,  22,  57], ..., [185,  74,  81]],
       [[ 82,  22,  57], ..., [185,  74,  81]]], dtype=uint8)

如果我们将 R,G 和 B 三个通道的像素从上面的矩阵中分离出来,我们得到。

R 矩阵

array([[226, 226, 223, ..., 230, 221, 200],
       [226, 226, 223, ..., 230, 221, 200],
       [226, 226, 223, ..., 230, 221, 200],
       ...,
       [ 84,  84,  92, ..., 173, 172, 177],
       [ 82,  82,  96, ..., 179, 181, 185],
       [ 82,  82,  96, ..., 179, 181, 185]], dtype=uint8)

G 矩阵

array([[137, 137, 137, ..., 148, 130,  99],
       [137, 137, 137, ..., 148, 130,  99],
       [137, 137, 137, ..., 148, 130,  99],
       ...,
       [ 18,  18,  27, ...,  73,  68,  62],
       [ 22,  22,  32, ...,  70,  71,  74],
       [ 22,  22,  32, ...,  70,  71,  74]], dtype=uint8)

B 矩阵

array([[125, 125, 133, ..., 122, 110,  90],
       [125, 125, 133, ..., 122, 110,  90],
       [125, 125, 133, ..., 122, 110,  90],
       ...,
       [ 60,  60,  58, ...,  84,  76,  79],
       [ 57,  57,  62, ...,  79,  81,  81],
       [ 57,  57,  62, ...,  79,  81,  81]], dtype=uint8)

无论我们对灰度图像进行什么操作,我们都需要对 RGB 图像进行相同的计算,但需要将 R,G 和 B 通道分离3次,最后将它们合并为一个正确的 RGB 图像。

编程时间

我们主要使用的软件库是:

  • NumPy

  • Matplotlib

  • OpenCV

基于 NumPy 的图像二值化_第1张图片

导入软件库

import numpy as np
import cv2
import json
from matplotlib import pyplot as plt

读取图片

def read_this(image_file, gray_scale=False):
    image_src = cv2.imread(image_file)
    if gray_scale:
        image_src = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY)
    else:
        image_src = cv2.cvtColor(image_src, cv2.COLOR_BGR2RGB)
    return image_src

上面的函数以灰度或者 RGB 的形式读取图像并返回图像矩阵。

实现代码

为了将图像转换为二值图像,我们可以简单地利用 cv2库中提供的threshold()方法。这种方法,不管图像是什么(灰度或 RGB)转换成二进制。使用时需要4个参数。

  • src:基本上就是图像矩阵

  • thresh:阈值,基于这个阈值像素被赋予一个新的值。如果像素小于这个值,我们将把这些像素重新赋值为255;否则,像素将重新定值为0

  • maxval:图像可以包含的最大像素值(255)

  • type:一种给定的阈值类型,并基于该类型计算操作。

在此之后,我们将在下面的函数绘制结果以查看变化。

def binarize_lib(image_file, thresh_val=127, with_plot=False, gray_scale=False):
    image_src = read_this(image_file=image_file, gray_scale=gray_scale)
    th, image_b = cv2.threshold(src=image_src, thresh=thresh_val, maxval=255, type=cv2.THRESH_BINARY)
    if with_plot:
        cmap_val = None if not gray_scale else 'gray'
        fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10, 20))
        
        ax1.axis("off")
        ax1.title.set_text('Original')
        
        ax2.axis("off")
        ax2.title.set_text("Binarized")
        
        ax1.imshow(image_src, cmap=cmap_val)
        ax2.imshow(image_b, cmap=cmap_val)
        return True
    return image_b

让我们测试一下上面的函数:

binarize_lib(image_file='lena_original.png', with_plot=True)

基于 NumPy 的图像二值化_第2张图片

binarize_lib(image_file='lena_original.png', with_plot=True, gray_scale=True)

基于 NumPy 的图像二值化_第3张图片

现在我们已经看到了原始图像和二进制图像的结果,很明显,使用库中提供的函数编写的代码对这两者都适用。是时候让我们从头开始编写如何使用 NumPy 对图像进行二值化。

从零开始的代码实现

首先,我们将编写一个函数,将小于指定阈值的像素值重新赋值为255。

通过这样做,我们可以看到下面这样的东西:

def convert_binary(image_matrix, thresh_val):
    white = 255
    black = 0
    
    initial_conv = np.where((image_matrix <= thresh_val), image_matrix, white)
    final_conv = np.where((initial_conv > thresh_val), initial_conv, black)
    
    return final_conv

我们将上面的函数通过分离 r、 g 和 b 值进行三次调用,最后将它们合并得到二值化图像。一旦这样做,我们就可以像以前那样绘制结果。

def binarize_this(image_file, thresh_val=127, with_plot=False, gray_scale=False):
    image_src = read_this(image_file=image_file, gray_scale=gray_scale)
    
    if not gray_scale:
        cmap_val = None
        r_img, g_img, b_img = image_src[:, :, 0], image_src[:, :, 1], image_src[:, :, 2]
        
        r_b = convert_binary(image_matrix=r_img, thresh_val=thresh_val)
        g_b = convert_binary(image_matrix=g_img, thresh_val=thresh_val)
        b_b = convert_binary(image_matrix=b_img, thresh_val=thresh_val)
        
        image_b = np.dstack(tup=(r_b, g_b, b_b))
    else:
        cmap_val = 'gray'
        image_b = convert_binary(image_matrix=image_src, thresh_val=thresh_val)
    
    if with_plot:
        fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10, 20))
        
        ax1.axis("off")
        ax1.title.set_text('Original')
        
        ax2.axis("off")
        ax2.title.set_text("Binarized")
        
        ax1.imshow(image_src, cmap=cmap_val)
        ax2.imshow(image_b, cmap=cmap_val)
        return True
    return image_b

我们只是使用 NumPy 创建了我们的二进制化代码:

binarize_this(image_file='lena_original.png', with_plot=True)

基于 NumPy 的图像二值化_第4张图片

binarize_this(image_file='lena_original.png', with_plot=True, gray_scale=True)

基于 NumPy 的图像二值化_第5张图片

至此,我们发现使用 NumPy 从零编写的结果与我们调用库函数编写的代码得到的结果非常相似。

·  END  ·

HAPPY LIFE

你可能感兴趣的:(python,opencv,深度学习,计算机视觉,人工智能)