2024-11-27

【Python】OpenCV—Color Map

在计算机视觉和图像处理领域,色彩图(Color Map)是一种常见的技术,用于将灰度图像的灰度值映射为不同的颜色,从而提高图像的可视化效果。在 OpenCV 中,cv2.applyColorMap() 函数可以将图像的灰度值转换为多种颜色。本文将详细讲解 OpenCV 中的色彩图(Color Map)及其应用,包括如何使用不同的色彩图来提升图像的视觉效果。

一、什么是色彩图(Color Map)

色彩图是灰度图像和颜色图像之间的桥梁,它通过将每个像素的灰度值映射到某个特定的颜色,来增强图像的信息表达。在许多视觉任务中,色彩图可以帮助我们更好地理解图像数据。

OpenCV 提供了多种内置的色彩图,例如:

  • COLORMAP_JET:常用于热力图,表示从冷到热的颜色渐变。
  • COLORMAP_HSV:根据颜色的 HSV 色调生成映射。
  • COLORMAP_COOLCOLORMAP_SPRINGCOLORMAP_OCEAN 等:这些映射颜色风格各异。

在 OpenCV 中,使用 cv2.applyColorMap() 函数可以很方便地应用这些色彩图。

二、色彩图的应用场景

色彩图通常用于:

  • 热力图显示:通过将灰度值映射为颜色,可以有效展示数据的分布和密度。
  • 医学图像分析:例如,将 X 光片或 CT 扫描的灰度图转换为颜色图,帮助医生更容易地分析异常区域。
  • 科学可视化:在数据可视化和图像分析中,色彩图常用于展示不同的数值范围,增加可读性。

三、OpenCV中的Color Map使用方法

1. 导入必要的库

首先,需要导入 cv2matplotlib 库来加载图像并展示结果:

import cv2
import numpy as np
import matplotlib.pyplot as plt

2. 加载图像并转换为灰度图

色彩图只能应用于灰度图像,因此我们需要将图像转换为灰度图。

# 读取图像
image = cv2.imread('your_image.jpg')

# 将图像转换为灰度图
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 展示灰度图
plt.imshow(gray_image, cmap='gray')
plt.title('Original Gray Image')
plt.axis('off')  # 不显示坐标轴
plt.show()

3. 使用 applyColorMap() 应用不同的色彩图

OpenCV 提供了多种色彩图,可以通过 cv2.applyColorMap() 函数来应用。下面的代码展示了如何将灰度图应用不同的色彩图。

# 使用不同的色彩图
color_mapped_image_jet = cv2.applyColorMap(gray_image, cv2.COLORMAP_JET)
color_mapped_image_hsv = cv2.applyColorMap(gray_image, cv2.COLORMAP_HSV)
color_mapped_image_ocean = cv2.applyColorMap(gray_image, cv2.COLORMAP_OCEAN)

# 展示色彩图效果
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].imshow(color_mapped_image_jet)
axes[0].set_title('Jet Color Map')
axes[0].axis('off')

axes[1].imshow(color_mapped_image_hsv)
axes[1].set_title('HSV Color Map')
axes[1].axis('off')

axes[2].imshow(color_mapped_image_ocean)
axes[2].set_title('Ocean Color Map')
axes[2].axis('off')

plt.show()

4. 不同色彩图效果展示

下面是几种常见的色彩图效果:

  • JET:这种色彩图通常用于热力图,显示从蓝色(低值)到红色(高值)的渐变。

    JET Color MapJET Color Map

  • HSV:这是基于色调(Hue)、饱和度(Saturation)和亮度(Value)创建的色彩图。
  • OCEAN:这种色彩图具有平和的冷色调,适合表示水域或低温区域。

5. 自定义色彩图

OpenCV 还支持自定义色彩图。例如,你可以创建自己的调色板并使用它。以下是如何定义一个自定义色彩图并应用它的示例。

# 创建一个自定义色彩图
custom_color_map = np.zeros((256, 1, 3), dtype=np.uint8)

# 定义自定义颜色映射(从黑色到红色)
for i in range(256):
    custom_color_map[i] = [i, 0, 0]  # Red component varies from 0 to 255

# 应用自定义色彩图
custom_color_mapped_image = cv2.applyColorMap(gray_image, custom_color_map)

# 展示自定义色彩图
plt.imshow(custom_color_mapped_image)
plt.title('Custom Color Map')
plt.axis('off')
plt.show()

四、图解示例

1. 原始灰度图像

我们使用一张简单的灰度图像来展示不同的色彩图效果。

# 读取一张灰度图(可以使用自己的图片)
gray_image = np.random.randint(0, 256, (300, 300), dtype=np.uint8)

# 展示灰度图像
plt.imshow(gray_image, cmap='gray')
plt.title('Original Grayscale Image')
plt.axis('off')
plt.show()

2. 应用 JET 色彩图

jet_image = cv2.applyColorMap(gray_image, cv2.COLORMAP_JET)
plt.imshow(jet_image)
plt.title('Jet Color Map')
plt.axis('off')
plt.show()

3. 应用 HSV 色彩图

hsv_image = cv2.applyColorMap(gray_image, cv2.COLORMAP_HSV)
plt.imshow(hsv_image)
plt.title('HSV Color Map')
plt.axis('off')
plt.show()

4. 应用 OCEAN 色彩图

ocean_image = cv2.applyColorMap(gray_image, cv2.COLORMAP_OCEAN)
plt.imshow(ocean_image)
plt.title('Ocean Color Map')
plt.axis('off')
plt.show()

五、总结

在计算机视觉中,色彩图是一种非常实用的技术,可以帮助我们更好地可视化灰度图像或热力图。OpenCV 提供了多种内置色彩图,并且可以通过 cv2.applyColorMap() 快速应用。在一些科学、医学和工程领域,色彩图常用于提升图像的可视化效果,使得数据的表达更加直观。

2024-11-27

Python 神器:一键下载 M3U8 并转换为 MP4

M3U8 是一种常见的媒体播放文件格式,通常用于视频流的播放,例如通过 HTTP Live Streaming (HLS) 协议传输的视频流。本文将介绍如何使用 Python 下载 M3U8 文件中的所有视频片段,并将它们合并为一个 MP4 文件。

一、前期准备

1. 安装依赖

我们需要使用几个 Python 库来实现下载和合并 M3U8 文件中的视频片段。最主要的库包括 m3u8(用于解析 M3U8 文件)和 ffmpeg(用于视频合并和转码)。同时,我们还需要 requests 库来下载 M3U8 文件中的 TS 视频片段。

首先,安装依赖库:

pip install m3u8 requests

