Python的图像处理:如何使用`Pillow`、`Scikit-image`和`OpenCV`进行图像处理。

Python 图像处理:Pillow、Scikit-image 和 OpenCV 的应用

大家好,今天我们来深入探讨 Python 在图像处理方面的应用,重点讲解三个非常流行的库:Pillow、Scikit-image 和 OpenCV。我们将从基础概念入手,逐步深入到实际应用,并通过代码示例展示它们各自的优势和特点。

1. 图像处理基础

在开始之前,我们先简单回顾一下图像处理的一些基础概念。

  • 图像表示: 数字图像通常由像素矩阵表示,每个像素代表图像中的一个点,其数值表示颜色或灰度值。
  • 颜色空间: 常见的颜色空间包括 RGB(红绿蓝)、灰度、HSV(色相、饱和度、亮度)等。
  • 基本操作: 包括图像读取、显示、保存,以及像素级别的操作。

2. Pillow:图像处理的瑞士军刀

Pillow 是 Python Imaging Library (PIL) 的一个分支,提供了广泛的图像处理功能,易于使用,适合处理各种图像格式。

2.1 安装 Pillow

pip install Pillow

2.2 图像的读取、显示和保存

from PIL import Image

# 读取图像
img = Image.open("image.jpg")

# 显示图像 (需要安装图像查看器)
img.show()

# 获取图像尺寸
width, height = img.size
print(f"图像尺寸:{width} x {height}")

# 获取图像格式
print(f"图像格式:{img.format}")

# 获取图像颜色模式
print(f"图像模式:{img.mode}")

# 保存图像
img.save("image_copy.png")

2.3 图像转换

Pillow 支持图像格式和颜色模式的转换。

from PIL import Image

img = Image.open("image.jpg")

# 转换为灰度图像
img_gray = img.convert("L")
img_gray.save("image_gray.jpg")

# 转换为 RGB 图像 (如果原始图像是其他格式)
img_rgb = img.convert("RGB")
img_rgb.save("image_rgb.jpg")

2.4 图像裁剪和缩放

from PIL import Image

img = Image.open("image.jpg")

# 裁剪图像 (左上角坐标 x, y, 右下角坐标 x, y)
cropped_img = img.crop((100, 100, 300, 300))
cropped_img.save("image_cropped.jpg")

# 缩放图像
resized_img = img.resize((200, 200))
resized_img.save("image_resized.jpg")

