`计算机视觉`:`OpenCV`和`Pillow`在`图像`处理中的`高级`应用。

好的,我们开始吧。

计算机视觉:OpenCV和Pillow在图像处理中的高级应用

各位同学,今天我们深入探讨计算机视觉领域,聚焦于两个强大的Python库:OpenCV和Pillow。 虽然它们都用于图像处理,但它们在设计理念、功能侧重和适用场景上存在显著差异。 本次讲座将讲解它们的高级应用,并通过实际代码示例帮助大家掌握它们的核心功能。

第一部分:OpenCV(cv2)高级应用

OpenCV(Open Source Computer Vision Library)是一个跨平台的计算机视觉库,专注于实时图像处理、视频分析以及机器学习。 其核心是用C/C++编写,提供了Python、Java等语言的接口。

1.1 图像滤波进阶

除了常见的均值滤波、高斯滤波之外,OpenCV还提供了更高级的滤波技术,例如双边滤波和形态学滤波。

  • 双边滤波 (Bilateral Filtering)

    双边滤波是一种非线性滤波技术,它在平滑图像的同时,能够较好地保持边缘信息。 它的核心思想是考虑像素的空间距离和像素值差异,只对空间距离近且像素值相近的像素进行平均。

    import cv2
    import numpy as np
    
    # 读取图像
    img = cv2.imread('image.jpg')
    
    # 双边滤波
    blurred = cv2.bilateralFilter(img, d=9, sigmaColor=75, sigmaSpace=75)
    
    # 显示结果
    cv2.imshow('Original Image', img)
    cv2.imshow('Bilateral Filtered Image', blurred)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    其中,d是滤波器的直径,sigmaColor是颜色空间的标准差,sigmaSpace是坐标空间的标准差。 sigmaColor越大,颜色差异较大的像素也会被纳入平均范围,图像会变得更模糊。 sigmaSpace越大,越多的相邻像素会被纳入平均范围。

  • 形态学滤波 (Morphological Filtering)

    形态学滤波是一组基于图像形状的非线性操作,常用于图像的去噪、分割、特征提取等。 常见的形态学操作包括腐蚀、膨胀、开运算和闭运算。

    • 腐蚀 (Erosion): 腐蚀操作可以消除图像中小的噪声点,并且可以分离图像中粘连的对象。
    • 膨胀 (Dilation): 膨胀操作可以填充图像中小的空洞,并且可以连接图像中分离的对象。
    • 开运算 (Opening): 开运算是先腐蚀后膨胀的操作,可以消除小的噪声点,同时保持图像的整体形状。
    • 闭运算 (Closing): 闭运算是先膨胀后腐蚀的操作,可以填充小的空洞,同时连接相邻的对象。
    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)
    
    # 膨胀
    dilation = cv2.dilate(img, kernel, iterations=1)
    
    # 开运算
    opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
    
    # 闭运算
    closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    
    # 显示结果
    cv2.imshow('Original Image', img)
    cv2.imshow('Erosion', erosion)
    cv2.imshow('Dilation', dilation)
    cv2.imshow('Opening', opening)
    cv2.imshow('Closing', closing)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    kernel是结构元素,它定义了形态学操作的形状和大小。 iterations是操作的迭代次数。

1.2 特征检测与描述

