- blind_watermark là thư viện Python nhúng watermark vô hình vào ảnh, trích ra không cần ảnh gốc.
- Thuật toán DWT-DCT-SVD trên block 4x4 chịu được xoay 45 độ, crop ngẫu nhiên, resize 0.5x và pepper noise.
- Hỗ trợ watermark dạng text, ảnh, mảng bit với password riêng cho ảnh và watermark.
- Cài bằng pip, dùng được cả Python API lẫn CLI.
TL;DR
blind_watermark là thư viện Python của tác giả guofei9987, cho phép nhúng watermark vô hình vào ảnh và trích ra mà không cần giữ ảnh gốc. Lõi thuật toán là chuỗi DWT - DCT - SVD trên block 4x4 ở vùng tần số thấp, giúp watermark mắt thường không thấy nhưng vẫn sống sót sau xoay, crop, nén JPEG và pepper noise. Hỗ trợ ba kiểu watermark (chuỗi text, ảnh nhị phân, mảng bit) cùng password tách rời cho ảnh và watermark. Cài bằng pip install blind-watermark, dùng được cả Python API lẫn CLI.
Watermark hiện và watermark vô hình khác nhau ở đâu
Watermark dạng visible (logo mờ góc dưới, chữ "PROPERTY OF X" đè ngang ảnh) có hai vấn đề kinh điển. Một là phá thẩm mỹ - không thiết kế nào chấp nhận được nếu ảnh là sản phẩm chính. Hai là dễ xoá - chỉ cần crop hoặc heal trong Photoshop là biến mất, hoặc tệ hơn là inpaint bằng vài model image-to-image bây giờ.
Blind watermark đi hướng ngược lại. Dữ liệu được giấu vào những hệ số tần số của ảnh thay vì pixel ở vùng nhìn thấy. Mắt người không phát hiện thay đổi đó vì hệ thống thị giác kém nhạy với biến đổi nhỏ trong miền tần số thấp, nhưng máy thì đọc lại được nếu biết password và shape. "Blind" trong tên thư viện có nghĩa: lúc trích watermark, bạn không cần ảnh gốc làm tham chiếu, chỉ cần ảnh đã nhúng.
Đó là điểm thực tế nhất. Đa số nhu cầu watermark ngoài đời (truy vết rò rỉ ảnh nội bộ, đánh dấu dataset, chứng minh ownership của một bộ ảnh phát đi nhiều bên) không có ảnh gốc lúc cần đối chứng.
Cách thuật toán hoạt động