安装 ffmpeg(用于视频处理):

  • 对于 Windows 用户,可以从 FFmpeg官网 下载并安装。
  • 对于 MacOS 用户,可以使用 Homebrew 安装:

    brew install ffmpeg
  • 对于 Linux 用户,可以使用 apt-get 安装:

    sudo apt install ffmpeg

二、M3U8 下载与转换实现

1. 下载 M3U8 文件并解析

M3U8 文件实际上包含了视频的索引信息,指示了所有的 .ts 文件(视频片段)的位置。我们可以用 m3u8 库来解析 M3U8 文件,获取其中的视频片段 URL。

import m3u8
import os
import requests

def download_m3u8(m3u8_url, download_folder):
    """
    下载并解析 M3U8 文件
    :param m3u8_url: M3U8 文件 URL
    :param download_folder: 下载的文件保存目录
    :return: 视频片段 URL 列表
    """
    # 解析 M3U8 文件
    playlist = m3u8.load(m3u8_url)
    ts_urls = []

    # 遍历 M3U8 中的每个片段 URL
    for segment in playlist.segments:
        ts_urls.append(segment.uri)

    # 下载视频片段
    if not os.path.exists(download_folder):
        os.makedirs(download_folder)
    
    ts_files = []
    for idx, ts_url in enumerate(ts_urls):
        ts_filename = os.path.join(download_folder, f"segment{idx + 1}.ts")
        ts_files.append(ts_filename)
        print(f"正在下载:{ts_url}")
        response = requests.get(ts_url, stream=True)
        with open(ts_filename, 'wb') as f:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:
                    f.write(chunk)
    
    print("所有视频片段下载完成!")
    return ts_files

# 示例用法
m3u8_url = "https://example.com/video.m3u8"
download_folder = "downloaded_video"
ts_files = download_m3u8(m3u8_url, download_folder)

2. 合并 TS 文件并转换为 MP4

下载所有的 .ts 文件后,我们可以使用 ffmpeg 来将这些视频片段合并成一个 MP4 文件。

import subprocess

def ts_to_mp4(ts_files, output_file):
    """
    使用 ffmpeg 将多个 TS 文件合并并转换为 MP4
    :param ts_files: TS 文件路径列表
    :param output_file: 输出的 MP4 文件路径
    """
    # 生成合并文件的文本
    merge_file = "merge_list.txt"
    with open(merge_file, "w") as f:
        for ts_file in ts_files:
            f.write(f"file '{ts_file}'\n")

    # 使用 ffmpeg 合并 TS 文件
    command = f"ffmpeg -f concat -safe 0 -i {merge_file} -c copy {output_file}"
    print(f"正在合并视频文件到 {output_file}...")
    subprocess.run(command, shell=True)
    
    # 删除临时合并文件列表
    os.remove(merge_file)
    print(f"视频已成功合并为: {output_file}")

# 示例用法
output_file = "output_video.mp4"
ts_to_mp4(ts_files, output_file)

3. 完整代码实现

将上述代码整合,得到一个完整的脚本,用于下载 M3U8 文件中的视频片段,并合并为 MP4 文件。

import m3u8
import os
import requests
import subprocess

def download_m3u8(m3u8_url, download_folder):
    playlist = m3u8.load(m3u8_url)
    ts_urls = []

    for segment in playlist.segments:
        ts_urls.append(segment.uri)

    if not os.path.exists(download_folder):
        os.makedirs(download_folder)
    
    ts_files = []
    for idx, ts_url in enumerate(ts_urls):
        ts_filename = os.path.join(download_folder, f"segment{idx + 1}.ts")
        ts_files.append(ts_filename)
        print(f"正在下载:{ts_url}")
        response = requests.get(ts_url, stream=True)
        with open(ts_filename, 'wb') as f:
            for chunk in response.iter_content(chunk_size=1024):
                if chunk:
                    f.write(chunk)
    
    print("所有视频片段下载完成!")
    return ts_files

def ts_to_mp4(ts_files, output_file):
    merge_file = "merge_list.txt"
    with open(merge_file, "w") as f:
        for ts_file in ts_files:
            f.write(f"file '{ts_file}'\n")

    command = f"ffmpeg -f concat -safe 0 -i {merge_file} -c copy {output_file}"
    print(f"正在合并视频文件到 {output_file}...")
    subprocess.run(command, shell=True)
    
    os.remove(merge_file)
    print(f"视频已成功合并为: {output_file}")

if __name__ == "__main__":
    m3u8_url = "https://example.com/video.m3u8"  # M3U8 文件 URL
    download_folder = "downloaded_video"        # 下载文件夹
    output_file = "output_video.mp4"            # 输出 MP4 文件

    ts_files = download_m3u8(m3u8_url, download_folder)
    ts_to_mp4(ts_files, output_file)

四、效果展示

  1. 输入:M3U8 文件 URL,如 https://example.com/video.m3u8
  2. 输出:一个 MP4 文件,包含合并后的完整视频。

五、注意事项

  1. M3U8 文件的格式:M3U8 文件中可以有不同的质量版本,可能需要选择合适的版本来下载。
  2. 视频大小:M3U8 通常是大视频流的分割文件,下载时需要稳定的网络连接。
  3. ffmpeg 配置:确保 ffmpeg 已正确安装并在系统环境变量中。

六、总结

通过本文的教程,你可以轻松实现一键下载 M3U8 文件中的所有视频片段,并将它们合并为一个 MP4 文件。这个工具适用于需要下载和处理 HLS 流的场景,操作简便且高效。

2024-11-27

一键智能视频语音转文本

——基于 PaddlePaddle 语音识别与 Python 轻松提取视频语音并生成文案

随着人工智能技术的不断进步,语音识别的应用场景越来越广泛。本文将详细介绍如何基于 PaddlePaddle 语音识别 框架,结合 Python 提取视频中的语音并生成对应的文本文案。


一、技术原理

1. 视频语音转文本的步骤

  1. 提取视频中的音频:通过 Python 的第三方库(如 moviepy)分离视频文件中的音频部分。
  2. 音频处理:将音频转为模型支持的格式(如 PCM、WAV)。
  3. 语音识别:使用 PaddleSpeech 提供的预训练语音识别模型,将音频转化为文本。
  4. 文案生成:将识别结果格式化,生成可用的文案内容。

二、环境准备

1. 安装必要依赖

首先,安装以下 Python 库:

pip install paddlepaddle paddlespeech moviepy soundfile
  • PaddlePaddle:深度学习框架,用于加载和运行语音模型。
  • PaddleSpeech:PaddlePaddle 的语音处理工具包,支持语音识别、合成等功能。
  • MoviePy:视频处理库,用于提取音频。
  • SoundFile:音频处理库,用于转换音频格式。