OpenCV提供了多种特征检测和描述算法,例如SIFT、SURF、ORB、以及更现代的KAZE、AKAZE等。

  • ORB (Oriented FAST and Rotated BRIEF)

    ORB是一种快速、鲁棒的特征检测和描述算法,它结合了FAST关键点检测和BRIEF描述符。 ORB具有计算速度快、对旋转和尺度变化具有较好的鲁棒性的优点。

    import cv2
    
    # 读取图像
    img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
    img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
    
    # 创建ORB对象
    orb = cv2.ORB_create()
    
    # 检测关键点和计算描述符
    kp1, des1 = orb.detectAndCompute(img1, None)
    kp2, des2 = orb.detectAndCompute(img2, None)
    
    # 创建BFMatcher对象
    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.imshow('ORB Feature Matching', img3)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    这段代码展示了如何使用ORB算法进行特征检测和描述,并使用BFMatcher进行特征匹配。 cv2.drawMatches函数用于绘制匹配结果。

  • KAZE/AKAZE

    KAZE和AKAZE是基于非线性扩散滤波的特征检测和描述算法。 它们对尺度和旋转变化具有较好的鲁棒性,并且在光照变化和图像模糊的情况下表现良好。 AKAZE是KAZE的加速版本。

    import cv2
    
    # 读取图像
    img1 = cv2.imread('image1.jpg', cv2.IMREAD_GRAYSCALE)
    img2 = cv2.imread('image2.jpg', cv2.IMREAD_GRAYSCALE)
    
    # 创建AKAZE对象
    akaze = cv2.AKAZE_create()
    
    # 检测关键点和计算描述符
    kp1, des1 = akaze.detectAndCompute(img1, None)
    kp2, des2 = akaze.detectAndCompute(img2, None)
    
    # 创建BFMatcher对象
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)  # AKAZE 通常使用 Hamming 距离
    
    # 匹配描述符
    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.imshow('AKAZE Feature Matching', img3)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    注意:AKAZE描述符通常使用Hamming距离进行匹配,因此BFMatcher的normType参数设置为cv2.NORM_HAMMING

1.3 目标检测

