`Python`的`图像`处理:`Pillow`和`OpenCV`的`高级`用法。

好的,我们开始今天的讲座,主题是Python图像处理中Pillow和OpenCV的高级用法。

Pillow高级用法

Pillow是Python Imaging Library (PIL) 的一个分支,它提供了广泛的图像处理能力。虽然基础用法如打开、保存、调整大小等比较常见,但Pillow的高级用法涉及更多图像操作和算法。

  • 图像模式转换:

    Pillow允许在不同的图像模式之间进行转换。常见的模式包括:

    • L: 灰度图像
    • RGB: 彩色图像
    • RGBA: 彩色图像,带透明度
    • CMYK: 用于印刷的彩色图像
    from PIL import Image
    
    img = Image.open("example.png") # 假设example.png是RGB图像
    img_gray = img.convert("L")
    img_rgba = img.convert("RGBA")
    img_cmyk = img.convert("CMYK")
    
    img_gray.save("example_gray.png")
    img_rgba.save("example_rgba.png")
    img_cmyk.save("example_cmyk.png")
    
    print(f"Original mode: {img.mode}")
    print(f"Gray mode: {img_gray.mode}")
    print(f"RGBA mode: {img_rgba.mode}")
    print(f"CMYK mode: {img_cmyk.mode}")

    图像模式转换在很多场景下非常有用,比如将彩色图像转换为灰度图像进行特征提取,或者为图像添加透明度图层。注意,转换过程中可能会有信息损失,比如从RGB转换为灰度时会丢失颜色信息。

  • 颜色处理:

    Pillow提供了多种颜色处理功能,包括颜色分离、颜色增强、色彩平衡等。

    • 颜色分离: 将图像的颜色通道分离出来。

      from PIL import Image
      
      img = Image.open("example.png")
      r, g, b = img.split()
      
      r.save("red_channel.png")
      g.save("green_channel.png")
      b.save("blue_channel.png")
    • 颜色合并: 将分离的颜色通道重新合并。

      from PIL import Image
      
      r = Image.open("red_channel.png")
      g = Image.open("green_channel.png")
      b = Image.open("blue_channel.png")
      
      img = Image.merge("RGB", (r, g, b))
      img.save("merged_image.png")
    • 颜色增强: 使用ImageEnhance模块调整图像的色彩、亮度、对比度等。

      from PIL import Image, ImageEnhance
      
      img = Image.open("example.png")
      
      # 亮度增强
      enhancer = ImageEnhance.Brightness(img)
      bright_img = enhancer.enhance(1.5) # 1.0是原始亮度
      
      # 对比度增强
      enhancer = ImageEnhance.Contrast(img)
      contrast_img = enhancer.enhance(1.2) # 1.0是原始对比度
      
      # 色彩增强
      enhancer = ImageEnhance.Color(img)
      color_img = enhancer.enhance(1.3) # 1.0是原始色彩
      
      # 锐度增强
      enhancer = ImageEnhance.Sharpness(img)
      sharp_img = enhancer.enhance(2.0) # 1.0是原始锐度
      
      bright_img.save("brightened_image.png")
      contrast_img.save("contrast_image.png")
      color_img.save("color_image.png")
      sharp_img.save("sharp_image.png")
  • 图像滤镜:

    Pillow提供了多种内置的图像滤镜,可以用于模糊、锐化、边缘检测等操作。

    from PIL import Image, ImageFilter
    
    img = Image.open("example.png")
    
    # 模糊滤镜
    blur_img = img.filter(ImageFilter.BLUR)
    
    # 锐化滤镜
    sharpen_img = img.filter(ImageFilter.SHARPEN)
    
    # 边缘增强滤镜
    edge_enhance_img = img.filter(ImageFilter.EDGE_ENHANCE)
    
    # 查找边缘滤镜
    find_edges_img = img.filter(ImageFilter.FIND_EDGES)
    
    # 高斯模糊滤镜
    gaussian_blur_img = img.filter(ImageFilter.GaussianBlur(radius=2))
    
    blur_img.save("blurred_image.png")
    sharpen_img.save("sharpened_image.png")
    edge_enhance_img.save("edge_enhanced_image.png")
    find_edges_img.save("find_edges_image.png")
    gaussian_blur_img.save("gaussian_blurred_image.png")
  • 图像几何变换:

    Pillow提供了旋转、缩放、裁剪、透视变换等几何变换功能。

    from PIL import Image
    
    img = Image.open("example.png")
    
    # 旋转
    rotated_img = img.rotate(45) # 逆时针旋转45度
    
    # 缩放
    resized_img = img.resize((200, 100)) # 调整为200x100像素
    
    # 裁剪
    cropped_img = img.crop((50, 50, 150, 150)) # 裁剪区域 (左上角x, 左上角y, 右下角x, 右下角y)
    
    # 透视变换
    width, height = img.size
    points = [
        (0, 0), (width, 0), (width, height), (0, height)
    ] # 原图的四个角点
    target_points = [
        (50, 50), (width - 50, 20), (width - 20, height - 50), (20, height - 20)
    ] # 变换后的四个角点
    
    # 使用PIL无法直接进行透视变换,通常需要结合其他库或者自己实现算法
    # 这里仅展示如何获取变换矩阵,实际变换需要额外的代码
    # 详见:https://stackoverflow.com/questions/2924701/pil-perspective-transform
    
    rotated_img.save("rotated_image.png")
    resized_img.save("resized_image.png")
    cropped_img.save("cropped_image.png")
  • 像素操作:

    Pillow允许直接访问和修改图像的像素数据。

    from PIL import Image
    
    img = Image.open("example.png")
    pixels = img.load() # 获取像素数据对象
    
    width, height = img.size
    
    # 将图像的左上角10x10区域设置为红色
    for x in range(10):
        for y in range(10):
            pixels[x, y] = (255, 0, 0) # RGB
    
    img.save("pixel_modified_image.png")

    直接操作像素数据可以实现更复杂的图像处理算法,比如图像二值化、边缘检测等。但是,这种方式通常比使用内置函数效率低,尤其是在处理大图像时。

  • 图像序列处理 (GIF动画):

    Pillow可以用来创建、修改和读取GIF动画。

    from PIL import Image
    
    # 创建GIF动画
    frames = []
    for i in range(10):
        img = Image.new("RGB", (100, 100), (i * 25, i * 25, i * 25))
        frames.append(img)
    
    frames[0].save("animation.gif", save_all=True, append_images=frames[1:], loop=0, duration=100) # duration单位是毫秒
    
    # 读取GIF动画
    gif_img = Image.open("animation.gif")
    for i in range(gif_img.n_frames):
        gif_img.seek(i)
        frame = gif_img.copy()
        frame.save(f"frame_{i}.png")
    

    save_all=True 表示保存所有帧。append_images 参数指定要添加到GIF中的图像序列。loop=0 表示无限循环播放。 duration 指定每帧的显示时间,单位是毫秒。 gif_img.n_frames 表示GIF动画的帧数。gif_img.seek(i) 移动到第i帧。