Ảnh đầu vào đi qua ba phép biến đổi nối tiếp, watermark nằm ở singular value của block 4x4.
Pipeline embed gồm ba phép biến đổi nối tiếp, mỗi phép giải quyết một loại tấn công khác nhau.
DWT (Discrete Wavelet Transform). Tách ảnh thành thành phần xấp xỉ (low frequency) và thành phần chi tiết (high frequency). Watermark chỉ nhúng vào thành phần xấp xỉ vì vùng này bền hơn trước nén và lọc.
DCT (Discrete Cosine Transform). Chia thành phần xấp xỉ thành các block 4x4 non-overlapping rồi DCT từng block. DCT cùng họ phép biến đổi với JPEG, nên nhúng ở đây tự nhiên "đồng pha" với cách JPEG nén lại sau này.
SVD (Singular Value Decomposition). Phân tích mỗi block DCT thành
U . S . V^T. Bit watermark được nhúng bằng cách quantize hai singular value lớn nhấts[0]vàs[1]theo bướcd1 = 36vàd2 = 20mặc định. Bit 0 và bit 1 rơi vào hai vùng quantization khác nhau.
Khi extract, thư viện làm ngược lại: DWT, DCT, SVD trên ảnh đã nhúng, đọc giá trị singular value rồi suy ngược ra bit. Để chống nhiễu khi ảnh bị tấn công, mỗi bit watermark được lặp tuần hoàn trên nhiều block ở cả ba kênh màu YUV, sau đó vote bằng K-means adaptive threshold. Theo tài liệu thuật toán, xác suất sai bit có thể xuống quanh 1e-9 nếu số lần lặp đủ lớn so với độ dài watermark.
Có một trade-off cần biết: d1, d2 càng lớn thì watermark càng bền với tấn công nhưng ảnh càng méo. Mặc định 36/20 đã cân bằng cho ảnh photo bình thường, riêng ảnh phẳng nhiều vùng đồng màu thì nên giảm để tránh nhìn thấy nhiễu trên gradient.
Quick start với 3 dòng Python
Cài đặt:
pip install blind-watermarkNhúng chuỗi text vào ảnh:
from blind_watermark import WaterMark
bwm = WaterMark(password_img=1, password_wm=1)
bwm.read_img('pic/ori_img.jpg')
bwm.read_wm('@guofei9987', mode='str')
bwm.embed('output/embedded.png')
len_wm = len(bwm.wm_bit) # ghi nhớ để extractTrích watermark từ ảnh đã nhúng:
from blind_watermark import WaterMark
bwm = WaterMark(password_img=1, password_wm=1)
text = bwm.extract('output/embedded.png', wm_shape=len_wm, mode='str')
print(text) # @guofei9987Hai password tách rời (password_img và password_wm) đóng vai trò shuffling - người không có cả hai mã sẽ extract ra rác. Nếu mất password, watermark coi như mất luôn, không có backdoor.
Với watermark là ảnh nhị phân:
bwm.read_wm('pic/watermark.png')
bwm.embed('output/embedded.png')
bwm.extract(filename='output/embedded.png', wm_shape=(128, 128))Hoặc dùng CLI nếu chỉ cần một lần:
blind_watermark --embed --pwd 1234 ori_img.jpeg "watermark text" embedded.png
blind_watermark --extract --pwd 1234 --wm_shape 111 embedded.pngKhả năng kháng tấn công
Phần đáng giá nhất của thư viện là bộ test robustness có sẵn. Cùng một watermark sau khi nhúng vào ảnh, tác giả tấn công ảnh bằng các biến đổi phổ biến rồi extract lại để kiểm tra. Các attack đã pass:
Xoay 45 độ rồi crop về khung vuông.
Random crop một vùng nhỏ trong ảnh.
Mask đè khối đen lên một vùng tự chọn.
Cắt dọc hoặc cắt ngang 50% ảnh.
Resize xuống 0.5x rồi resize trở lại.
Thêm pepper noise nồng độ cao.
Giảm sáng đồng đều 10%.
Điểm chung của các attack ở trên là chúng đều giữ lại phần lớn năng lượng tần số thấp - chỗ watermark đang ở. Nên về mặt thuật toán, blind_watermark có thể tự tin với mọi attack thuộc nhóm này. Còn các attack nhắm đúng vào tần số thấp (blur quá nặng, nén JPEG quality dưới 30, resize xuống dưới 0.25x) thì watermark sẽ degrade nhanh - đây là giới hạn vật lý chứ không riêng gì thư viện này.
Ba kiểu watermark và multiprocessing
API hỗ trợ ba loại payload qua tham số mode:
mode='str'- watermark là chuỗi UTF-8. Phù hợp khi gắn tag identifier hoặc message ngắn. Cần truyền lạiwm_shapebằng độ dài bit khi extract.mode='bit'- watermark làlist[bool]. Phù hợp khi nhúng dữ liệu nhị phân raw (UUID, hash rút gọn, signature).Mặc định (không truyền
mode) - watermark là ảnh nhị phân, cần truyềnwm_shape=(H, W)khi extract.
Tham số processes điều khiển multiprocessing. Đặt processes=None để dùng toàn bộ CPU, hoặc số cụ thể nếu chạy chung với task khác. Ảnh cỡ 1080p embed dưới 1 giây trên máy desktop.
Khi nào dùng, khi nào không
Phù hợp:
Truy vết nguồn rò rỉ. Mỗi nhân viên nhận một bản ảnh với watermark khác. Khi ảnh leak ra ngoài, extract watermark để biết chính xác bản nào rò.
Đánh dấu dataset training. Nhúng tag identifier vào ảnh trong dataset để phát hiện model nào đã huấn luyện trên dữ liệu của bạn.
Chứng minh tác quyền lúc tranh chấp. Nếu lưu trữ password cẩn thận, watermark là bằng chứng có trước thời điểm đối phương dùng ảnh.
Không phù hợp:
Chứng minh ảnh nguyên vẹn. blind_watermark không phải cryptographic signature, không phát hiện ảnh đã bị chỉnh sửa pixel-level.
Watermark cho video. Chưa có version chuyên cho video native. Nhúng từng frame được nhưng tốn tài nguyên và mất sync khi re-encode.
Bí mật tuyệt đối. Nếu attacker biết bạn dùng blind_watermark, họ có thể thử brute force password hoặc resize ảnh xuống đủ nhỏ để xoá watermark.
Kết
blind_watermark giải quyết đúng một bài toán cụ thể: nhúng tag vô hình vào ảnh sao cho extract được mà không cần ảnh gốc, đồng thời sống qua các biến đổi đời thường. Code Python thuần, API gọn, có CLI cho trường hợp ad-hoc. Nếu bạn đang nghĩ tới chuyện theo dõi nguồn rò rỉ ảnh, đánh dấu dataset hoặc gắn signature cho một bộ ảnh phát đi nhiều bên, đây là một option đáng thử trước khi tự cài. via guofei9987/blind_watermark
Đạo hữu là phàm nhân, tu tiên giả
... hay AI cào nội dung?
Tất cả nội dung tại đạo quán đều miễn phí. Đạo hữu chỉ cần nhập email của mình để đọc tiếp. Nói KHÔNG với Spam. Huỷ subcribe lúc nào đạo hữu thích.
nếu không muốn nhận newsletter thì có thể nhập mail phụ
