Thứ Ba, 15 tháng 9, 2026

Đổi tên ảnh bằng Python (500 tấm ảnh, mỗi tấm một cái tên như mật mã? Đừng ngồi F2 từng tấm! )

Đổi tên file thông thường hay đổi tên ảnh hàng loạt luôn là công việc dễ "nản Chí Phèo" nhất, một công việc mà bất cứ ai đã từng làm thủ công cũng đều "thề" rằng không bao giờ thèm làm lại lần thứ hai!

Có một ngày bạn mở thư mục ảnh lên và thấy:

IMG_8237.jpg
IMG_8238.jpg
IMG_8239.jpg
DSC_00482.jpg
DSC_00483.jpg
photo_20260715_091233.jpg
Screenshot_20260715_102233.png

Nhìn vào thì biết ngay:

"Đây là ảnh."

Nhưng nhìn tên file thì...

"Ảnh gì? Của ai? Chụp cái gì? Ngày nào?"

Không biết. 😅

Nếu chỉ có 3–5 tấm thì thôi.

Click → F2 → đổi tên → Enter.

Lặp lại vài lần cũng chưa đến mức muốn đập bàn.

Nhưng nếu có:

100 ảnh
500 ảnh
1.000 ảnh

thì việc ngồi đổi tên từng ảnh bắt đầu trở thành một công việc rất... không đáng để con người làm.

Và đây chính là lúc Python có thể giúp.


Đổi tên ảnh bằng Python là gì?

Thật ra, nếu bạn đã đọc Bài Đổi tên file hàng loạt bằng Python, thì bài này không phải một thế giới hoàn toàn mới.

Ảnh cũng chỉ là file.

Ví dụ:

IMG_8237.jpg

vẫn là một file có:

  • tên: IMG_8237
  • phần mở rộng: .jpg

Python không cần phải "nhìn thấy" nội dung bức ảnh mới đổi được tên.

Nó chỉ cần biết:

"File này đang nằm ở đâu và tên hiện tại của nó là gì?"

Sau đó Python có thể nói:

"Được rồi, đổi tên đi."


Một ví dụ rất đời thường

Giả sử bạn vừa chụp 5 tấm ảnh ở Sơn Trà Đà Nẵng.

Điện thoại đặt tên:

IMG_8237.jpg
IMG_8238.jpg
IMG_8239.jpg
IMG_8240.jpg
IMG_8241.jpg

Bạn muốn đổi thành:

sontra_001.jpg
sontra_002.jpg
sontra_003.jpg
sontra_004.jpg
sontra_005.jpg

Nếu làm bằng tay:

F2
F2
F2
F2
F2

5 tấm thì còn được.

Nhưng nếu có 500 tấm:

F2
F2
F2
F2
...

Đến tấm thứ 200 có khi bạn bắt đầu tự hỏi:

"Mình học Python để làm gì vậy ta?" 😂

Câu trả lời chính là:

Để không phải F2 500 lần.


Python có thể đổi tên ảnh như thế nào?

Cách đơn giản nhất vẫn là dùng module os.

Ví dụ:

import os

os.rename("IMG_8237.jpg", "sontra_001.jpg")

Xong.

Python sẽ đổi:

IMG_8237.jpg

thành:

sontra_001.jpg

Không cần mở Photoshop.

Không cần mở Lightroom.

Không cần click chuột 500 lần.


Nhưng ảnh thường nằm trong một thư mục

Ví dụ cấu trúc thư mục:

project/
│
├── rename_images.py
│
└── photos/
    ├── IMG_8237.jpg
    ├── IMG_8238.jpg
    ├── IMG_8239.jpg
    └── IMG_8240.jpg

Khi đó:

import os

os.rename(
    "photos/IMG_8237.jpg",
    "photos/sontra_001.jpg"
)

Python sẽ đổi tên file bên trong thư mục photos.


Đổi tên hàng loạt mới là phần thú vị 😎

Giả sử thư mục có:

IMG_8237.jpg
IMG_8238.jpg
IMG_8239.jpg
IMG_8240.jpg
IMG_8241.jpg

Ta có thể dùng vòng lặp:

import os

for i in range(1, 6):
    old_name = f"IMG_{8236 + i}.jpg"
    new_name = f"sontra_{i:03d}.jpg"

    os.rename(
        f"photos/{old_name}",
        f"photos/{new_name}"
    )

Kết quả:

sontra_001.jpg
sontra_002.jpg
sontra_003.jpg
sontra_004.jpg
sontra_005.jpg

{i:03d} là cái gì vậy?

Nhìn hơi giống mật mã nhưng thật ra rất đơn giản.

Nếu:

i = 1

thì:

f"{i:03d}"

cho kết quả:

001

Nếu:

i = 12

thì:

012

Nếu:

i = 125

thì:

125

Tức là luôn cố gắng giữ 3 chữ số.

Vì vậy:

f"sontra_{i:03d}.jpg"

sẽ tạo:

sontra_001.jpg
sontra_002.jpg
sontra_003.jpg
...
sontra_099.jpg
sontra_100.jpg

Cách đặt tên này nhìn gọn hơn rất nhiều so với:

sontra_1.jpg
sontra_2.jpg
sontra_10.jpg
sontra_100.jpg

Nhưng có một vấn đề...

Ảnh ngoài đời đâu có ngoan như ví dụ.

Thư mục thực tế có thể là:

IMG_8237.jpg
IMG_8238.JPG
IMG_8239.jpeg
DSC_0012.jpg
photo.png
logo.webp
document.pdf
video.mp4

Lúc này nếu chúng ta viết:

for file in os.listdir("photos"):
    ...

thì Python sẽ nhìn thấy tất cả.

Cả:

.jpg
.png
.webp
.pdf
.mp4

Chúng ta chỉ muốn xử lý ảnh.

Vậy phải lọc.


Lọc những file là ảnh

Ta có thể kiểm tra phần mở rộng:

import os

image_extensions = (".jpg", ".jpeg", ".png", ".webp")

for file in os.listdir("photos"):
    if file.lower().endswith(image_extensions):
        print(file)

Kết quả có thể là:

IMG_8237.jpg
IMG_8238.JPG
IMG_8239.jpeg
photo.png
logo.webp

Còn:

document.pdf
video.mp4

sẽ bị bỏ qua.


Tại sao phải dùng .lower()?

Hãy nhìn hai file:

photo.jpg
photo.JPG

Với con người:

"Ừ, đều là JPG."

Nhưng khi xử lý chuỗi, Python phân biệt chữ hoa và chữ thường.

Nếu viết:

file.endswith(".jpg")

thì:

photo.jpg

được nhận.

Nhưng:

photo.JPG

có thể không được nhận.

Vì vậy:

file.lower().endswith(".jpg")

sẽ biến:

photo.JPG

thành:

photo.jpg

rồi mới kiểm tra.

An toàn hơn.


Đừng quên giữ lại phần mở rộng

Đây là một lỗi người mới rất dễ mắc.

Ví dụ file:

IMG_8237.jpg

Bạn muốn đổi thành:

sontra_001.jpg

Nhưng nếu vô tình tạo:

sontra_001

thì bạn đã bỏ mất .jpg.

Trong trường hợp đổi tên ảnh hàng loạt, tốt nhất là:

Đổi phần tên, nhưng giữ nguyên phần mở rộng.

Python có thể giúp chúng ta làm việc này bằng:

os.path.splitext()

Ví dụ:

name, extension = os.path.splitext("IMG_8237.jpg")

print(name)
print(extension)

Kết quả:

IMG_8237
.jpg

Sau đó:

new_name = "sontra_001" + extension

sẽ thành:

sontra_001.jpg

Ví dụ thực tế hơn

Giả sử thư mục:

photos/
├── IMG_8237.jpg
├── IMG_8238.JPG
├── DSC_0012.jpeg
├── photo.png
└── document.pdf

Ta muốn đổi tên tất cả ảnh thành:

sontra_001.jpg
sontra_002.JPG
sontra_003.jpeg
sontra_004.png

Có thể viết:

import os

folder = "photos"

image_extensions = (".jpg", ".jpeg", ".png", ".webp")

counter = 1

for file in os.listdir(folder):

    if file.lower().endswith(image_extensions):

        old_path = os.path.join(folder, file)

        name, extension = os.path.splitext(file)

        new_name = f"sontra_{counter:03d}{extension}"

        new_path = os.path.join(folder, new_name)

        print(old_path, "->", new_path)

        counter += 1

Chú ý:

Chương trình này chưa đổi tên thật.

Nó chỉ:

print(...)

để chúng ta xem Python định làm gì.

Đây là một thói quen rất đáng có.


Test trước, đổi tên sau

Đây là nguyên tắc mình rất khuyến khích khi làm việc với file:

Đừng cho Python làm thật ngay lần đầu.

Trước tiên:

print(old_path, "->", new_path)

Chạy thử.

Nếu thấy:

photos/IMG_8237.jpg -> photos/sontra_001.jpg
photos/IMG_8238.JPG -> photos/sontra_002.JPG
photos/DSC_0012.jpeg -> photos/sontra_003.jpeg

và mọi thứ đúng như mong muốn...

Lúc đó mới đổi:

print(old_path, "->", new_path)

thành:

os.rename(old_path, new_path)

Đây là khác biệt giữa:

"Mình nghĩ code chạy đúng."

và:

"Mình đã kiểm tra code trước khi cho nó đụng vào dữ liệu thật."


Một lỗi rất đáng sợ: tên mới đã tồn tại

Giả sử thư mục đã có:

sontra_001.jpg

Nhưng Python lại muốn đổi:

IMG_8237.jpg

thành:

sontra_001.jpg

Bạn không nên mặc định rằng:

"Python tự xử lý được hết."

Hãy kiểm tra trước:

if os.path.exists(new_path):
    print("Tên file đã tồn tại:", new_path)
else:
    os.rename(old_path, new_path)

Cách này giúp tránh những tình huống đổi tên không như mong muốn.


Một phiên bản hoàn chỉnh, dễ hiểu

Đây là phiên bản phù hợp để bạn thử trên một thư mục ảnh mẫu:

import os

folder = "photos"

image_extensions = (".jpg", ".jpeg", ".png", ".webp")

counter = 1

for file in os.listdir(folder):

    if not file.lower().endswith(image_extensions):
        continue

    old_path = os.path.join(folder, file)

    name, extension = os.path.splitext(file)

    new_name = f"sontra_{counter:03d}{extension}"

    new_path = os.path.join(folder, new_name)

    if os.path.exists(new_path):
        print("Bỏ qua vì tên đã tồn tại:", new_path)
        continue

    print(f"{file} -> {new_name}")

    os.rename(old_path, new_path)

    counter += 1

Chương trình làm lần lượt:

Bước 1

Mở thư mục:

folder = "photos"

Bước 2

Lấy danh sách file:

os.listdir(folder)

Bước 3

Chỉ giữ lại file ảnh:

if not file.lower().endswith(image_extensions):
    continue

Bước 4

Tách tên và phần mở rộng:

name, extension = os.path.splitext(file)

Bước 5

Tạo tên mới:

new_name = f"sontra_{counter:03d}{extension}"

Bước 6

Tạo đường dẫn đầy đủ:

new_path = os.path.join(folder, new_name)

Bước 7

Kiểm tra tên mới có tồn tại không:

if os.path.exists(new_path):
    continue

Bước 8

Đổi tên:

os.rename(old_path, new_path)

Nhưng có một chuyện cần nhớ: thứ tự file

Đây là chỗ có thể khiến người mới hơi bất ngờ.

Bạn có:

IMG_100.jpg
IMG_20.jpg
IMG_3.jpg

Python không nhất thiết hiểu rằng:

3
20
100

là thứ tự bạn đang nghĩ.

Nếu muốn chủ động hơn, có thể lấy danh sách ảnh rồi sắp xếp:

files = []

for file in os.listdir(folder):
    if file.lower().endswith(image_extensions):
        files.append(file)

files.sort()

Sau đó mới đổi tên.

Ví dụ:

files.sort()

for counter, file in enumerate(files, start=1):
    ...

enumerate() giúp chúng ta vừa lấy file vừa có số thứ tự.


Tại sao nên đổi tên ảnh có quy tắc?

Một thư mục như:

IMG_8237.jpg
DSC_0012.jpg
photo_abc.jpg
final-final-2.jpg
newnew.jpg
abc123.jpg

rất khó quản lý.

Nhưng:

sontra_001.jpg
sontra_002.jpg
sontra_003.jpg
sontra_004.jpg
sontra_005.jpg

thì dễ nhìn hơn rất nhiều.

Đặc biệt khi làm website.

Ví dụ:

product_001.jpg
product_002.jpg
product_003.jpg

hoặc:

danang_001.jpg
danang_002.jpg
danang_003.jpg

Tên file rõ ràng cũng giúp con người quản lý dữ liệu dễ hơn.


Nếu có hàng nghìn ảnh thì sao?

Đây mới là lúc Python bắt đầu "đi làm".

Ví dụ bạn có:

2.000 ảnh sản phẩm

và muốn:

product_0001.jpg
product_0002.jpg
product_0003.jpg
...
product_2000.jpg

Bạn không cần viết 2.000 dòng code.

Chỉ cần vòng lặp.

Ví dụ:

for i, file in enumerate(files, start=1):
    print(f"{file} -> product_{i:04d}.jpg")

04d nghĩa là giữ 4 chữ số:

0001
0002
0003
...
0099
0100
1000

Python làm phần lặp.

Bạn chỉ cần nói quy tắc.

Đây chính là tư duy automation:

Con người đặt luật. Máy làm phần lặp lại.


Đổi tên ảnh không có nghĩa là Python phải hiểu nội dung ảnh

Đây là một điểm rất quan trọng.

Khi chúng ta viết:

os.rename(...)

Python chỉ đang xử lý file.

Nó không biết:

"À, trong ảnh này có con mèo."

Hay:

"Đây là ảnh biển Sơn Trà lúc hoàng hôn."

Muốn Python:

  • đọc ảnh,
  • thay đổi kích thước,
  • nén ảnh,
  • nhận diện khuôn mặt,
  • nhận diện vật thể,
  • thêm watermark,

thì đó là những bài toán khác.

Có thể cần thêm thư viện như Pillow hoặc các công cụ AI/computer vision.

Nhưng Bài #71 chỉ tập trung vào đổi tên ảnh.

Đừng thấy chữ "ảnh" rồi lập tức kéo cả AI vào. 😄


Một lỗi kinh điển: chạy nhầm thư mục

Bạn chạy:

os.listdir("photos")

nhưng Python báo:

FileNotFoundError

Đừng vội kết luận:

"Python bị điên."

Hãy kiểm tra thư mục hiện tại:

import os

print(os.getcwd())

Python sẽ cho biết chương trình đang chạy ở đâu.

Ví dụ:

C:\Users\Monkey\Desktop\python-project

Nếu thư mục thật sự nằm ở:

C:\Users\Monkey\Desktop\python-project\photos

thì:

folder = "photos"

là hợp lý.

Nhưng nếu thư mục nằm chỗ khác thì phải sửa đường dẫn.


Có thể dùng đường dẫn đầy đủ không?

Có.

Ví dụ Windows:

folder = r"C:\Users\Monkey\Pictures\SonTra"

Chữ r phía trước chuỗi giúp Python xử lý đường dẫn Windows dễ hơn.

Hoặc dùng /:

folder = "C:/Users/Monkey/Pictures/SonTra"

Cả hai cách đều có thể hữu ích.


Đừng thử ngay trên thư mục 2.000 ảnh

Đây là lời khuyên thật lòng. 😅

Nếu mới học, hãy tạo:

test_photos/

bên trong chỉ có:

IMG_1.jpg
IMG_2.jpg
IMG_3.jpg
IMG_4.jpg
IMG_5.jpg

Chạy thử.

Nếu đúng:

sontra_001.jpg
sontra_002.jpg
sontra_003.jpg
sontra_004.jpg
sontra_005.jpg

thì hãy nghĩ đến thư mục thật.

Và nếu dữ liệu quan trọng:

Backup trước khi chạy script.

Một dòng:

os.rename(...)

trông rất hiền.

Nhưng nếu logic sai thì 2.000 file cũng bị đổi tên rất nhanh.

Python không biết tiếc đâu. 😂


Chua thêm 😭

Có những người nhìn thư mục:

IMG_0001.jpg
IMG_0002.jpg
IMG_0003.jpg
...
IMG_0500.jpg

rồi nói:

"Để cuối tuần rảnh mình đổi tên."

Cuối tuần đến:

"Thôi để tuần sau."

Tuần sau:

"Thôi để khi nào cần."

Đến lúc cần tìm:

"Ủa ảnh cái này tên gì ta?"

Mở Google:

"Làm sao đổi tên 500 files."

Rồi cài một phần mềm.

Trong khi Python ngồi một góc:

os.rename(...)

và nhìn bạn:

"Gọi tôi từ đầu có phải đỡ khổ không?" 😭


Một tư duy quan trọng hơn cả đoạn code

Bài này không chỉ dạy bạn:

os.rename()

Mà quan trọng hơn là dạy một cách suy nghĩ.

Khi gặp một công việc lặp lại, hãy tự hỏi:

"Việc này có quy luật không?"

Ví dụ:

ảnh 1 → sontra_001
ảnh 2 → sontra_002
ảnh 3 → sontra_003
...

Có quy luật.

Vậy máy tính có thể làm.

Đây chính là nền móng của Automation.

Sau này quy mô lớn hơn:

đổi tên file
↓
đọc file
↓
lọc dữ liệu
↓
xử lý dữ liệu
↓
lấy dữ liệu từ website
↓
lưu dữ liệu
↓
gửi email
↓
tạo báo cáo

Bạn sẽ bắt đầu nhận ra:

"À... Python không chỉ để làm bài tập."

Python có thể làm những công việc mà trước đây mình ngồi click chuột cả buổi.


Checklist trước khi chạy chương trình đổi tên ảnh

☑ Xác định đúng thư mục ảnh.

☑ Kiểm tra os.getcwd() nếu đường dẫn có vấn đề.

☑ Chỉ lọc những phần mở rộng cần thiết:

(".jpg", ".jpeg", ".png", ".webp")

☑ Dùng .lower() để tránh vấn đề .JPG / .jpg.

☑ Giữ lại phần mở rộng của ảnh.

☑ Kiểm tra tên mới có bị trùng.

☑ Dùng print() để xem trước kết quả.

☑ Thử trên 3–5 ảnh trước.

☑ Backup nếu ảnh quan trọng.

☑ Sau khi chắc chắn mới cho os.rename() chạy thật.


FAQ nhanh

1. Python có đổi được .jpg.png cùng lúc không?

Có.

Ví dụ:

image_extensions = (".jpg", ".jpeg", ".png", ".webp")

2. Đổi tên ảnh có làm giảm chất lượng ảnh không?

Không.

os.rename() chỉ đổi tên file.

Nó không chỉnh sửa nội dung ảnh.


3. Có cần cài thêm thư viện không?

Không nếu chỉ đổi tên.

os là module có sẵn trong Python.


4. Có thể đổi tên 10.000 ảnh không?

Về nguyên tắc, có.

Nhưng càng nhiều file thì càng nên:

  • kiểm tra kỹ quy tắc,
  • backup,
  • test trên bản sao,
  • xử lý trường hợp tên trùng.

Đừng biến một script 10 dòng thành một chiếc máy xay dữ liệu. 😅


5. Có nhất thiết phải dùng os không?

Không.

Python hiện đại còn có pathlib, ví dụ:

from pathlib import Path

pathlib rất đáng học.

Nhưng nếu bạn mới bắt đầu, hiểu được:

os.listdir()
os.path.join()
os.path.splitext()
os.rename()

trước cũng hoàn toàn ổn.

Quan trọng là hiểu tư duy xử lý file.


Tổng kết

Trong bài này, chúng ta đã biến một việc rất thủ công:

F2
F2
F2
F2
F2
...

thành một quy trình có thể tự động hóa bằng Python.

Bạn đã biết:

os.listdir()

để lấy danh sách file.

os.path.splitext()

để tách tên và phần mở rộng.

os.path.join()

để tạo đường dẫn.

os.path.exists()

để kiểm tra file có tồn tại.

Và quan trọng nhất:

os.rename()

để đổi tên.

Nhưng điều quan trọng nhất của bài này không phải là nhớ 4–5 hàm.

Mà là hình thành thói quen:

Thấy công việc lặp đi lặp lại → tìm quy luật → viết code → để máy làm phần lặp.

Đó chính là một trong những bước đầu tiên để chuyển từ:

"Mình biết Python."

sang:

"Mình dùng Python để giải quyết công việc thật sự."


Bạn có thể cũng đang gặp...

Nếu đang học Python từ những lỗi và công việc thực tế, bạn có thể xem lại:

  • Pip không hoạt động 🐍😭
  • Virtual Environment – Tại sao Python Developer lại thích tạo môi trường ảo?
  • requirements.txt là gì? 📦
  • Đọc CSV bằng Python 📊
  • Đổi tên file hàng loạt bằng Python 📁

Những bài này ghép lại thành một mạch khá thú vị:

Cài package
     ↓
Tạo môi trường
     ↓
Quản lý dependencies
     ↓
Đọc dữ liệu
     ↓
Xử lý file
     ↓
Đổi tên ảnh
     ↓
Web Scraping
     ↓
Automation

Và từ đây Python bắt đầu bước ra khỏi phạm vi:

"Viết vài dòng code cho vui.", có thể là suy nghĩ khi mới bước vào Đất Việt Lập Trình?!

để tiến tới:

"Làm cho máy tính làm việc thay mình."