# 保持比例缩放
def resize_image(image, size):
    """
    保持原始图像的纵横比进行缩放
    """
    width, height = image.size
    new_width, new_height = size

    # 计算缩放比例
    width_ratio = new_width / width
    height_ratio = new_height / height

    # 选择较小的缩放比例以避免裁剪
    ratio = min(width_ratio, height_ratio)

    # 计算新的尺寸
    resized_width = int(width * ratio)
    resized_height = int(height * ratio)

    # 使用 LANCZOS (抗锯齿) 算法调整大小
    resized_image = image.resize((resized_width, resized_height), Image.LANCZOS)

    # 创建一个新图像,并在中心粘贴调整大小后的图像
    new_image = Image.new("RGB", (new_width, new_height), (0, 0, 0))  # 黑色背景
    new_image.paste(resized_image, ((new_width - resized_width) // 2, (new_height - resized_height) // 2))

    return new_image

img = Image.open("image.jpg")
resized_img_with_padding = resize_image(img, (200, 200))
resized_img_with_padding.save("image_resized_padding.jpg")

2.5 图像旋转

from PIL import Image

img = Image.open("image.jpg")

# 旋转 45 度
rotated_img = img.rotate(45)
rotated_img.save("image_rotated.jpg")

# 旋转 45 度,并填充空白区域
rotated_img_expand = img.rotate(45, expand=True)
rotated_img_expand.save("image_rotated_expand.jpg")

2.6 图像滤镜

Pillow 提供了一些内置的图像滤镜。

from PIL import Image, ImageFilter

img = Image.open("image.jpg")

# 应用模糊滤镜
blurred_img = img.filter(ImageFilter.BLUR)
blurred_img.save("image_blurred.jpg")

# 应用锐化滤镜
sharpened_img = img.filter(ImageFilter.SHARPEN)
sharpened_img.save("image_sharpened.jpg")

# 应用边缘增强滤镜
edge_enhanced_img = img.filter(ImageFilter.EDGE_ENHANCE)
edge_enhanced_img.save("image_edge_enhanced.jpg")

2.7 像素级别的操作

from PIL import Image

img = Image.open("image.jpg")
pixels = img.load()  # 返回一个像素访问对象

width, height = img.size

# 反转颜色
for x in range(width):
    for y in range(height):
        r, g, b = pixels[x, y]
        pixels[x, y] = (255 - r, 255 - g, 255 - b)

img.save("image_inverted.jpg")

3. Scikit-image:科学图像处理库

Scikit-image 是一个基于 NumPy 的图像处理库,提供了大量的图像处理算法,包括图像分割、特征提取、图像增强等,更偏向于科学研究。

3.1 安装 Scikit-image

pip install scikit-image

3.2 图像的读取、显示和保存

from skimage import io

# 读取图像
img = io.imread("image.jpg")

# 显示图像 (需要 matplotlib)
import matplotlib.pyplot as plt
plt.imshow(img)
plt.show()

# 获取图像尺寸
height, width, channels = img.shape
print(f"图像尺寸:{width} x {height}, 通道数:{channels}")

# 保存图像
io.imsave("image_copy.png", img)

3.3 图像转换

from skimage import io, color

img = io.imread("image.jpg")

# 转换为灰度图像
img_gray = color.rgb2gray(img)
io.imsave("image_gray.jpg", img_gray)

# 转换为 HSV 图像
img_hsv = color.rgb2hsv(img)
io.imsave("image_hsv.jpg", img_hsv)  # HSV图像保存通常需要做一些处理,因为它的值范围不同于RGB

# 将灰度图像转换为 RGB 图像 (重复灰度值到三个通道)
img_rgb = color.gray2rgb(img_gray)
io.imsave("image_rgb.jpg", img_rgb)

3.4 图像增强

from skimage import io, exposure

img = io.imread("image.jpg")

# 调整伽马值
gamma_corrected_img = exposure.adjust_gamma(img, gamma=0.5)  # gamma < 1 增强图像亮度
io.imsave("image_gamma.jpg", gamma_corrected_img)

# 直方图均衡化
equalized_img = exposure.equalize_hist(img)
io.imsave("image_equalized.jpg", equalized_img)

# 自适应直方图均衡化 (CLAHE)
from skimage import exposure

img = io.imread("image.jpg")

clahe = exposure.equalize_adapthist(img, clip_limit=0.03)
io.imsave("image_clahe.jpg", clahe)

3.5 图像滤波

from skimage import io, filters

img = io.imread("image.jpg")

# 高斯滤波
blurred_img = filters.gaussian(img, sigma=1)
io.imsave("image_gaussian.jpg", blurred_img)

# 中值滤波
from skimage.morphology import disk
from skimage.filters import rank

selem = disk(5)
median_filtered_img = rank.median(img, selem=selem)
io.imsave("image_median.jpg", median_filtered_img)

# Sobel 边缘检测
edges = filters.sobel(img_gray) #需要灰度图
io.imsave("image_sobel.jpg", edges)

3.6 图像分割

from skimage import io, segmentation

img = io.imread("image.jpg")

# 使用 Felzenszwalb 算法进行图像分割
segments_fz = segmentation.felzenszwalb(img, scale=100, sigma=0.5, min_size=50)
io.imsave("image_segmented_fz.jpg", segmentation.mark_boundaries(img, segments_fz))

# 使用 SLIC 算法进行图像分割
segments_slic = segmentation.slic(img, n_segments=100, compactness=10, sigma=1)
io.imsave("image_segmented_slic.jpg", segmentation.mark_boundaries(img, segments_slic))

# 使用 Watershed 算法进行图像分割 (需要预处理,例如计算梯度)
from skimage.filters import sobel
from skimage.segmentation import watershed
from scipy import ndimage as ndi

elevation_map = sobel(img_gray)

markers = ndi.label(elevation_map < 0.08)[0] #阈值需要根据图像进行调整

segments_watershed = watershed(elevation_map, markers)
io.imsave("image_segmented_watershed.jpg", segmentation.mark_boundaries(img, segments_watershed))

3.7 特征提取

from skimage import io, feature

img = io.imread("image.jpg", as_gray=True)

# 提取 HOG 特征 (方向梯度直方图)
hog_features, hog_image = feature.hog(img, orientations=8, pixels_per_cell=(16, 16),
                                        cells_per_block=(1, 1), visualize=True, channel_axis=None)

io.imsave("image_hog.jpg", hog_image)

print(f"HOG 特征维度:{hog_features.shape}")

4. OpenCV:强大的计算机视觉库

OpenCV (Open Source Computer Vision Library) 是一个广泛应用于计算机视觉领域的库,提供了丰富的图像处理和计算机视觉算法,性能优异,适合实时应用。

4.1 安装 OpenCV

pip install opencv-python

4.2 图像的读取、显示和保存

import cv2

# 读取图像
img = cv2.imread("image.jpg")

# 显示图像 (使用 OpenCV 的窗口)
cv2.imshow("Image", img)
cv2.waitKey(0)  # 等待按键按下
cv2.destroyAllWindows()

# 获取图像尺寸
height, width, channels = img.shape
print(f"图像尺寸:{width} x {height}, 通道数:{channels}")

# 保存图像
cv2.imwrite("image_copy.png", img)

4.3 图像转换

import cv2

img = cv2.imread("image.jpg")

# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("image_gray.jpg", img_gray)

# 转换为 HSV 图像
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.imwrite("image_hsv.jpg", img_hsv)

# BGR 转换为 RGB (OpenCV 默认使用 BGR 颜色顺序)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imwrite("image_rgb.jpg", img_rgb)

#RGB to LAB
img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
cv2.imwrite("image_lab.jpg", img_lab)

4.4 图像增强

import cv2
import numpy as np

img = cv2.imread("image.jpg")

# 调整亮度
alpha = 1.5  # 对比度控制 (1.0-3.0)
beta = 50    # 亮度控制 (0-100)
adjusted_img = cv2.convertScaleAbs(img, alpha=alpha, beta=beta)
cv2.imwrite("image_adjusted.jpg", adjusted_img)

# 直方图均衡化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
equalized_img = cv2.equalizeHist(img_gray)
cv2.imwrite("image_equalized.jpg", equalized_img)

# 自适应直方图均衡化 (CLAHE)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_img = clahe.apply(img_gray)
cv2.imwrite("image_clahe.jpg", clahe_img)

4.5 图像滤波

import cv2

img = cv2.imread("image.jpg")

# 高斯滤波
blurred_img = cv2.GaussianBlur(img, (5, 5), 0)  # (5, 5) 是内核大小,0 是标准差
cv2.imwrite("image_gaussian.jpg", blurred_img)

# 中值滤波
median_filtered_img = cv2.medianBlur(img, 5)  # 5 是内核大小
cv2.imwrite("image_median.jpg", median_filtered_img)

# Sobel 边缘检测
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
sobelx = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3)
abs_sobelx = cv2.convertScaleAbs(sobelx)
abs_sobely = cv2.convertScaleAbs(sobely)
edges = cv2.addWeighted(abs_sobelx, 0.5, abs_sobely, 0.5, 0)
cv2.imwrite("image_sobel.jpg", edges)

4.6 形态学操作

import cv2
import numpy as np

img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE) #读取灰度图

# 定义内核
kernel = np.ones((5, 5), np.uint8)

# 腐蚀
erosion = cv2.erode(img, kernel, iterations=1)
cv2.imwrite("image_erosion.jpg", erosion)

# 膨胀
dilation = cv2.dilate(img, kernel, iterations=1)
cv2.imwrite("image_dilation.jpg", dilation)

# 开运算 (先腐蚀后膨胀)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv2.imwrite("image_opening.jpg", opening)

# 闭运算 (先膨胀后腐蚀)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imwrite("image_closing.jpg", closing)

4.7 图像分割

import cv2
import numpy as np

img = cv2.imread("image.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Otsu's 二值化
ret, thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imwrite("image_threshold.jpg", thresh)

# K-means 聚类分割
# 将图像转换为一维数组
pixels = img.reshape((-1, 3))
pixels = np.float32(pixels)

# 定义停止条件
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)

# 应用 K-means
k = 3  # 分成 3 类
_, labels, centers = cv2.kmeans(pixels, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

# 将像素重新塑形为原始图像尺寸
segmented_img = labels.reshape(img.shape[:2])
cv2.imwrite("image_kmeans.jpg", segmented_img * (255 // (k - 1))) #缩放到0-255方便显示

4.8 特征提取

import cv2

img = cv2.imread("image.jpg")
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# SIFT 特征检测
sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(img_gray, None)

# 在图像上绘制关键点
img_with_keypoints = cv2.drawKeypoints(img_gray, keypoints, img)
cv2.imwrite("image_sift.jpg", img_with_keypoints)

# ORB 特征检测
orb = cv2.ORB_create()
keypoints_orb, descriptors_orb = orb.detectAndCompute(img_gray, None)
img_with_keypoints_orb = cv2.drawKeypoints(img_gray, keypoints_orb, img)
cv2.imwrite("image_orb.jpg", img_with_keypoints_orb)

5. 三个库的对比

为了更清晰地了解这三个库的特点,我们用表格进行对比:

特性 Pillow Scikit-image OpenCV
设计目标 易用性,通用图像处理 科学研究,图像分析 实时性,计算机视觉应用
算法丰富度 适中
性能 较好 中等 优异
依赖 无核心依赖 (可选 Tkinter) NumPy, SciPy, Matplotlib NumPy
易用性 非常容易 容易 中等
应用场景 图像格式转换、缩放、裁剪、简单滤镜 图像分割、特征提取、图像分析、科学研究 目标检测、人脸识别、视频处理、实时应用
开发语言 Python, 部分 C 代码 Python, 部分 C 代码 C++, Python

6. 选择合适的库

如何选择合适的库取决于你的具体需求:

  • Pillow: 如果你需要进行简单的图像处理,例如格式转换、缩放、裁剪等,并且希望代码易于编写和理解,那么 Pillow 是一个不错的选择。
  • Scikit-image: 如果你需要进行更复杂的图像分析和科学研究,例如图像分割、特征提取、图像增强等,那么 Scikit-image 提供了丰富的算法和工具。
  • OpenCV: 如果你需要进行实时图像处理或计算机视觉应用,例如目标检测、人脸识别、视频处理等,并且对性能有较高要求,那么 OpenCV 是最佳选择。

当然,在实际应用中,你也可以结合使用这三个库,例如使用 Pillow 进行图像的读取和保存,使用 Scikit-image 进行图像分析,使用 OpenCV 进行实时处理。

7. 实际案例:图像去噪

我们来看一个实际的例子:使用 OpenCV 和 Scikit-image 对图像进行去噪。

import cv2
from skimage import io, restoration

# 使用 OpenCV 进行中值滤波去噪
img_cv = cv2.imread("noisy_image.jpg")
img_cv_median = cv2.medianBlur(img_cv, 5)
cv2.imwrite("denoised_cv_median.jpg", img_cv_median)

# 使用 Scikit-image 进行 TV 去噪 (Total Variation Denoising)
img_sk = io.imread("noisy_image.jpg", as_gray=True) #TV去噪需要灰度图
img_sk_tv = restoration.denoise_tv_chambolle(img_sk, weight=0.1) #权重需要根据图像进行调整
io.imsave("denoised_sk_tv.jpg", img_sk_tv)

在这个例子中,我们使用了 OpenCV 的中值滤波和 Scikit-image 的 TV 去噪算法,分别对图像进行了去噪处理。你可以根据实际情况选择合适的算法和参数。

8. 常见问题与技巧

在实际使用中,可能会遇到一些常见问题,以下是一些建议:

  • 图像格式兼容性: 不同的库可能支持不同的图像格式,需要注意格式转换。
  • 颜色空间: 确保在进行图像处理之前,将图像转换为合适的颜色空间。
  • 数据类型: 不同的算法可能需要不同的数据类型,例如浮点型或整型。
  • 性能优化: 对于性能敏感的应用,可以使用 OpenCV 的 C++ 接口或 NumPy 的向量化操作进行优化。
  • 参数调整: 图像处理算法通常有很多参数需要调整,需要根据实际情况进行尝试。

9. 探索更多的图像处理技术

图像处理是一个非常广泛的领域,还有很多其他的技术值得学习,例如:

  • 深度学习: 使用卷积神经网络 (CNN) 进行图像分类、目标检测、图像分割等。
  • 图像配准: 将多幅图像对齐到同一个坐标系中。
  • 三维重建: 从二维图像中重建三维模型。
  • 视频处理: 对视频进行分析和处理,例如目标跟踪、行为识别等。

10. 选择合适的工具,熟练掌握图像处理技术

我们今天讨论了如何使用 Pillow、Scikit-image 和 OpenCV 进行图像处理。这三个库各有特点和优势,选择合适的库取决于具体的应用场景。希望通过今天的讲解,大家能够对 Python 图像处理有更深入的了解,并在实际应用中灵活运用这些工具。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注