0

Kiểm tra hàng loạt ảnh bằng Python trước khi đưa vào pipeline tạo video

Khi xây dựng một workflow xử lý ảnh hoặc tạo video từ ảnh, có một bước khá dễ bị bỏ qua: kiểm tra file đầu vào.

Một thư mục chứa 100 ảnh có thể trông hoàn toàn bình thường khi xem bằng File Explorer. Nhưng khi chạy xử lý tự động, chúng ta có thể gặp những vấn đề như:

  • Ảnh có kích thước quá nhỏ.
  • Tỷ lệ khung hình không phù hợp với video đầu ra.
  • File có phần mở rộng .jpg nhưng nội dung thực tế là PNG.
  • File bị hỏng hoặc không thể đọc.
  • Dung lượng ảnh vượt quá giới hạn của pipeline.

Nếu chỉ phát hiện lỗi sau khi đã gửi ảnh tới bước xử lý tiếp theo, chúng ta sẽ mất thời gian để tìm lại file gây ra sự cố.

Trong bài này, chúng ta sẽ viết một công cụ Python nhỏ để kiểm tra ảnh hàng loạt và xuất kết quả thành file CSV.

Công cụ hoạt động hoàn toàn trên máy cục bộ, không cần API bên ngoài.

1. Thiết kế workflow

Mục tiêu là xây dựng một bước kiểm tra đơn giản:

Input Images
     |
     v
Python Validator
     |
     +-- Check Format
     +-- Check Dimensions
     +-- Check Aspect Ratio
     +-- Check File Size
     +-- Detect Corrupted Files
     |
     v
Validation Report (CSV)
     |
     v
Review / Processing Pipeline

Chúng ta sẽ sử dụng thư viện Pillow để đọc và xác minh dữ liệu ảnh.

Bài viết tập trung vào PNG và JPEG. Các định dạng khác sẽ bị đánh dấu là không được hỗ trợ.

2. Chuẩn bị môi trường

Yêu cầu Python 3.10 trở lên.

Tạo thư mục dự án:

mkdir image-validator
cd image-validator
python -m venv .venv

Kích hoạt virtual environment.

Trên Windows:

.venv\Scripts\activate

Trên macOS hoặc Linux:

source .venv/bin/activate

Cài đặt Pillow:

python -m pip install Pillow

Tạo thư mục images để chứa những ảnh cần kiểm tra.

Cấu trúc dự án:

image-validator/
├── images/
├── validate_images.py
└── requirements.txt

Trong requirements.txt, thêm:

Pillow

Khi sử dụng trong dự án thực tế, nên khóa phiên bản thư viện sau khi kiểm thử để đảm bảo môi trường có thể tái tạo.

3. Viết chương trình kiểm tra ảnh

Tạo file validate_images.py:

from pathlib import Path
from PIL import Image, UnidentifiedImageError
import csv

INPUT_DIR = Path("images")
REPORT_FILE = Path("report.csv")

MIN_WIDTH = 1024
MIN_HEIGHT = 576
MAX_SIZE_MB = 10
TARGET_RATIO = 16 / 9
RATIO_TOLERANCE = 0.03

SUPPORTED = {
    ".jpg": "JPEG",
    ".jpeg": "JPEG",
    ".png": "PNG",
}


def validate_image(path):
    result = {
        "filename": path.name,
        "width": "",
        "height": "",
        "format": "",
        "status": "PASS",
        "issues": "",
    }

    issues = []

    try:
        with Image.open(path) as img:
            actual_format = img.format
            img.verify()

        # Mở lại vì verify() không dùng để đọc pixel.
        with Image.open(path) as img:
            img.load()
            width, height = img.size

        result["width"] = width
        result["height"] = height
        result["format"] = actual_format

        expected_format = SUPPORTED.get(
            path.suffix.lower()
        )

        if expected_format != actual_format:
            issues.append("Format mismatch or unsupported")

        if width < MIN_WIDTH or height < MIN_HEIGHT:
            issues.append("Resolution too small")

        ratio = width / height

        if abs(ratio - TARGET_RATIO) > RATIO_TOLERANCE:
            issues.append("Unexpected aspect ratio")

        size_mb = path.stat().st_size / (1024 * 1024)

        if size_mb > MAX_SIZE_MB:
            issues.append("File too large")

    except (
        UnidentifiedImageError,
        OSError,
        ValueError,
        Image.DecompressionBombError,
    ) as exc:
        issues.append(f"Cannot read image: {type(exc).__name__}")

    if issues:
        result["status"] = "FAIL"
        result["issues"] = "; ".join(issues)

    return result


def main():
    if not INPUT_DIR.is_dir():
        raise SystemExit("Input directory does not exist")

    files = sorted(
        p for p in INPUT_DIR.iterdir()
        if p.is_file()
    )

    results = [validate_image(p) for p in files]

    fields = [
        "filename",
        "width",
        "height",
        "format",
        "status",
        "issues",
    ]

    with REPORT_FILE.open(
        "w", newline="", encoding="utf-8-sig"
    ) as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows(results)

    failed = sum(
        row["status"] == "FAIL" for row in results
    )

    print(f"Checked: {len(results)}")
    print(f"Passed: {len(results) - failed}")
    print(f"Failed: {failed}")
    print(f"Report: {REPORT_FILE}")

    if failed:
        raise SystemExit(1)