OpenCV提供了多种目标检测算法,包括Haar级联检测器、HOG(Histogram of Oriented Gradients)+ SVM、以及基于深度学习的目标检测器(例如YOLO、SSD)。

  • Haar级联检测器 (Haar Cascade Classifiers)

    Haar级联检测器是一种基于 Haar 特征的实时目标检测算法。 它通过训练大量的正负样本,学习到目标的 Haar 特征,然后使用 Adaboost 算法将这些特征组合成一个强分类器。

    import cv2
    
    # 加载 Haar 级联分类器
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    
    # 读取图像
    img = cv2.imread('image.jpg')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 检测人脸
    faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
    
    # 绘制矩形框
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
    
    # 显示结果
    cv2.imshow('Face Detection', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    这段代码使用Haar级联检测器检测图像中的人脸。 haarcascade_frontalface_default.xml是人脸检测器的XML文件,可以从OpenCV的GitHub仓库下载。 detectMultiScale函数用于检测图像中的人脸,scaleFactor是图像缩放因子,minNeighbors是每个候选矩形应该保留的邻居数,minSize是最小的人脸尺寸。

  • 基于深度学习的目标检测器 (YOLO/SSD)

    YOLO (You Only Look Once) 和 SSD (Single Shot MultiBox Detector) 是两种流行的基于深度学习的目标检测算法。 它们具有检测速度快、精度高的优点。 OpenCV 提供了对这些算法的支持,可以通过加载预训练的模型来进行目标检测。

    import cv2
    
    # 加载 YOLO 模型
    net = cv2.dnn.readNet('yolov3.weights', 'yolov3.cfg')
    
    # 加载 COCO 类别名称
    with open('coco.names', 'r') as f:
        classes = [line.strip() for line in f.readlines()]
    
    # 获取输出层名称
    layer_names = net.getLayerNames()
    output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
    
    # 读取图像
    img = cv2.imread('image.jpg')
    height, width, channels = img.shape
    
    # 图像预处理
    blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
    net.setInput(blob)
    outs = net.forward(output_layers)
    
    # 解析输出
    class_ids = []
    confidences = []
    boxes = []
    for out in outs:
        for detection in out:
            scores = detection[5:]
            class_id = np.argmax(scores)
            confidence = scores[class_id]
            if confidence > 0.5:
                # Object detected
                center_x = int(detection[0] * width)
                center_y = int(detection[1] * height)
                w = int(detection[2] * width)
                h = int(detection[3] * height)
    
                # Rectangle coordinate
                x = int(center_x - w / 2)
                y = int(center_y - h / 2)
    
                boxes.append([x, y, w, h])
                confidences.append(float(confidence))
                class_ids.append(class_id)
    
    # 应用非极大值抑制
    indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
    
    # 绘制矩形框
    font = cv2.FONT_HERSHEY_PLAIN
    for i in range(len(boxes)):
        if i in indexes:
            x, y, w, h = boxes[i]
            label = str(classes[class_ids[i]])
            color = (0,255,0)
            cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
            cv2.putText(img, label, (x, y - 5), font, 1, color, 1)
    
    # 显示结果
    cv2.imshow("YOLO Object Detection", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    这段代码使用YOLOv3模型检测图像中的目标。 需要下载yolov3.weightsyolov3.cfg文件,以及coco.names文件,这些文件可以在YOLO的官方网站或其他资源网站找到。 cv2.dnn.blobFromImage函数用于将图像转换为blob格式,net.setInput函数用于设置网络的输入,net.forward函数用于进行前向推理,cv2.dnn.NMSBoxes函数用于应用非极大值抑制。

1.4 视频分析

OpenCV提供了丰富的视频分析功能,例如运动检测、目标跟踪、行为识别等。

  • 运动检测 (Motion Detection)

    运动检测是指检测视频中运动的物体。 一种常用的方法是使用背景建模技术,例如高斯混合模型 (Gaussian Mixture Model, GMM)。

    import cv2
    
    # 创建背景建模对象
    fgbg = cv2.createBackgroundSubtractorMOG2()
    
    # 打开视频文件
    cap = cv2.VideoCapture('video.mp4')
    
    while(1):
        # 读取帧
        ret, frame = cap.read()
    
        if not ret:
            break
    
        # 应用背景建模
        fgmask = fgbg.apply(frame)
    
        # 显示结果
        cv2.imshow('Original Video', frame)
        cv2.imshow('Foreground Mask', fgmask)
    
        k = cv2.waitKey(30) & 0xff
        if k == 27:
            break
    
    # 释放资源
    cap.release()
    cv2.destroyAllWindows()

    这段代码使用高斯混合模型进行背景建模,从而检测视频中的运动物体。 cv2.createBackgroundSubtractorMOG2函数用于创建背景建模对象,fgbg.apply函数用于应用背景建模。

  • 目标跟踪 (Object Tracking)

    OpenCV提供了多种目标跟踪算法,例如MeanShift、CamShift、KCF、以及更现代的CSRT、GOTURN等。

    import cv2
    
    # 打开视频文件
    cap = cv2.VideoCapture('video.mp4')
    
    # 读取第一帧
    ret, frame = cap.read()
    
    # 选择跟踪区域
    bbox = cv2.selectROI(frame, False)
    
    # 初始化跟踪器
    tracker = cv2.TrackerCSRT_create()
    ok = tracker.init(frame, bbox)
    
    while(1):
        # 读取帧
        ret, frame = cap.read()
        if not ret:
            break
    
        # 更新跟踪器
        ok, bbox = tracker.update(frame)
    
        # 绘制矩形框
        if ok:
            # Tracking success
            p1 = (int(bbox[0]), int(bbox[1]))
            p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
            cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
        else :
            # Tracking failure
            cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)
    
        # 显示结果
        cv2.imshow("Tracking", frame)
    
        # 退出
        k = cv2.waitKey(1) & 0xff
        if k == 27 : break
    
    # 释放资源
    cap.release()
    cv2.destroyAllWindows()

    这段代码使用CSRT跟踪器跟踪视频中的目标。 cv2.selectROI函数用于选择跟踪区域,cv2.TrackerCSRT_create函数用于创建CSRT跟踪器,tracker.init函数用于初始化跟踪器,tracker.update函数用于更新跟踪器。

第二部分:Pillow高级应用

Pillow是Python Imaging Library (PIL) 的一个分支,是一个强大的图像处理库。 它提供了广泛的图像处理功能,包括图像格式转换、图像缩放、图像裁剪、图像增强、以及像素级别的操作。 Pillow更侧重于图像处理本身,而非像OpenCV那样侧重于计算机视觉算法。

2.1 图像增强进阶

Pillow 提供了多种图像增强方法,例如色彩平衡、对比度调整、锐化、以及滤镜效果。

  • 色彩平衡 (Color Balance)

    调整图像的色彩平衡可以改变图像的整体色调,使其更加自然或更具艺术感。

    from PIL import Image
    from PIL import ImageEnhance
    
    # 打开图像
    img = Image.open('image.jpg')
    
    # 创建色彩平衡增强器
    enhancer = ImageEnhance.Color(img)
    
    # 增强色彩平衡
    factor = 1.5  # 增强因子
    img_enhanced = enhancer.enhance(factor)
    
    # 显示结果
    img_enhanced.show()

    ImageEnhance.Color类用于创建色彩平衡增强器,enhance方法用于增强色彩平衡。 factor参数控制增强的程度,factor > 1表示增强色彩,factor < 1表示减弱色彩。

  • 锐化 (Sharpening)

    锐化可以增强图像的细节,使其看起来更加清晰。

    from PIL import Image
    from PIL import ImageEnhance
    
    # 打开图像
    img = Image.open('image.jpg')
    
    # 创建锐化增强器
    enhancer = ImageEnhance.Sharpness(img)
    
    # 增强锐化
    factor = 2  # 增强因子
    img_enhanced = enhancer.enhance(factor)
    
    # 显示结果
    img_enhanced.show()

    ImageEnhance.Sharpness类用于创建锐化增强器,enhance方法用于增强锐化。 factor参数控制增强的程度,factor > 1表示增强锐化,factor < 1表示减弱锐化。

  • 滤镜效果 (Filters)

    Pillow 提供了多种滤镜效果,例如模糊、边缘增强、浮雕等。

    from PIL import Image
    from PIL import ImageFilter
    
    # 打开图像
    img = Image.open('image.jpg')
    
    # 应用模糊滤镜
    img_blurred = img.filter(ImageFilter.BLUR)
    
    # 应用边缘增强滤镜
    img_edge_enhanced = img.filter(ImageFilter.EDGE_ENHANCE)
    
    # 应用浮雕滤镜
    img_embossed = img.filter(ImageFilter.EMBOSS)
    
    # 显示结果
    img_blurred.show()
    img_edge_enhanced.show()
    img_embossed.show()

    ImageFilter模块提供了多种滤镜,例如BLUR(模糊)、EDGE_ENHANCE(边缘增强)、EMBOSS(浮雕)等。

2.2 像素级别操作

Pillow 允许我们访问和修改图像的每个像素,从而实现更精细的图像处理。

  • 访问像素 (Accessing Pixels)

    可以使用getpixel方法访问指定位置的像素值,使用putpixel方法修改指定位置的像素值。

    from PIL import Image
    
    # 打开图像
    img = Image.open('image.jpg')
    
    # 获取图像尺寸
    width, height = img.size
    
    # 访问像素
    pixel = img.getpixel((100, 100))  # 获取 (100, 100) 位置的像素值
    print(pixel)
    
    # 修改像素
    img.putpixel((100, 100), (255, 0, 0))  # 将 (100, 100) 位置的像素设置为红色
    
    # 显示结果
    img.show()
  • 图像直方图 (Image Histogram)

    图像直方图是图像像素值的统计分布,可以用于图像分析和图像增强。

    from PIL import Image
    import matplotlib.pyplot as plt
    
    # 打开图像 (灰度图)
    img = Image.open('image.jpg').convert('L')
    
    # 获取直方图
    histogram = img.histogram()
    
    # 绘制直方图
    plt.hist(histogram, bins=256, range=(0, 256))
    plt.show()

    histogram方法返回一个包含256个元素的列表,每个元素表示对应像素值的像素数量。 可以使用matplotlib库绘制直方图。

2.3 图像序列处理

Pillow 支持处理图像序列,例如 GIF 动画和多帧 TIFF 图像。

  • GIF 动画 (GIF Animation)

    可以读取 GIF 动画的每一帧,并进行处理。

    from PIL import Image
    
    # 打开 GIF 动画
    img = Image.open('animation.gif')
    
    # 遍历每一帧
    for i in range(img.n_frames):
        img.seek(i)  # 跳转到指定帧
        frame = img.copy()  # 复制当前帧
        # 对帧进行处理
        # ...
        # frame.save(f'frame_{i}.png') # 保存帧

    img.n_frames属性表示 GIF 动画的帧数,img.seek方法用于跳转到指定帧,img.copy方法用于复制当前帧。

第三部分:OpenCV 与 Pillow 的结合应用

OpenCV 和 Pillow 可以结合使用,发挥各自的优势。 例如,可以使用 OpenCV 进行图像的预处理和特征提取,然后使用 Pillow 进行图像的增强和显示。

import cv2
from PIL import Image

# 使用 OpenCV 读取图像
img_cv = cv2.imread('image.jpg')

# 将 OpenCV 图像转换为 Pillow 图像
img_pil = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))

# 使用 Pillow 进行图像增强
img_pil_enhanced = img_pil.filter(ImageFilter.EDGE_ENHANCE)

# 将 Pillow 图像转换为 OpenCV 图像
img_cv_enhanced = cv2.cvtColor(np.array(img_pil_enhanced), cv2.COLOR_RGB2BGR)

# 使用 OpenCV 显示图像
cv2.imshow('Enhanced Image', img_cv_enhanced)
cv2.waitKey(0)
cv2.destroyAllWindows()

这段代码展示了如何将 OpenCV 图像转换为 Pillow 图像,然后使用 Pillow 进行图像增强,最后将 Pillow 图像转换回 OpenCV 图像。

第四部分:实际案例分析

4.1 案例一:基于OpenCV的车牌识别

车牌识别是一个典型的计算机视觉应用。 我们可以使用OpenCV进行车牌定位、字符分割和字符识别。

  1. 车牌定位: 使用边缘检测、形态学操作等技术提取车牌区域。
  2. 字符分割: 使用投影法或连通域分析等方法分割车牌字符。
  3. 字符识别: 使用机器学习算法(例如SVM、神经网络)识别字符。

(由于篇幅限制,这里只提供思路,详细代码实现较为复杂,需要进行模型训练和参数调整。)

4.2 案例二:基于Pillow的图像水印添加

图像水印可以用于保护图像的版权。 我们可以使用Pillow将水印添加到图像的指定位置。

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

# 打开图像
img = Image.open('image.jpg')

# 创建 Draw 对象
draw = ImageDraw.Draw(img)

# 设置水印文字
text = '© My Company'

# 设置字体
font = ImageFont.truetype('arial.ttf', size=36)  # 需要下载字体文件

# 计算文字位置
text_width, text_height = draw.textsize(text, font=font)
width, height = img.size
x = width - text_width - 10
y = height - text_height - 10

# 添加水印
draw.text((x, y), text, font=font, fill=(255, 255, 255, 128))  # 白色半透明

# 保存图像
img.save('image_with_watermark.png')

# 显示图像
img.show()

这段代码将水印文字添加到图像的右下角。 可以根据需要调整水印的位置、字体、颜色和透明度。

第五部分:选择合适的工具

特性 OpenCV Pillow
主要用途 计算机视觉,实时图像/视频处理 图像处理,格式转换,图像增强
核心语言 C/C++ Python
算法支持 丰富的计算机视觉算法(特征检测、目标检测等) 图像处理算法(滤镜、色彩调整等)
实时性 更好 相对较弱
易用性 相对复杂,需要了解底层原理 简单易用,API友好
适用场景 实时视频分析、机器人视觉、自动驾驶等 图像编辑、图像格式转换、Web图像处理等

选择哪个库取决于你的具体需求。 如果你需要进行实时的计算机视觉处理,OpenCV 是更好的选择。 如果你需要进行简单的图像编辑和格式转换,Pillow 则更加方便易用。 当然,也可以将两者结合使用,发挥各自的优势。

OpenCV专注于计算机视觉算法,Pillow侧重于图像本身的处理,两者的结合能发挥更大的作用。

本次讲座到此结束,谢谢大家。

发表回复

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