数字图像处理 - 实验作业六 - Python

文章目录

  • 第十章 图像分割
    • 实现一种基于梯度算子的边缘检测
    • 实现一种基于阈值的分割方法(利用简单的阈值确定方法)
    • 实现基于类间方差最大(otsu’s)的图像阈值分割

第十章 图像分割

整体等于其部分之和
整体大于其部分之和

实现一种基于梯度算子的边缘检测

这里采用了拉普拉斯算子来进行边缘检测

Laplace算子作为边缘检测的方法之一,也是工程数学中常用的一种积分变换。把图像的像素值想象成一个变化的曲线。对应变化的曲线,一阶导数的极值位置,二阶导数为0,利用这个来检测边缘

实现的边缘检测效果如下所示

数字图像处理 - 实验作业六 - Python_第1张图片

对应的代码为:

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image


def laplace_filter(image):
    kernel_size = 3
    height, width = image.shape
    padding_size = int((kernel_size - 1) / 2)
    template = np.array([[1, 1, 1],
                         [1, -8, 1],
                         [1, 1, 1]])

    padded_img = np.pad(image, padding_size, 'constant')
    edge_of_img = np.zeros_like(image, dtype=float)

    for i in range(height):
        for j in range(width):
            corr = padded_img[i:i + kernel_size, j:j + kernel_size]
            edge_of_img[i, j] = np.abs(np.sum(template * corr))

    return edge_of_img


def process():
    src = np.array(Image.open("man.jpg").convert("L"))
    edge = laplace_filter(src)

    plt.subplot(1, 2, 1)
    plt.imshow(src, cmap='gray')
    plt.axis("off")

    plt.subplot(1, 2, 2)
    plt.imshow(edge, cmap='gray')
    plt.axis("off")
    plt.show()


if __name__ == '__main__':
    process()

实现一种基于阈值的分割方法(利用简单的阈值确定方法)

这里采用的是全局阈值的方法进行分割

全局阈值的计算过程为

  1. 给出初始阈值T
  2. 用T分割图像得到G1和G2
  3. 计算两部分的均值μ1和μ1
  4. 计算新的阈值 T = 1 2 ( μ 1 + μ 2 ) T=\frac{1}{2}(\mu_1+\mu_2) T=21(μ1+μ2)
  5. 重复2-4,直到 ∣ T k − T k − 1 ∣ ≤ T 0 |T_k-T_{k-1}|≤T_0 TkTk1T0

全局阈值分割图像的实现效果如下所示

数字图像处理 - 实验作业六 - Python_第2张图片

实现的代码如下所示:

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import cv2


def global_threshold(image):
    error = 1
    old_t = 127
    new_t = 0

    while True:

        m1 = image[image <= old_t]
        m2 = image[image > old_t]

        mean1 = np.mean(m1)
        mean2 = np.mean(m2)

        new_t = (mean1 + mean2) / 2

        if (np.abs(new_t - old_t)) <= error:
            break
        else:
            old_t = new_t

    return new_t


def process():
    src = np.array(Image.open("man.jpg").convert("L"))
    line = global_threshold(src)
    ret, dst = cv2.threshold(src, line, 255, cv2.THRESH_BINARY)

    plt.subplot(1, 2, 1)
    plt.imshow(src, cmap='gray')
    plt.axis("off")

    plt.subplot(1, 2, 2)
    plt.imshow(dst, cmap='gray')
    plt.axis("off")
    plt.show()


if __name__ == '__main__':
    process()

实现基于类间方差最大(otsu’s)的图像阈值分割

相对于上述方法来说,otus是一种找出全局最佳阈值的方法

大津法(OTSU)是一种确定图像二值化分割阈值的算法,由日本学者大津于1979年提出。从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。

它被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响,因此在数字图像处理上得到了广泛的应用。它是按图像的灰度特性,将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。因此,使类间方差最大的分割意味着错分概率最小

其实现的效果如下所示

数字图像处理 - 实验作业六 - Python_第3张图片
其实现的代码如下所示

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
import cv2


def otsu(image):  # 传入的参数为ndarray形式
    height, width = image.shape
    pixels = np.zeros(256)

    for i in range(height):
        for j in range(width):
            pixels[int(image[i][j])] += 1

    var_best = 0.0
    current_best = 0
    for k in range(1, 256):

        front = pixels[:k].sum() / (height * width)
        back = pixels[k:].sum() / (height * width)
        front_mean = 0.0
        back_mean = 0.0

        for i in range(k):
            front_mean += i * pixels[i]
        for j in range(k, 256):
            back_mean += j * pixels[j]

        front_mean = front_mean / pixels[:k].sum()
        back_mean = back_mean / pixels[k:].sum()

        gray_sum = front_mean * front + back_mean * back
        tmp_var = front * np.power((gray_sum - front_mean), 2) + back * np.power((gray_sum - back_mean), 2)

        if tmp_var > var_best:
            current_best = k
            var_best = tmp_var

    return current_best


def process():
    src = np.array(Image.open("man.jpg").convert("L"))
    best = otsu(src)
    print(best)
    ret, dst = cv2.threshold(src, best, 255, cv2.THRESH_BINARY)

    plt.subplot(1, 2, 1)
    plt.imshow(src, cmap='gray')
    plt.axis("off")

    plt.subplot(1, 2, 2)
    plt.imshow(dst, cmap='gray')
    plt.axis("off")
    plt.show()


if __name__ == '__main__':
    process()

你可能感兴趣的:(数字图像处理,python)