好的,我们开始今天的讲座,主题是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颜色顺序,因此需要进行颜色通道的转换。
图像处理流程的一般步骤
- 图像获取: 从文件、摄像头或其他来源读取图像。
- 预处理: 对图像进行预处理,例如调整大小、裁剪、灰度化、降噪等。
- 特征提取: 提取图像的特征,例如边缘、角点、纹理等。
- 分析与识别: 使用提取的特征进行图像分析和识别,例如目标检测、图像分类、图像分割等。
- 后处理: 对分析结果进行后处理,例如平滑、去噪、校正等。
- 结果展示与存储: 将处理结果展示给用户,并将结果保存到文件或数据库中。
掌握基础是关键,不断实践才能深入理解图像处理。