三、代码实现

1. 提取视频中的音频

使用 MoviePy 分离视频中的音频:

from moviepy.editor import VideoFileClip

def extract_audio(video_path, audio_output_path):
    """
    从视频中提取音频
    :param video_path: 输入视频路径
    :param audio_output_path: 输出音频文件路径
    """
    video = VideoFileClip(video_path)
    video.audio.write_audiofile(audio_output_path)
    print(f"音频已保存至: {audio_output_path}")

# 示例用法
extract_audio("sample_video.mp4", "audio_output.wav")

2. 使用 PaddleSpeech 进行语音识别

from paddlespeech.cli.asr import ASRExecutor

def audio_to_text(audio_path):
    """
    将音频转换为文本
    :param audio_path: 输入音频文件路径
    :return: 识别结果文本
    """
    asr = ASRExecutor()
    result = asr(audio_file=audio_path)
    print("语音识别结果:", result)
    return result

# 示例用法
text = audio_to_text("audio_output.wav")

3. 自动生成文案

将识别结果格式化为文案:

def generate_transcript(text, output_path):
    """
    生成文案文件
    :param text: 识别的文本内容
    :param output_path: 文案保存路径
    """
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("自动生成的文案:\n")
        f.write(text)
    print(f"文案已保存至: {output_path}")

# 示例用法
generate_transcript(text, "transcript.txt")

四、完整代码示例

整合上述步骤的完整代码:

from moviepy.editor import VideoFileClip
from paddlespeech.cli.asr import ASRExecutor

def extract_audio(video_path, audio_output_path):
    video = VideoFileClip(video_path)
    video.audio.write_audiofile(audio_output_path)
    print(f"音频已保存至: {audio_output_path}")

def audio_to_text(audio_path):
    asr = ASRExecutor()
    result = asr(audio_file=audio_path)
    print("语音识别结果:", result)
    return result

def generate_transcript(text, output_path):
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("自动生成的文案:\n")
        f.write(text)
    print(f"文案已保存至: {output_path}")

# 主程序
if __name__ == "__main__":
    video_path = "sample_video.mp4"  # 输入视频文件
    audio_output_path = "audio_output.wav"  # 提取的音频文件
    transcript_path = "transcript.txt"  # 输出文案文件

    # 步骤 1: 提取音频
    extract_audio(video_path, audio_output_path)

    # 步骤 2: 转换语音为文本
    text = audio_to_text(audio_output_path)

    # 步骤 3: 生成文案
    generate_transcript(text, transcript_path)

五、效果展示

  1. 输入:一个示例视频文件(sample_video.mp4)。
  2. 输出

    • 提取的音频文件:audio_output.wav
    • 生成的文案文件:transcript.txt,内容类似:

      自动生成的文案:
      你好,这是一段用于测试语音识别的文字。

六、注意事项

  1. 音频格式要求:确保音频文件的格式是模型支持的(如 PCM 或 WAV)。
  2. 模型性能:PaddleSpeech 提供多种语音识别模型,可以根据需求选择性能更优的模型。
  3. 背景噪声:语音识别效果受背景噪声影响较大,建议在安静环境下录制视频。
  4. 多语言支持:PaddleSpeech 支持多种语言,可根据需求选择模型。

七、总结

通过本文的教程,你可以轻松实现基于 PaddlePaddle 的视频语音转文本功能,从提取音频到生成文案一键搞定。

  • 核心亮点:高效、智能、简单的实现流程。
  • 应用场景:会议记录、字幕生成、视频文案提取等。

如果想了解更多,建议深入学习 PaddleSpeech 的官方文档和更多高级功能。

2024-11-27

Python 库之 Celery 详解

Celery 是一个用于分布式任务队列的强大 Python 库,可以帮助开发者轻松实现异步任务调度、高并发、任务重试等功能。它常用于 Web 开发、定时任务处理和后台作业。

本文将详细讲解 Celery 的核心概念、安装与配置,以及代码示例和图解,帮助你快速掌握 Celery 的使用。


一、什么是 Celery?

1. 核心概念

  • 分布式任务队列:Celery 使用生产者-消费者模型,将任务推送到队列中,由多个工作者(worker)异步执行。
  • 异步任务:任务可以独立于主进程执行,不阻塞主程序。
  • 高并发:Celery 能处理大量任务,支持任务优先级和调度。

2. 工作流程

  1. 任务生产者(Producer):定义并发送任务。
  2. 消息代理(Broker):管理任务队列。常用 RabbitMQ、Redis 等。
  3. 任务执行者(Worker):从队列中取出任务并执行。
  4. 结果后端(Backend):存储任务的执行结果。

图解:

+----------------+          +----------------+
| Task Producer  |   --->   |   Message      |
| (e.g., Web App)|          |   Broker       |
+----------------+          +----------------+
                                ↓
                          +----------------+
                          |   Worker       |
                          |   (Executor)   |
                          +----------------+
                                ↓
                          +----------------+
                          | Result Backend |
                          +----------------+

二、Celery 的安装与配置

1. 安装 Celery

使用 pip 安装:

pip install celery

安装 Redis 作为消息代理:

pip install redis

确保 Redis 服务已启动:

redis-server

2. 配置 Celery

创建一个名为 tasks.py 的文件:

from celery import Celery

# 配置 Celery 应用
app = Celery('tasks', broker='redis://localhost:6379/0', backend='redis://localhost:6379/0')

@app.task
def add(x, y):
    return x + y

三、使用 Celery 执行任务

1. 启动 Celery Worker

在终端运行以下命令,启动 Worker:

celery -A tasks worker --loglevel=info

Worker 会监听任务队列并执行任务。

2. 发送任务

在另一个 Python 脚本中调用任务:

from tasks import add

# 调用任务
result = add.delay(4, 6)  # 异步调用
print("任务提交完成,结果:", result.id)

# 检查任务结果
print("任务结果:", result.get(timeout=10))

3. 任务结果查看

运行代码后,你会在 Worker 的日志中看到类似以下的输出:

[2024-11-27 12:00:00,000: INFO/MainProcess] Received task: tasks.add[1234abcd]
[2024-11-27 12:00:00,010: INFO/MainProcess] Task tasks.add[1234abcd] succeeded in 0.01s: 10

四、进阶使用

1. 定时任务

结合 celery-beat 实现定时任务:

pip install celery[redis] celery[django] django-celery-beat

定义周期性任务:

from celery import Celery
from celery.schedules import crontab

app = Celery('periodic_tasks', broker='redis://localhost:6379/0')

@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(10.0, test.s('hello'), name='add every 10 seconds')
    sender.add_periodic_task(
        crontab(minute='*/1'),
        test.s('world'),
        name='say hello every minute',
    )

@app.task
def test(arg):
    print(arg)

启动 Worker 和 celery-beat 调度:

celery -A periodic_tasks worker --loglevel=info
celery -A periodic_tasks beat --loglevel=info

2. 任务重试

任务失败时可以重试:

from celery import Celery

app = Celery('retry_task', broker='redis://localhost:6379/0')

@app.task(bind=True, max_retries=3)
def retry_task(self):
    try:
        # 模拟错误
        raise ValueError("模拟任务失败")
    except Exception as exc:
        raise self.retry(exc=exc, countdown=5)  # 5 秒后重试

五、Celery 优势和应用场景

1. 优势

  • 异步执行:主程序不必等待任务完成。
  • 高扩展性:支持分布式任务调度。
  • 灵活性:支持多种消息代理和结果存储后端。

2. 应用场景

  • Web 应用:处理后台作业(如邮件发送、图片处理)。
  • 数据处理:处理批量任务(如数据清洗、ETL 操作)。
  • 定时任务:定时触发特定任务。

六、总结

Celery 是一个功能强大的分布式任务调度库,其灵活性和高效性使其成为异步任务处理的首选工具。从简单的异步任务到复杂的定时任务,Celery 都能胜任。

通过本文的图解和代码示例,你可以快速上手 Celery 并应用到实际项目中。进一步学习可以深入研究 Celery 的任务优先级、路由和监控工具(如 Flower)。

推荐阅读

2024-11-27

Python中栈的概念和使用

栈(Stack)是一种常见的数据结构,广泛应用于计算机科学和编程中。在 Python 中,栈的操作十分灵活且易于实现。本篇文章将详细介绍栈的概念、特点及其在 Python 中的实现和使用,配以代码示例和图解,帮助你轻松掌握栈的基础知识。


一、栈的概念

1. 栈的定义

栈是一种后进先出(LIFO,Last In First Out)的数据结构。这意味着,最后存入栈的元素最先被取出。

2. 栈的基本操作

栈支持以下核心操作:

  • 压栈(Push):将一个元素放入栈中。
  • 弹栈(Pop):移除并返回栈顶的元素。
  • 查看栈顶(Peek/Top):查看栈顶元素但不移除。
  • 判断栈空(IsEmpty):检查栈是否为空。

二、栈的实现方式

在 Python 中,我们可以使用以下方式实现栈:

  1. 列表(list):利用 Python 的内置列表模拟栈。
  2. collections.deque:双端队列更适合作为栈。
  3. 自定义类:通过封装实现栈的功能。

1. 使用列表实现栈

# 栈的实现
stack = []

# 压栈
stack.append(1)
stack.append(2)
stack.append(3)
print("栈的状态:", stack)  # 输出:[1, 2, 3]

# 弹栈
top_element = stack.pop()
print("弹出的元素:", top_element)  # 输出:3
print("栈的状态:", stack)        # 输出:[1, 2]

# 查看栈顶元素
if stack:
    print("栈顶元素:", stack[-1])  # 输出:2
else:
    print("栈为空")

图解:

  1. 压栈操作

    • 初始状态:[]
    • append(1) 后:[1]
    • append(2) 后:[1, 2]
    • append(3) 后:[1, 2, 3]
  2. 弹栈操作

    • pop() 移除栈顶元素 3,剩余 [1, 2]

2. 使用 collections.deque 实现栈

deque 是双端队列,比列表在栈操作中更高效。

from collections import deque

# 使用 deque 实现栈
stack = deque()

# 压栈
stack.append(1)
stack.append(2)
stack.append(3)
print("栈的状态:", stack)  # 输出:deque([1, 2, 3])

# 弹栈
top_element = stack.pop()
print("弹出的元素:", top_element)  # 输出:3
print("栈的状态:", stack)         # 输出:deque([1, 2])

3. 自定义栈类

通过面向对象的方式封装栈操作。

class Stack:
    def __init__(self):
        self.stack = []

    def push(self, item):
        self.stack.append(item)

    def pop(self):
        if not self.is_empty():
            return self.stack.pop()
        else:
            raise IndexError("弹栈失败,栈为空")

    def peek(self):
        if not self.is_empty():
            return self.stack[-1]
        else:
            return None

    def is_empty(self):
        return len(self.stack) == 0

    def size(self):
        return len(self.stack)

# 测试自定义栈类
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print("栈顶元素:", stack.peek())  # 输出:3
print("弹出元素:", stack.pop())   # 输出:3
print("栈是否为空:", stack.is_empty())  # 输出:False

三、栈的应用场景

1. 括号匹配

栈常用于检查括号是否成对出现。

示例代码:

def is_valid_parentheses(s):
    stack = []
    mapping = {')': '(', '}': '{', ']': '['}
    for char in s:
        if char in mapping:
            top_element = stack.pop() if stack else '#'
            if mapping[char] != top_element:
                return False
        else:
            stack.append(char)
    return not stack

# 测试
print(is_valid_parentheses("()[]{}"))  # 输出:True
print(is_valid_parentheses("(]"))      # 输出:False

2. 栈实现表达式求值

栈可以用于后缀表达式(逆波兰表达式)的求值。

示例代码:

def eval_rpn(tokens):
    stack = []
    for token in tokens:
        if token.isdigit() or (token[0] == '-' and len(token) > 1):  # 操作数
            stack.append(int(token))
        else:  # 操作符
            b = stack.pop()
            a = stack.pop()
            if token == '+':
                stack.append(a + b)
            elif token == '-':
                stack.append(a - b)
            elif token == '*':
                stack.append(a * b)
            elif token == '/':
                stack.append(int(a / b))  # Python 中整除
    return stack[0]

# 测试
expression = ["2", "1", "+", "3", "*"]  # 表示 (2 + 1) * 3
print(eval_rpn(expression))  # 输出:9

四、总结

  1. 栈的特点:后进先出,适合管理具有层级关系的数据。
  2. 实现方式

    • 使用 Python 列表(简单、灵活)。
    • 使用 deque(性能更优)。
    • 自定义栈类(更清晰的逻辑封装)。
  3. 常见应用

    • 括号匹配
    • 表达式求值
    • 深度优先搜索等。

掌握栈的基本操作和实际应用,将为你在算法与数据结构学习中打下坚实基础!

2024-11-27

【图像分割】Meta分割一切(SAM)模型环境配置和使用教程

Meta 的 Segment Anything Model (SAM) 是一款强大的图像分割工具,支持多种提示方式(点提示、框提示、文本提示等),可以对任意对象进行高效分割。本教程将详细介绍 SAM 的安装、环境配置及其在 Python 中的使用,配合代码示例和图解,帮助你快速上手。


一、SAM 简介

SAM (Segment Anything Model) 是 Meta AI 推出的一款通用分割模型,其特点包括:

  • 支持多种提示方式:如单点、多点、框选、文本描述。
  • 极高的分割精度:可对图像中的任意对象进行分割。
  • 开箱即用:可应用于研究、开发或生产环境。

二、环境配置

1. 系统和硬件需求

SAM 对硬件性能有一定要求,建议使用支持 CUDA 的 GPU 来加速推理。

推荐配置:

  • 操作系统:Windows/Linux/MacOS
  • Python:3.8 及以上
  • 显卡:支持 CUDA 的 GPU

2. 安装步骤

(1) 克隆 SAM 项目代码

首先,获取 SAM 的官方代码库:

git clone https://github.com/facebookresearch/segment-anything.git
cd segment-anything

(2) 创建虚拟环境

为确保环境干净,建议创建一个虚拟环境:

python -m venv sam_env
source sam_env/bin/activate  # Linux/MacOS
sam_env\Scripts\activate     # Windows

(3) 安装依赖

安装所需 Python 库:

pip install -r requirements.txt

(4) 下载预训练模型

SAM 官方下载页面 获取预训练权重文件(如 sam_vit_h_4b8939.pth)。将权重文件保存到项目的 checkpoint 文件夹中。

(5) 验证安装

运行以下命令,确保环境配置成功:

python scripts/demo.py

三、SAM 模型原理及工作流程

SAM 的核心工作流程如下:

  1. 输入提示:如点、框或文本描述。
  2. 特征提取:通过 ViT 模型提取全局图像特征。
  3. 生成分割:根据输入提示生成对应的分割掩码。

四、SAM 使用教程

以下以 Python 为例,演示如何加载模型并进行分割。

1. 导入必要库并加载模型

import torch
from segment_anything import sam_model_registry, SamPredictor

# 加载模型
sam_checkpoint = "checkpoint/sam_vit_h_4b8939.pth"
model_type = "vit_h"  # 可选 'vit_l' 或 'vit_b'
sam = sam_model_registry[model_type](checkpoint=sam_checkpoint)
sam.to(device="cuda")  # 将模型加载到 GPU

2. 初始化预测器

predictor = SamPredictor(sam)

3. 加载输入图像

from PIL import Image
import numpy as np

# 加载图像并转换为 NumPy 数组
image_path = "example.jpg"
image = np.array(Image.open(image_path))

# 设置预测图像
predictor.set_image(image)

4. 使用提示进行分割

(1) 单点提示

input_point = np.array([[200, 300]])  # 提示点坐标 (x, y)
input_label = np.array([1])          # 1 表示前景
masks, scores, logits = predictor.predict(
    point_coords=input_point,
    point_labels=input_label,
    multimask_output=True  # 是否输出多个候选掩码
)

(2) 框提示

input_box = np.array([100, 100, 400, 400])  # 边界框 [x1, y1, x2, y2]
masks, scores, logits = predictor.predict(
    box=input_box,
    multimask_output=False
)

五、可视化分割结果

以下是使用 Matplotlib 对分割结果进行可视化的示例:

import matplotlib.pyplot as plt

# 绘制原始图像
plt.figure(figsize=(10, 10))
plt.imshow(image)
plt.title("Original Image")
plt.axis("off")

# 绘制分割掩码
for i, mask in enumerate(masks):
    plt.figure(figsize=(10, 10))
    plt.imshow(image)
    plt.imshow(mask, alpha=0.5, cmap="jet")  # 半透明叠加掩码
    plt.title(f"Mask {i+1}")
    plt.axis("off")
plt.show()

六、完整代码示例

以下代码演示了从加载模型到分割图像并可视化结果的完整流程:

import torch
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
from segment_anything import sam_model_registry, SamPredictor

# 加载模型
sam_checkpoint = "checkpoint/sam_vit_h_4b8939.pth"
model_type = "vit_h"
sam = sam_model_registry[model_type](checkpoint=sam_checkpoint)
sam.to(device="cuda")

# 初始化预测器
predictor = SamPredictor(sam)

# 加载图像
image_path = "example.jpg"
image = np.array(Image.open(image_path))
predictor.set_image(image)

# 单点提示
input_point = np.array([[200, 300]])
input_label = np.array([1])
masks, scores, logits = predictor.predict(
    point_coords=input_point,
    point_labels=input_label,
    multimask_output=True
)

# 可视化分割结果
plt.figure(figsize=(10, 10))
plt.imshow(image)
plt.title("Original Image")
plt.axis("off")

for i, mask in enumerate(masks):
    plt.figure(figsize=(10, 10))
    plt.imshow(image)
    plt.imshow(mask, alpha=0.5, cmap="jet")
    plt.title(f"Mask {i+1}")
    plt.axis("off")
plt.show()

七、总结与展望

通过本教程,你已经掌握了如何配置环境、加载 SAM 模型并执行图像分割。接下来,你可以尝试:

  1. 使用更多提示方式(例如文本提示)。
  2. 将 SAM 应用于批量图像分割任务。
  3. 探索 SAM 的 API,结合其他模型完成更多计算机视觉任务。

SAM 的强大之处在于其通用性和精确性,它将在图像分割领域产生深远影响!

2024-11-27

Python NumPy 库详解

NumPy 是 Python 科学计算的核心库之一,主要用于处理大型、多维数组和矩阵,并提供对数组进行高效运算的函数和工具。本教程将深入讲解 NumPy 的功能,包括安装、核心概念、常用操作、代码示例和图解,帮助你快速掌握 NumPy。


一、NumPy 简介

1. 什么是 NumPy?

NumPy(Numerical Python)是一个开源库,用于高性能的数组计算。它提供:

  • 多维数组对象(ndarray)。
  • 用于数组操作的函数,例如数学、线性代数、傅里叶变换等。
  • 高效的数值运算性能,内部使用 C 实现。

2. NumPy 的应用场景

  • 数据分析
  • 机器学习
  • 科学计算
  • 图像处理

二、NumPy 安装

在开始使用之前,确保已经安装 NumPy,可以通过以下命令安装:

pip install numpy

验证安装:

import numpy as np
print(np.__version__)  # 打印 NumPy 版本

三、核心概念详解

1. ndarray 对象

NumPy 的核心是 ndarray,它是一种多维数组。

import numpy as np

# 创建一维数组
arr1 = np.array([1, 2, 3, 4])
print(arr1)

# 创建二维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)

输出:

[1 2 3 4]
[[1 2 3]
 [4 5 6]]

2. 数组属性

数组的属性可以帮助我们了解数组的信息:

print(arr2.shape)  # 数组形状
print(arr2.ndim)   # 数组维度
print(arr2.size)   # 数组总元素个数
print(arr2.dtype)  # 数组元素数据类型

四、NumPy 常用操作

1. 数组的创建

# 创建全零数组
zeros = np.zeros((3, 3))
print("全零数组:\n", zeros)

# 创建全一数组
ones = np.ones((2, 4))
print("全一数组:\n", ones)

# 创建指定范围的数组
arange = np.arange(0, 10, 2)  # 步长为 2
print("arange:\n", arange)

# 创建等间距数组
linspace = np.linspace(0, 1, 5)  # 0 到 1 等间隔取 5 个点
print("linspace:\n", linspace)

图解:

zeros:
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]

ones:
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]]

arange:
[0 2 4 6 8]

linspace:
[0.   0.25 0.5  0.75 1.  ]

2. 数组的切片与索引

一维数组切片

arr = np.array([10, 20, 30, 40, 50])
print(arr[1:4])  # 输出 [20 30 40]

多维数组切片

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[1:, 1:])  # 输出 [[5 6] [8 9]]

3. 数组运算

数组间运算

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a + b)  # 加法
print(a * b)  # 逐元素乘法

数学函数

arr = np.array([0, np.pi / 2, np.pi])
print(np.sin(arr))  # 正弦
print(np.exp(arr))  # 指数
print(np.sqrt(arr))  # 开方

4. 广播机制

NumPy 支持不同形状的数组进行运算,称为广播机制。

a = np.array([[1], [2], [3]])
b = np.array([10, 20, 30])
print(a + b)

输出:

[[11 21 31]
 [12 22 32]
 [13 23 33]]

五、高级功能

1. 线性代数

from numpy.linalg import inv, det

# 矩阵求逆
matrix = np.array([[1, 2], [3, 4]])
inverse = inv(matrix)
print("矩阵的逆:\n", inverse)

# 矩阵行列式
determinant = det(matrix)
print("矩阵行列式:", determinant)

2. 随机数生成

from numpy.random import rand, randint

# 随机生成浮点数
random_floats = rand(3, 3)
print("随机浮点数:\n", random_floats)

# 随机生成整数
random_ints = randint(0, 10, (3, 3))
print("随机整数:\n", random_ints)

六、NumPy 应用案例

1. 数据分析

data = np.array([5, 10, 15, 20, 25])
mean = np.mean(data)  # 均值
std = np.std(data)    # 标准差
print("均值:", mean)
print("标准差:", std)

2. 图像处理

from PIL import Image

# 加载图像并转换为 NumPy 数组
image = Image.open('example.jpg')
image_array = np.array(image)

# 将图像反转
inverted_image = 255 - image_array

# 显示原始图像和反转图像
Image.fromarray(inverted_image).show()

七、总结与练习

通过本教程,你已经掌握了 NumPy 的基本操作、高级功能和常见应用。以下是一些练习建议:

  1. 使用 NumPy 实现矩阵乘法。
  2. 使用 NumPy 生成正态分布的数据,并绘制直方图。
  3. 使用广播机制完成不同形状数组的运算。

NumPy 是数据科学的基石,学习好它将为你后续的数据分析、机器学习等任务奠定坚实的基础。

2024-11-27

【图像分割】Grounded Segment Anything:根据文字自动画框或分割环境配置和使用教程

Grounded Segment Anything 是一种结合了 OpenAI 的 GPT 和 Meta 的 Segment Anything 模型(SAM)的创新工具。它可以根据用户输入的文本提示,自动生成图像分割的框或掩码。本教程将从环境配置开始,逐步介绍如何安装和使用该工具,同时包含代码示例和图解。


一、Grounded Segment Anything 的概述

1. Grounded Segment Anything 是什么?

  • 功能:根据用户输入的自然语言描述,对目标图像中的特定区域进行分割或画框。
  • 优势:无需训练,快速部署;结合 SAM 模型的强大分割能力,能够识别并精准定位任意目标。

二、环境配置

要使用 Grounded Segment Anything,我们需要安装相关依赖,包括 PyTorch、SAM、GroundingDINO 等。

1. 环境需求

  • Python 版本:3.8 或以上
  • GPU:建议支持 CUDA 的显卡
  • 操作系统:Linux / MacOS / Windows

2. 安装步骤

(1)安装 PyTorch

安装适合你硬件的 PyTorch 版本。以下以 CUDA 11.8 为例:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

(2)克隆 Grounded Segment Anything 仓库

git clone https://github.com/IDEA-Research/Grounded-Segment-Anything.git
cd Grounded-Segment-Anything

(3)安装依赖

pip install -r requirements.txt

(4)下载预训练模型

需要下载 GroundingDINO 和 SAM 的权重文件:

下载后,将模型权重保存到 models/ 目录下。


三、代码示例

以下是一个使用 Grounded Segment Anything 进行图像分割的完整示例。

1. 导入库和加载模型

import torch
from groundingdino.util.inference import load_model, predict
from segment_anything import SamPredictor, sam_model_registry
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# 加载 GroundingDINO 模型
dino_model = load_model("models/groundingdino_swint_ogc.pth")

# 加载 SAM 模型
sam_checkpoint = "models/sam_vit_h_4b8939.pth"
sam = sam_model_registry["vit_h"](checkpoint=sam_checkpoint)
sam_predictor = SamPredictor(sam)

2. 加载图像

# 读取并预处理图像
image_path = "example.jpg"
image = Image.open(image_path).convert("RGB")
image_np = np.array(image)

# 设置 SAM 图像
sam_predictor.set_image(image_np)

3. 根据文本提示生成框

# 文本提示
text_prompt = "a cat"

# 使用 GroundingDINO 生成候选框
boxes, scores, phrases = predict(
    model=dino_model,
    image=image_np,
    text_prompt=text_prompt,
    box_threshold=0.3,  # 置信度阈值
    text_threshold=0.25
)

# 可视化生成的框
for box in boxes:
    plt.gca().add_patch(plt.Rectangle(
        (box[0], box[1]),
        box[2] - box[0],
        box[3] - box[1],
        edgecolor='red',
        fill=False,
        linewidth=2
    ))
plt.imshow(image_np)
plt.show()

4. 使用 SAM 模型分割框中区域

# 选择一个框(以第一个为例)
selected_box = boxes[0]

# 使用 SAM 分割框内区域
masks, _, _ = sam_predictor.predict(
    box=np.array(selected_box),
    multimask_output=False
)

# 显示分割结果
plt.figure(figsize=(10, 10))
plt.imshow(image_np)
plt.imshow(masks[0], alpha=0.5, cmap="jet")  # 叠加掩码
plt.axis("off")
plt.show()

四、完整运行流程图解

1. GroundedDINO 提取文本相关框

  • 输入text_prompt="a cat"
  • 输出:框的坐标和得分。

GroundedDINO 画框示意图GroundedDINO 画框示意图


2. SAM 精确分割目标

  • 输入:GroundedDINO 提供的框。
  • 输出:分割的掩码。

SAM 分割示意图SAM 分割示意图


五、应用场景

1. 自动化标注

通过自然语言输入,自动生成分割标注,大大提高数据标注效率。

2. 目标检测与分割

快速检测并分割特定对象,适用于工业检测、医学图像等领域。

3. 智能图像编辑

结合分割结果,对目标区域进行替换、增强等操作。


六、常见问题与解决方案

1. CUDA Out of Memory 错误

原因:图像过大或模型占用显存过多。
解决:缩小图像尺寸或切换到低版本的 SAM 模型。

2. 分割结果不理想

原因:文本描述过于模糊。
解决:提高文本描述的细化程度,例如增加目标的颜色、位置等特征。

3. 模型下载速度慢

解决:使用加速下载工具或国内镜像。


七、总结

通过 Grounded Segment Anything,可以轻松实现基于文字提示的图像分割任务。无论是自动化标注还是智能编辑,它都展示了强大的实用性。结合本教程,你可以快速上手该工具,为你的项目增添新的可能性。

推荐实验:

  1. 尝试不同的文本提示,观察对分割结果的影响。
  2. 修改代码,将分割结果保存为 PNG 格式。
  3. 集成到 Flask 或 Streamlit 应用中,实现在线分割服务。

快去尝试吧!🎉

2024-11-27

Python Socket 详解,最全教程

Socket 是计算机网络编程的基础工具,它提供了跨网络通信的能力。在 Python 中,socket 模块是开发网络应用的核心库。本教程将详细介绍 Python socket 模块的基础知识、用法及应用场景,并通过代码示例和图解帮助你快速入门。


一、什么是 Socket?

Socket 是网络中不同程序间通信的桥梁。它允许程序发送或接收数据,通常用于构建服务器与客户端模型。

常见 Socket 类型

  1. TCP(传输控制协议): 提供可靠的、基于连接的通信。
  2. UDP(用户数据报协议): 提供不可靠、无连接的通信,但速度快。

二、Python Socket 基本用法

1. 导入模块

在使用 socket 前,需导入模块:

import socket

2. 创建 Socket

基本语法:

s = socket.socket(family, type)
  • family: 地址族,例如 AF_INET(IPv4)或 AF_INET6(IPv6)。
  • type: 套接字类型,例如 SOCK_STREAM(TCP)或 SOCK_DGRAM(UDP)。

示例:

# 创建一个 TCP 套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 创建一个 UDP 套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

3. 客户端通信流程

TCP 客户端通信的基本步骤如下:

1. 创建套接字

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

2. 连接到服务器

server_address = ('127.0.0.1', 65432)  # 地址和端口
client_socket.connect(server_address)

3. 发送和接收数据

client_socket.sendall(b'Hello, Server!')
response = client_socket.recv(1024)  # 接收数据,最大字节数
print(f'Received: {response}')

4. 关闭套接字

client_socket.close()

完整示例:

import socket

# 创建客户端套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务器
server_address = ('127.0.0.1', 65432)
client_socket.connect(server_address)

try:
    # 发送数据
    message = b'Hello, Server!'
    client_socket.sendall(message)

    # 接收响应
    response = client_socket.recv(1024)
    print(f'Received: {response.decode()}')
finally:
    client_socket.close()

4. 服务器通信流程

TCP 服务器通信的基本步骤如下:

1. 创建套接字

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

2. 绑定地址

server_socket.bind(('127.0.0.1', 65432))  # 绑定 IP 和端口

3. 开始监听

server_socket.listen(5)  # 最大连接数

4. 接收连接和处理

connection, client_address = server_socket.accept()
print(f'Connection from {client_address}')

data = connection.recv(1024)  # 接收数据
print(f'Received: {data.decode()}')

connection.sendall(b'Hello, Client!')  # 发送响应
connection.close()

完整示例:

import socket

# 创建服务器套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 65432))
server_socket.listen(5)

print('Server is listening...')

while True:
    connection, client_address = server_socket.accept()
    try:
        print(f'Connection from {client_address}')
        data = connection.recv(1024)
        print(f'Received: {data.decode()}')

        if data:
            connection.sendall(b'Hello, Client!')
    finally:
        connection.close()

运行结果:

  1. 启动服务器。
  2. 启动客户端发送数据。
  3. 客户端收到响应。

三、UDP 通信

与 TCP 不同,UDP 是无连接协议,不需要建立连接。

1. UDP 客户端

示例:

import socket

udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

server_address = ('127.0.0.1', 65432)
udp_socket.sendto(b'Hello, UDP Server!', server_address)

data, server = udp_socket.recvfrom(1024)
print(f'Received: {data.decode()}')

udp_socket.close()

2. UDP 服务器

示例:

import socket

udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(('127.0.0.1', 65432))

print('UDP server is listening...')

while True:
    data, address = udp_socket.recvfrom(1024)
    print(f'Received {data.decode()} from {address}')

    udp_socket.sendto(b'Hello, UDP Client!', address)

四、图解 Socket 通信

1. TCP 通信模型

+------------+       +-------------+
|  Client    |       |  Server     |
+------------+       +-------------+
| Connect()  | <-->  | Accept()    |
| Send()     | <-->  | Receive()   |
| Receive()  | <-->  | Send()      |
| Close()    | <-->  | Close()     |
+------------+       +-------------+

2. UDP 通信模型

+------------+         +-------------+
|  Client    |         |  Server     |
+------------+         +-------------+
| SendTo()   | ----->  | RecvFrom()  |
| RecvFrom() | <-----  | SendTo()    |
+------------+         +-------------+

五、Socket 编程的常见问题

1. Address already in use

原因: 套接字未关闭或正在使用。
解决:

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

2. Connection reset by peer

原因: 客户端过早断开连接。
解决: 检查连接和数据流逻辑。

3. Timeout

原因: 通信超时。
解决:

socket.settimeout(5)  # 设置超时时间