OpenCV高级用法

OpenCV (Open Source Computer Vision Library) 是一个强大的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。

  • 图像滤波:

    OpenCV提供了多种图像滤波方法,包括均值滤波、高斯滤波、中值滤波、双边滤波等。

    import cv2
    import numpy as np
    
    img = cv2.imread("example.png")
    
    # 均值滤波
    blur_img = cv2.blur(img, (5, 5)) # (5, 5)是卷积核大小
    
    # 高斯滤波
    gaussian_blur_img = cv2.GaussianBlur(img, (5, 5), 0) # 0是标准差,可以自动计算
    
    # 中值滤波
    median_blur_img = cv2.medianBlur(img, 5) # 5是卷积核大小,必须是奇数
    
    # 双边滤波
    bilateral_filter_img = cv2.bilateralFilter(img, 9, 75, 75) # 9是像素邻域直径,75是颜色和空间sigma
    
    cv2.imwrite("blur_image.png", blur_img)
    cv2.imwrite("gaussian_blur_image.png", gaussian_blur_img)
    cv2.imwrite("median_blur_image.png", median_blur_img)
    cv2.imwrite("bilateral_filter_image.png", bilateral_filter_img)

    不同的滤波方法适用于不同的场景。均值滤波和高斯滤波适用于去除图像中的噪声,但会模糊图像的细节。中值滤波对椒盐噪声有很好的去除效果。双边滤波在去除噪声的同时,可以保留图像的边缘信息。

  • 边缘检测:

    OpenCV提供了多种边缘检测算法,包括Sobel算子、Laplacian算子、Canny边缘检测等。

    import cv2
    import numpy as np
    
    img = cv2.imread("example.png", cv2.IMREAD_GRAYSCALE) # 读取为灰度图像
    
    # Sobel算子
    sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) # x方向梯度
    sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3) # y方向梯度
    abs_sobelx = np.absolute(sobelx)
    abs_sobely = np.absolute(sobely)
    sobelx = np.uint8(abs_sobelx)
    sobely = np.uint8(abs_sobely)
    
    # Laplacian算子
    laplacian = cv2.Laplacian(img, cv2.CV_64F)
    abs_laplacian = np.absolute(laplacian)
    laplacian = np.uint8(abs_laplacian)
    
    # Canny边缘检测
    canny = cv2.Canny(img, 100, 200) # 100和200是阈值
    
    cv2.imwrite("sobelx_image.png", sobelx)
    cv2.imwrite("sobely_image.png", sobely)
    cv2.imwrite("laplacian_image.png", laplacian)
    cv2.imwrite("canny_image.png", canny)

    Sobel算子用于计算图像的梯度,可以检测水平和垂直方向的边缘。Laplacian算子用于计算图像的二阶导数,可以检测图像中的细节。Canny边缘检测是一种经典的边缘检测算法,它结合了多种技术,可以有效地检测图像中的边缘。注意,Canny检测通常需要调整阈值来获得最佳效果。

  • 图像分割:

    OpenCV提供了多种图像分割方法,包括阈值分割、区域生长、分水岭算法等。

    • 阈值分割:

      import cv2
      import numpy as np
      
      img = cv2.imread("example.png", cv2.IMREAD_GRAYSCALE)
      
      # 简单阈值
      ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
      ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
      ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
      ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
      ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)
      
      # 自适应阈值
      thresh6 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
      thresh7 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
      
      cv2.imwrite("thresh1_image.png", thresh1)
      cv2.imwrite("thresh2_image.png", thresh2)
      cv2.imwrite("thresh3_image.png", thresh3)
      cv2.imwrite("thresh4_image.png", thresh4)
      cv2.imwrite("thresh5_image.png", thresh5)
      cv2.imwrite("thresh6_image.png", thresh6)
      cv2.imwrite("thresh7_image.png", thresh7)

      简单阈值使用固定的阈值进行分割。自适应阈值根据图像的局部特性动态地调整阈值。cv2.ADAPTIVE_THRESH_MEAN_C 使用邻域的平均值作为阈值。cv2.ADAPTIVE_THRESH_GAUSSIAN_C 使用邻域的加权平均值(高斯分布)作为阈值。

    • K-means 聚类分割:

      import cv2
      import numpy as np
      
      img = cv2.imread("example.png")
      Z = img.reshape((-1,3))
      
      # convert to np.float32
      Z = np.float32(Z)
      
      # define criteria, number of clusters(K) and apply kmeans()
      criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
      K = 3
      ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
      
      # Now convert back into uint8, and make original image
      center = np.uint8(center)
      res = center[label.flatten()]
      res2 = res.reshape((img.shape))
      
      cv2.imwrite("kmeans_image.png", res2)

      该方法首先将图像转换为一个像素点的数组,然后使用K-means算法将像素点聚类成K个簇,最后将每个簇的像素点替换为该簇的中心颜色。

  • 特征检测和匹配:

    OpenCV提供了多种特征检测和匹配算法,包括SIFT、SURF、ORB等。

    import cv2
    
    img1 = cv2.imread("image1.png", cv2.IMREAD_GRAYSCALE)
    img2 = cv2.imread("image2.png", cv2.IMREAD_GRAYSCALE)
    
    # ORB特征检测
    orb = cv2.ORB_create()
    kp1, des1 = orb.detectAndCompute(img1, None)
    kp2, des2 = orb.detectAndCompute(img2, None)
    
    # 特征匹配
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = bf.match(des1, des2)
    matches = sorted(matches, key=lambda x: x.distance)
    
    # 绘制匹配结果
    img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
    
    cv2.imwrite("orb_matches.png", img3)

    ORB是一种快速的特征检测和匹配算法,适用于实时应用。cv2.BFMatcher 是暴力匹配器,cv2.NORM_HAMMING 是汉明距离,适用于二进制描述子(如ORB)。crossCheck=True 表示进行交叉验证,提高匹配的准确性。

  • 目标检测:

    OpenCV提供了多种目标检测算法,包括Haar级联分类器、HOG+SVM、以及基于深度学习的目标检测模型。

    • Haar级联分类器:

      import cv2
      
      face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") # 加载人脸检测器
      
      img = cv2.imread("example.png")
      gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
      
      faces = face_cascade.detectMultiScale(gray, 1.1, 4) # 检测人脸
      
      for (x, y, w, h) in faces:
          cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2) # 绘制矩形框
      
      cv2.imwrite("face_detection.png", img)

      Haar级联分类器是一种基于机器学习的目标检测方法,它使用Haar特征和Adaboost算法进行训练。OpenCV提供了预训练的人脸检测器。detectMultiScale 函数可以检测图像中不同大小的目标。

    • 使用预训练的深度学习模型 (DNN):

      import cv2
      
      # Load the pre-trained model and configuration
      net = cv2.dnn.readNetFromCaffe("deploy.prototxt", "res10_300x300_ssd_iter_140000.caffemodel")
      
      # Load the image
      img = cv2.imread("example.png")
      h, w = img.shape[:2]
      
      # Preprocess the image
      blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)), 1.0,
                                   (300, 300), (104.0, 177.0, 123.0))
      
      # Set the input blob for the network
      net.setInput(blob)
      
      # Make the detections
      detections = net.forward()
      
      # Loop over the detections
      for i in range(detections.shape[2]):
          confidence = detections[0, 0, i, 2]
          if confidence > 0.5:  # Filter detections by confidence
              box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
              (startX, startY, endX, endY) = box.astype("int")
      
              # Draw the bounding box and confidence
              text = "{:.2f}%".format(confidence * 100)
              y = startY - 10 if startY - 10 > 10 else startY + 10
              cv2.rectangle(img, (startX, startY), (endX, endY), (0, 0, 255), 2)
              cv2.putText(img, text, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)
      
      cv2.imwrite("dnn_face_detection.png", img)

      这段代码使用基于Caffe框架的预训练的深度学习模型来检测人脸。cv2.dnn.readNetFromCaffe 函数用于加载模型。cv2.dnn.blobFromImage 函数用于将图像转换为blob格式,这是深度学习模型需要的输入格式。

  • 视频处理:

    OpenCV可以用于处理视频流,包括视频读取、视频写入、视频分析等。

    import cv2
    
    # 打开视频文件
    cap = cv2.VideoCapture("video.mp4")
    
    # 获取视频帧率和大小
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    
    # 创建视频写入对象
    fourcc = cv2.VideoWriter_fourcc(*"mp4v") # 编码格式
    out = cv2.VideoWriter("output.mp4", fourcc, fps, (width, height))
    
    while(cap.isOpened()):
        ret, frame = cap.read() # 读取一帧
    
        if ret == True:
            # 在这里进行图像处理
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            out.write(gray) # 写入处理后的帧
    
            # 显示视频
            cv2.imshow("frame", gray)
            if cv2.waitKey(1) & 0xFF == ord("q"): # 按q键退出
                break
        else:
            break
    
    # 释放资源
    cap.release()
    out.release()
    cv2.destroyAllWindows()

    这段代码读取一个视频文件,将每一帧转换为灰度图像,然后将处理后的帧写入到新的视频文件中。cv2.VideoCapture 用于打开视频文件。cap.read() 用于读取一帧。cv2.VideoWriter 用于创建视频写入对象。cv2.waitKey(1) 用于等待1毫秒,并检测键盘输入。

Pillow与OpenCV的对比和选择

Pillow和OpenCV都是强大的图像处理库,但它们在功能和应用场景上有所不同。

特性 Pillow OpenCV
主要功能 图像格式支持、基本图像处理、颜色处理 计算机视觉算法、图像分析、视频处理
易用性 简单易用,API设计清晰 功能强大,但API较为复杂
性能 相对较低 较高,尤其是在C++接口下
应用场景 图像格式转换、简单图像编辑、Web图像处理 计算机视觉应用、目标检测、视频监控、机器人

总的来说,如果你的应用场景主要是图像格式转换、简单的图像编辑或者Web图像处理,Pillow是一个不错的选择。如果你的应用场景涉及到计算机视觉算法、目标检测、视频处理等,OpenCV则是更好的选择。在一些复杂的应用中,你也可以将Pillow和OpenCV结合使用,例如使用Pillow读取图像,然后使用OpenCV进行图像分析。

图像处理库的选择取决于具体需求,两者各有优势。

代码示例:结合使用Pillow和OpenCV

from PIL import Image
import cv2
import numpy as np

# 使用Pillow读取图像
pil_img = Image.open("example.png")

# 将Pillow图像转换为OpenCV图像
cv_img = np.array(pil_img)
cv_img = cv_img[:, :, ::-1].copy() # RGB to BGR

# 使用OpenCV进行图像处理
gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200)

# 将OpenCV图像转换为Pillow图像
pil_edges = Image.fromarray(edges)

# 保存处理后的图像
pil_edges.save("edges.png")

这段代码演示了如何将Pillow图像转换为OpenCV图像,然后使用OpenCV进行边缘检测,最后将结果保存为Pillow图像。注意,Pillow使用RGB颜色顺序,而OpenCV使用BGR颜色顺序,因此需要进行颜色通道的转换。

图像处理流程的一般步骤

  1. 图像获取: 从文件、摄像头或其他来源读取图像。
  2. 预处理: 对图像进行预处理,例如调整大小、裁剪、灰度化、降噪等。
  3. 特征提取: 提取图像的特征,例如边缘、角点、纹理等。
  4. 分析与识别: 使用提取的特征进行图像分析和识别,例如目标检测、图像分类、图像分割等。
  5. 后处理: 对分析结果进行后处理,例如平滑、去噪、校正等。
  6. 结果展示与存储: 将处理结果展示给用户,并将结果保存到文件或数据库中。

掌握基础是关键,不断实践才能深入理解图像处理。

发表回复

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