if __name__ == "__main__":
    main()

Một vài điểm đáng chú ý

img.verify() không thay thế img.load()

verify() kiểm tra cấu trúc file ở mức Pillow hỗ trợ, nhưng không phải lúc nào cũng giải mã toàn bộ dữ liệu pixel. Vì vậy, chương trình mở lại ảnh và gọi load().

Kiểm tra định dạng thực tế

Chúng ta không chỉ dựa vào phần mở rộng của tên file. Thuộc tính img.format giúp xác định định dạng mà Pillow nhận diện được.

Tolerance cho tỷ lệ khung hình

Thay vì yêu cầu tỷ lệ chính xác tuyệt đối là 16:9, chương trình cho phép sai số 0.03.

Đây là quy tắc kiểm tra của ví dụ, không phải yêu cầu bắt buộc của mọi hệ thống tạo video.

4. Tạo dữ liệu để kiểm thử

Không nên chỉ chạy chương trình trên những ảnh có sẵn rồi cho rằng nó hoạt động đúng.

Chúng ta có thể tạo một số file thử nghiệm:

from PIL import Image
from pathlib import Path

folder = Path("images")
folder.mkdir(exist_ok=True)

Image.new(
    "RGB", (1920, 1080), "blue"
).save(folder / "valid.jpg")

Image.new(
    "RGB", (640, 360), "red"
).save(folder / "small.jpg")

Image.new(
    "RGB", (1080, 1080), "green"
).save(folder / "square.png")

Image.new(
    "RGB", (1920, 1080), "white"
).save(folder / "wrong_extension.png", format="JPEG")

(folder / "broken.jpg").write_bytes(
    b"not a valid image"
)

Lưu đoạn code trên thành create_samples.py, sau đó chạy:

python create_samples.py
python validate_images.py

Lệnh kiểm tra sẽ trả exit code 1 vì bộ dữ liệu cố ý chứa file không hợp lệ.

Kết quả mong đợi:

Checked: 5
Passed: 1
Failed: 4
Report: report.csv

Chương trình cũng tạo ra report.csv để xem chi tiết từng lỗi.

Bảng dưới đây mô tả kết quả kỳ vọng, không phải benchmark hiệu năng:

File Kết quả Lý do
valid.jpg PASS Đúng các điều kiện
small.jpg FAIL Độ phân giải thấp
square.png FAIL Sai tỷ lệ khung hình
wrong_extension.png FAIL Phần mở rộng không khớp
broken.jpg FAIL Không đọc được ảnh

Điểm quan trọng là lỗi được phát hiện trước khi file đi vào các bước xử lý tốn tài nguyên hơn.

5. Tích hợp vào pipeline tạo video bằng AI

Sau khi hoàn thành bước kiểm tra ảnh, chúng ta có thể sử dụng những file đạt yêu cầu làm đầu vào cho các công cụ tạo video.

Ví dụ, PWZ AI là một nền tảng cung cấp các công cụ tạo ảnh và video với nhiều mô hình AI khác nhau. Trong một quy trình thử nghiệm, ảnh đầu vào có thể được kiểm tra bằng script Python trước khi người dùng tải lên nền tảng để tạo video.

Cần lưu ý rằng script trong bài viết hoạt động độc lập, không sử dụng API của PWZ AI và không tự động tải file lên dịch vụ. Việc chọn mô hình, cấu hình và tạo video vẫn được thực hiện theo những chức năng mà nền tảng hỗ trợ.

6. Những giới hạn của cách làm này

Công cụ trên kiểm tra những đặc điểm kỹ thuật cơ bản của file ảnh, nhưng không đánh giá chất lượng nội dung.

Ví dụ, nó không phát hiện được:

  • Logo hoặc chữ bị sai trong ảnh.
  • Chủ thể bị biến dạng.
  • Ánh sáng không tự nhiên.
  • Hình ảnh không phù hợp với yêu cầu thương hiệu.
  • Metadata EXIF định hướng ảnh chưa được chuẩn hóa.

Ngoài ra, chương trình hiện chỉ quét file trực tiếp trong một thư mục, không duyệt thư mục con.

Với hệ thống production, nên bổ sung kiểm thử tự động, giới hạn tài nguyên, xử lý file không đáng tin cậy trong môi trường cô lập và quy trình quản lý dependency chặt chẽ hơn.

Các giới hạn như 1024 × 576, 10 MB và tỷ lệ 16:9 cần được cấu hình theo yêu cầu thực tế của dự án, thay vì áp dụng cố định cho mọi trường hợp.

7. Kết luận

Trong một pipeline tạo nội dung, không phải lỗi nào cũng cần giải quyết bằng một mô hình AI mạnh hơn.

Nhiều lỗi có thể được phát hiện sớm bằng những bước kiểm tra đơn giản: định dạng file, độ phân giải, tỷ lệ khung hình và khả năng đọc dữ liệu ảnh.

Với Python và Pillow, chúng ta có thể tạo một công cụ validation nhỏ, dễ mở rộng và có thể tích hợp vào quy trình xử lý tự động.

Đây không phải giải pháp kiểm soát chất lượng hình ảnh toàn diện. Nhưng nó là một bước đầu hợp lý để giảm những lỗi đầu vào không cần thiết trước khi chạy các tác vụ xử lý ảnh hoặc tạo video tốn tài nguyên hơn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí