python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python进行图像处理

Python进行图像处理的入门指南

作者:yuanpan

本文介绍了Python图像处理的基础概念、环境搭建、常用操作和实战案例,面向Python初学者从零开始完成一次Python图像处理入门实践,主要使用Pillow和OpenCV两个库,从基本概念到环境搭建,再到常用操作和实战案例,逐步带领读者掌握Python图像处理的技巧

前言

大家好,最近我在学习 Python 图像处理。相比纯算法理论,图像处理最有意思的地方是:代码运行之后马上就能看到效果,一张图片经过裁剪、缩放、灰度化、滤波、边缘检测之后,变化非常直观。

这篇文章面向 Python 初学者,按照“基础概念 → 环境搭建 → 常用操作 → 实战案例 → 完整代码”的路线,带大家从零开始完成一次 Python 图像处理入门实践。

本文主要使用两个常见库:

一、图像处理基础

1.1 什么是图像处理

图像处理就是使用程序对图片进行读取、分析、修改和保存。常见任务包括:

1.2 图像在程序中的表示

一张图片在计算机里本质上是像素矩阵。

彩色 图片通常由三个通道组成:

在 OpenCV 中,默认通道顺序是 BGR,不是常见的 RGB,这是初学者非常容易踩坑的地方。

import cv2

image = cv2.imread("demo.jpg")
print(image.shape)

如果输出:

(600, 800, 3)

表示图片高度为 600,宽度为 800,有 3 个颜色通道。

二、环境搭建

2.1 安装依赖库

在命令提示符或 PowerShell 中执行:

pip install pillow opencv-python numpy matplotlib

各库作用如下:

2.2 准备测试图片

建议准备一张普通图片,例如:

demo.jpg

把图片和 Python 脚本放在同一个文件夹中,方便后续读取。

目录结构可以这样:

image_demo/
├── demo.jpg
└── image_processing_demo.py

三、使用 Pillow 进行基础操作

3.1 打开和保存图片

from PIL import Image

image = Image.open("demo.jpg")
print(image.size)
print(image.mode)

image.save("output_copy.jpg")

说明:

3.2 图片缩放

from PIL import Image

image = Image.open("demo.jpg")
resized = image.resize((400, 300))
resized.save("output_resized.jpg")

如果想按比例缩放,可以这样写:

from PIL import Image

image = Image.open("demo.jpg")
width, height = image.size

new_width = 400
new_height = int(height * new_width / width)

resized = image.resize((new_width, new_height))
resized.save("output_keep_ratio.jpg")

3.3 图片裁剪

from PIL import Image

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

box = (100, 100, 500, 400)
cropped = image.crop(box)

cropped.save("output_cropped.jpg")

crop() 的参数是一个四元组:

(左, 上, 右, 下)

3.4 灰度转换

from PIL import Image

image = Image.open("demo.jpg")
gray = image.convert("L")
gray.save("output_gray.jpg")

L 表示灰度模式,每个像素只保留亮度信息。

四、使用 OpenCV 进行图像处理

4.1 读取和显示图片

import cv2

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

cv2.imshow("image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

注意:

4.2 BGR 转 RGB

OpenCV 默认使用 BGR。如果要用 matplotlib 显示,需要转换为 RGB。

import cv2
import matplotlib.pyplot as plt

image = cv2.imread("demo.jpg")
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

plt.imshow(rgb_image)
plt.axis("off")
plt.show()

4.3 灰度图

import cv2

image = cv2.imread("demo.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

cv2.imwrite("opencv_gray.jpg", gray)

4.4 高斯模糊

高斯模糊常用于降噪,让图片变得更平滑。

import cv2

image = cv2.imread("demo.jpg")
blurred = cv2.GaussianBlur(image, (7, 7), 0)

cv2.imwrite("opencv_blur.jpg", blurred)

参数 (7, 7) 是卷积核大小,必须是正奇数。

4.5 边缘检测

Canny 边缘检测可以提取图片中的轮廓线。

import cv2

image = cv2.imread("demo.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200)

cv2.imwrite("opencv_edges.jpg", edges)

其中 100200 是两个阈值,阈值不同,边缘检测结果也会不同。

五、实战项目一:批量生成缩略图

很多网站或后台系统都需要生成缩略图。下面用 Pillow 批量处理一个文件夹中的图片。

from pathlib import Path
from PIL import Image


def create_thumbnails(input_dir, output_dir, size=(300, 300)):
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    image_exts = [".jpg", ".jpeg", ".png", ".bmp"]

    for file_path in input_path.iterdir():
        if file_path.suffix.lower() not in image_exts:
            continue

        image = Image.open(file_path)
        image.thumbnail(size)

        save_path = output_path / f"{file_path.stem}_thumb.jpg"
        image.convert("RGB").save(save_path, quality=90)
        print(f"已生成缩略图:{save_path}")


create_thumbnails("images", "thumbnails")

thumbnail() 会保持原始比例,不会强行拉伸图片。

六、实战项目二:批量添加文字水印

在图片右下角添加文字水印,是非常常见的批处理需求。

from pathlib import Path
from PIL import Image, ImageDraw, ImageFont


def add_text_watermark(image_path, output_path, text):
    image = Image.open(image_path).convert("RGBA")
    watermark_layer = Image.new("RGBA", image.size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(watermark_layer)

    font = ImageFont.truetype("arial.ttf", 32)
    text_box = draw.textbbox((0, 0), text, font=font)
    text_width = text_box[2] - text_box[0]
    text_height = text_box[3] - text_box[1]

    x = image.width - text_width - 30
    y = image.height - text_height - 30

    draw.text((x, y), text, font=font, fill=(255, 255, 255, 160))

    result = Image.alpha_composite(image, watermark_layer)
    result.convert("RGB").save(output_path, quality=95)


def batch_add_watermark(input_dir, output_dir, text):
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    for file_path in input_path.glob("*.*"):
        if file_path.suffix.lower() not in [".jpg", ".jpeg", ".png"]:
            continue

        save_path = output_path / f"{file_path.stem}_watermark.jpg"
        add_text_watermark(file_path, save_path, text)
        print(f"已添加水印:{save_path}")


batch_add_watermark("images", "watermarked", "Python Image")

如果 arial.ttf 找不到,可以换成 Windows 常见字体路径:

font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", 32)

七、实战项目三:图像边缘检测工具

下面做一个完整的小工具:读取图片、灰度化、模糊降噪、边缘检测,并把每一步结果保存下来。

from pathlib import Path

import cv2


def detect_edges(image_path, output_dir):
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    image = cv2.imread(str(image_path))
    if image is None:
        raise FileNotFoundError(f"图片读取失败:{image_path}")

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edges = cv2.Canny(blurred, 80, 180)

    cv2.imwrite(str(output_path / "01_gray.jpg"), gray)
    cv2.imwrite(str(output_path / "02_blurred.jpg"), blurred)
    cv2.imwrite(str(output_path / "03_edges.jpg"), edges)

    print("处理完成,结果已保存。")


detect_edges("demo.jpg", "edge_output")

这个流程适合用来理解很多视觉任务的前处理步骤。

八、完整代码演示

下面是一份完整代码,整合了图片信息读取、缩放、裁剪、灰度化、模糊、边缘检测、批量缩略图和水印功能。

保存为 image_processing_demo.py

from pathlib import Path

import cv2
from PIL import Image, ImageDraw, ImageFont


IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".bmp"]


def show_image_info(image_path):
    image = Image.open(image_path)
    print("图片路径:", image_path)
    print("图片尺寸:", image.size)
    print("图片模式:", image.mode)
    print("图片格式:", image.format)


def resize_keep_ratio(image_path, output_path, new_width=500):
    image = Image.open(image_path)
    width, height = image.size
    new_height = int(height * new_width / width)
    resized = image.resize((new_width, new_height))
    resized.save(output_path)


def crop_center(image_path, output_path, crop_width=400, crop_height=300):
    image = Image.open(image_path)
    width, height = image.size

    left = (width - crop_width) // 2
    top = (height - crop_height) // 2
    right = left + crop_width
    bottom = top + crop_height

    cropped = image.crop((left, top, right, bottom))
    cropped.save(output_path)


def convert_to_gray(image_path, output_path):
    image = Image.open(image_path)
    gray = image.convert("L")
    gray.save(output_path)


def opencv_blur_and_edges(image_path, output_dir):
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    image = cv2.imread(str(image_path))
    if image is None:
        raise FileNotFoundError(f"图片读取失败:{image_path}")

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edges = cv2.Canny(blurred, 80, 180)

    cv2.imwrite(str(output_path / "gray.jpg"), gray)
    cv2.imwrite(str(output_path / "blurred.jpg"), blurred)
    cv2.imwrite(str(output_path / "edges.jpg"), edges)


def create_thumbnails(input_dir, output_dir, size=(300, 300)):
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    for file_path in input_path.iterdir():
        if file_path.suffix.lower() not in IMAGE_EXTS:
            continue

        image = Image.open(file_path)
        image.thumbnail(size)

        save_path = output_path / f"{file_path.stem}_thumb.jpg"
        image.convert("RGB").save(save_path, quality=90)
        print(f"缩略图已保存:{save_path}")


def load_font(size):
    font_candidates = [
        "C:/Windows/Fonts/msyh.ttc",
        "C:/Windows/Fonts/simhei.ttf",
        "arial.ttf"
    ]

    for font_path in font_candidates:
        if Path(font_path).exists():
            return ImageFont.truetype(font_path, size)

    return ImageFont.load_default()


def add_text_watermark(image_path, output_path, text):
    image = Image.open(image_path).convert("RGBA")
    watermark_layer = Image.new("RGBA", image.size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(watermark_layer)

    font = load_font(32)
    text_box = draw.textbbox((0, 0), text, font=font)
    text_width = text_box[2] - text_box[0]
    text_height = text_box[3] - text_box[1]

    x = image.width - text_width - 30
    y = image.height - text_height - 30

    draw.text((x, y), text, font=font, fill=(255, 255, 255, 160))

    result = Image.alpha_composite(image, watermark_layer)
    result.convert("RGB").save(output_path, quality=95)


def batch_add_watermark(input_dir, output_dir, text):
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    for file_path in input_path.iterdir():
        if file_path.suffix.lower() not in [".jpg", ".jpeg", ".png"]:
            continue

        save_path = output_path / f"{file_path.stem}_watermark.jpg"
        add_text_watermark(file_path, save_path, text)
        print(f"水印图片已保存:{save_path}")


def main():
    demo_image = Path("demo.jpg")

    if not demo_image.exists():
        print("请先在当前目录准备一张 demo.jpg 测试图片。")
        return

    Path("output").mkdir(exist_ok=True)

    show_image_info(demo_image)

    resize_keep_ratio(demo_image, "output/resized.jpg", new_width=500)
    crop_center(demo_image, "output/cropped.jpg", crop_width=400, crop_height=300)
    convert_to_gray(demo_image, "output/gray.jpg")
    opencv_blur_and_edges(demo_image, "output/opencv")
    add_text_watermark(demo_image, "output/watermark.jpg", "Python Image")

    print("基础图像处理完成,结果在 output 文件夹中。")

    if Path("images").exists():
        create_thumbnails("images", "output/thumbnails")
        batch_add_watermark("images", "output/watermarked", "Python Image")
    else:
        print("如果需要批量处理,请创建 images 文件夹并放入图片。")


if __name__ == "__main__":
    main()

九、运行说明

9.1 安装依赖

pip install pillow opencv-python numpy matplotlib

9.2 准备图片

把一张测试图片命名为:

demo.jpg

并和代码文件放在同一个目录。

9.3 运行程序

python image_processing_demo.py

运行后会生成:

output/
├── resized.jpg
├── cropped.jpg
├── gray.jpg
├── watermark.jpg
└── opencv/
    ├── gray.jpg
    ├── blurred.jpg
    └── edges.jpg

如果你创建了 images 文件夹并放入多张图片,程序还会批量生成缩略图和水印图。

十、常见问题与解决方案

10.1 cv2.imread 读取结果是 None

常见原因:

建议先用 Path.exists() 判断文件是否存在。

10.2 OpenCV 显示颜色不对

OpenCV 默认是 BGR,matplotlib 默认按 RGB 显示,所以需要转换:

rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

10.3 水印中文乱码或不显示

通常是字体不支持中文。Windows 下可以使用:

font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", 32)

10.4 保存 JPG 时报错

如果图片是 RGBA 模式,直接保存为 JPG 可能报错,需要先转换为 RGB

image.convert("RGB").save("output.jpg")

十一、图像处理的应用场景

Python 图像处理可以应用在很多实际场景中:

如果继续深入,可以学习:

十二、总结

Python 图像处理是一个非常适合通过实践学习的方向。入门阶段建议先掌握 Pillow 和 OpenCV 的基础用法:

从学习路径上看,可以先做小工具,再做完整项目。比如先写一个图片缩放脚本,再扩展成批量压缩工具;先做边缘检测,再扩展成轮廓提取和目标识别。

保持学习,保持输出。图像处理并不是只能停留在理论里,只要多动手写代码,一张普通图片也可以变成很好的练习素材。

以上就是Python进行图像处理的入门指南的详细内容,更多关于Python进行图像处理的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文