六、Socket 的高级用法

  1. 多线程/多进程支持: 使用 threadingmultiprocessing 模块实现并发。
  2. SSL/TLS 支持: 使用 ssl 模块实现加密通信。
  3. 非阻塞 Socket: 设置套接字为非阻塞模式,适用于高性能应用。
  4. WebSocket 支持: 可结合 websockets 库构建实时通信。

七、总结

通过本文的介绍,你已经掌握了 Python socket 的基本概念和使用方法。无论是实现简单的客户端-服务器通信,还是构建复杂的网络应用,socket 都是不可或缺的工具。

练习建议:

  1. 使用 TCP 创建一个聊天室应用。
  2. 使用 UDP 构建一个简单的文件传输工具。
  3. 探索 SSL 加密通信。

拓展阅读:

  • 官方文档:Python socket
  • 实战项目:用 socket 构建 HTTP 服务。

快动手尝试吧!Socket 是网络编程的基石,掌握它将为你打开更广阔的编程世界。

2024-11-27

PyCryptodome,一个神奇的 Python 库!

在现代软件开发中,数据加密是确保信息安全的重要手段。PyCryptodome 是一个强大的 Python 库,用于实现各种加密算法。它是 Python Cryptography Toolkit 的改进版本,提供了现代加密方法,性能高且易于使用。本文将介绍 PyCryptodome 的基本功能、安装方法、主要模块及代码示例,帮助你快速上手。


一、PyCryptodome 简介

PyCryptodome 是一套轻量级但功能强大的加密库,支持对称加密、非对称加密、哈希算法等功能,广泛应用于数据保护和安全通信领域。

主要特点:

  1. 支持现代加密算法(如 AES、RSA、SHA 等)。
  2. 完全兼容 PyCrypto,可以作为其直接替代品。
  3. 性能优化,适合高效处理大数据。
  4. 具备多平台支持。

二、安装 PyCryptodome

在 Python 环境中安装 PyCryptodome 非常简单,使用 pip 命令即可:

pip install pycryptodome

验证安装:

import Crypto
print(Crypto.__version__)

如果没有报错,并输出版本号,说明安装成功。


三、PyCryptodome 的主要模块

PyCryptodome 提供了多个模块,用于不同的加密场景。以下是常用模块:

模块名称功能描述
Crypto.Cipher对称加密和非对称加密算法(如 AES、DES、RSA)。
Crypto.Hash哈希算法(如 SHA-256、MD5)。
Crypto.Random生成随机数和随机密钥。
Crypto.Signature数字签名,用于验证消息完整性和身份。

四、PyCryptodome 使用示例

1. 对称加密(AES 加密)

AES(高级加密标准)是一种常用的对称加密算法,适合快速加密大块数据。

示例代码:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

# 数据和密钥
data = b"Hello, PyCryptodome!"
key = get_random_bytes(16)  # 生成16字节密钥(128位)

# 加密
cipher = AES.new(key, AES.MODE_CBC)  # 创建 AES 加密器,使用 CBC 模式
ciphertext = cipher.encrypt(pad(data, AES.block_size))  # 数据填充并加密
iv = cipher.iv  # 获取初始化向量(IV)
print(f"Ciphertext: {ciphertext}")

# 解密
cipher_dec = AES.new(key, AES.MODE_CBC, iv=iv)  # 创建解密器
plaintext = unpad(cipher_dec.decrypt(ciphertext), AES.block_size)  # 解密并去除填充
print(f"Decrypted: {plaintext}")

输出:

Ciphertext: b'\x93\x...'
Decrypted: b'Hello, PyCryptodome!'

图解:

数据: Hello, PyCryptodome!
    ↓   填充
加密: AES (模式: CBC)
    ↓
密文: <加密后的数据>
    ↓   去除填充
解密: AES (模式: CBC)
    ↓
原文: Hello, PyCryptodome!

2. 非对称加密(RSA 加密)

RSA 是一种非对称加密算法,使用公钥加密,私钥解密。

示例代码:

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

# 生成 RSA 密钥对
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()

# 加密
public_key_obj = RSA.import_key(public_key)
cipher_rsa = PKCS1_OAEP.new(public_key_obj)
encrypted = cipher_rsa.encrypt(b"Secure message")
print(f"Encrypted: {encrypted}")

# 解密
private_key_obj = RSA.import_key(private_key)
cipher_rsa_dec = PKCS1_OAEP.new(private_key_obj)
decrypted = cipher_rsa_dec.decrypt(encrypted)
print(f"Decrypted: {decrypted}")

输出:

Encrypted: b'\x80...'
Decrypted: b'Secure message'

3. 哈希算法(SHA-256)

哈希算法用于生成数据的固定长度摘要,常用于校验文件完整性。

示例代码:

from Crypto.Hash import SHA256

# 生成哈希值
data = b"PyCryptodome is powerful!"
hash_obj = SHA256.new(data)
print(f"Hash: {hash_obj.hexdigest()}")

输出:

Hash: e9cbb8a...

4. 数字签名

数字签名确保消息的完整性和身份验证。

示例代码:

from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA

# 生成 RSA 密钥
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()

# 签名
message = b"Important message"
hash_obj = SHA256.new(message)
signature = pkcs1_15.new(key).sign(hash_obj)
print(f"Signature: {signature}")

# 验证签名
try:
    public_key_obj = RSA.import_key(public_key)
    pkcs1_15.new(public_key_obj).verify(hash_obj, signature)
    print("Signature is valid.")
except ValueError:
    print("Signature is invalid.")

输出:

Signature: b'\x12...'
Signature is valid.

五、PyCryptodome 的优势

  1. 易用性: 提供直观的 API,适合快速开发。
  2. 兼容性: 可无缝替代 PyCrypto,无需额外学习成本。
  3. 性能优化: 支持多线程和大数据加密。
  4. 功能齐全: 集成加密、哈希、随机数生成等多种功能。

六、常见问题与解决方案

1. 为什么提示 ImportError: No module named 'Crypto'

确保安装的库是 pycryptodome 而非 crypto,使用以下命令安装:

pip install pycryptodome

2. 如何提高加密效率?

  • 尽量使用适合场景的加密模式(如 AES-GCM 提供加密和认证)。
  • 优化数据填充策略,减少冗余。

七、总结

PyCryptodome 是一个功能强大且灵活的 Python 加密库。它可以帮助开发者快速实现从对称加密到非对称加密,再到哈希运算的全套功能。通过学习本文,你应该掌握了 PyCryptodome 的安装方法、基本模块以及实际使用中的常见场景。

快动手试试这个神奇的库,为你的 Python 项目添加强大的加密能力吧!