
3分鐘給圖片加上看不見的盲水印:blind_watermark 快速實戰指南【免費下載鏈接】blind_watermarkBlindInvisible Watermark 圖片盲水印提取水印無須原圖項目地址: https://gitcode.com/GitHub_Trending/bl/blind_watermark你剛把插畫發出去三天,發現它掛在了別人主頁當頭像,而平臺只會讓你自證原創。截圖加時間戳不算證據,最直接的,是在圖片里放一個肉眼看不見、事后還能取出來的標記。blind_watermark 就是做這件事的 Python 庫:它把文字或圖片做成盲水印嵌進照片,之后提取水印無須原圖,也不需要當初那張底圖。blind_watermark 怎么裝,兩分鐘跑通第一張圖安裝就一條命令:pip install blind-watermark裝完直接用 Python API,嵌入和提取各幾行。假設你有一張圖pic/ori_img.jpeg,想嵌一句文字:from blind_watermark import WaterMark bwm WaterMark(password_img1, password_wm1) bwm.read_img(pic/ori_img.jpeg) bwm.read_wm(guofei9987 開源萬歲!, modestr) bwm.embed(output/embedded.png) print(len(bwm.wm_bit)) # 記下來,提取水印要用到modestr表示嵌文字;換成read_wm(pic/watermark.png)就是嵌一張小圖片,modebit則是直接塞 0/1 數據。提取時把之前記下的長度作為wm_shape傳回去:bwm2 WaterMark(password_img1, password_wm1) wm_extract bwm2.extract(output/embedded.png, wm_shape111, modestr) print(wm_extract) # guofei9987 開源萬歲!不想寫代碼也行,命令行把嵌入和提取都包好了:blind_watermark --embed --pwd 1234 examples/pic/ori_img.jpeg watermark text examples/output/embedded.png blind_watermark --extract --pwd 1234 --wm_shape 111 examples/output/embedded.png盲水印的嵌入和提取到底在做什么先看效果。左邊是原圖,右邊是嵌入水印后的圖,肉眼幾乎找不出差別,但第二張圖里已經裝進了完整的文字水印:嵌入:把 0 和 1 寫成半步位移可以把它理解成在樂器的泛音里刻字:人耳聽的是主旋律(圖像里人眼敏感的亮度、顏色),而水印寫在人眼不敏感的頻域細節里,聽起來還是原曲,懂行的人卻能聽出來。具體做法在 blind_watermark/bwm_core.py:每個 4×4 小塊的最強頻率分量,被取整到一個基準值,然后 0 不動、1 抬半步。人眼看的是整體明暗,對這種半步級的細節不敏感,所以圖看起來沒變。提取:為什么不需要原圖關鍵有兩點。第一,信息靠的是半步位移本身,不是某個像素的絕對值——提取時只看分量對基準值取余,判斷它落在半步的哪一側,原圖像素根本不參與判斷。第二,同一個 bit 被循環寫進很多小塊、三個顏色通道各寫一份,提取時把幾百上千份投票求平均,個別塊被噪聲干擾也會被沖掉。所以提取只需要三樣東西:被攻擊后的圖、兩個密碼、水印比特長度。底圖從來就不在依賴清單里,這就是盲的含義。 打它幾下試試:旋轉、加噪、縮放扛不扛得住別光聽它說,自己動手打。攻擊函數都放在 blind_watermark/att.py,完整演示在 examples/example_str.py,下面三招都是照它跑的。旋轉:把圖轉 60°,再轉回來,直接提取——結果還是完整的水印文字,一個字節不少。椒鹽噪聲:按 5% 概率往圖里撒白色噪點,模擬傳輸和劣質壓縮。加噪后的圖明顯臟了,提取依舊正確。原因是前面說的冗余:一個 bit 被寫了上千份,噪點打壞幾份,平均下來票還是對的。縮放:把圖縮到 400×300 再拉回原尺寸,提取正常。注意縮到的小圖四周會有空白,拉回去只是尺寸復原,水印跟著塊一起縮放,所以還能讀出來。README 里還列了遮擋、裁剪、亮度共 8 類攻擊,提取結果全部一致。其中裁剪稍微特殊:如果你不知道被裁去了哪里,可以用 blind_watermark/recover.py 的estimate_crop_parameters先推測裁剪位置和縮放比例,再recover_crop補回原尺寸,然后照常提取。?? 底層怎么實現的:水印寫在 DWT-DCT-SVD 鏈路上整條鏈路在 blind_watermark/bwm_core.py,用一句話說:圖像先做 DWT(離散小波變換,把圖拆成人眼敏感的低頻和細節高頻),取低頻部分切成 4×4 小塊;每塊做 DCT(離散余弦變換,把能量集中到少數系數上);再對塊做 SVD(奇異值分解,拆出幾個強度分量 s[0]、s[1]),把水印位按取整到基準 半步位移寫進這兩個分量,然后層層逆變換回圖像。兩個密碼其實是兩個隨機種子:password_img決定各小塊內部系數怎么置換,password_wm決定水印比特順序怎么打亂——沒有種子,你連哪個塊對應第幾位都不知道。提取端用同一組種子還原順序,逐塊讀出 0/1,三通道求平均后經過一維 k-means 找到 0 和 1 的自動分界,輸出干凈的水印。魯棒性基本就來自多份冗余 平均 自動閾值這套組合拳。適合誰,不適合誰適合:在社交平臺、圖庫發布作品,想事后能自證原創的創作者和攝影師;需要給一批圖各打一個編號做溯源的內容平臺(用 bit 模式,每張圖嵌一段 ID);以及分發格式可控、能拿到 PNG 或高質量 JPG 的場景。不適合:指望被人隨意裁剪、二次壓縮、換角度上傳之后還能無參考提取——裁剪還原需要一張攻擊前的圖做參照,旋轉回正需要你知道轉了多少度;也不做視頻水印,只處理圖片。還有一個常見誤解:那兩個密碼是打亂順序的隨機種子,只防順手提取,不是加密,別拿它當保密通信的密鑰。 用之前先知道的幾件事提取必須給長度。extract的wm_shape要傳嵌入時len(bwm.wm_bit)的值,嵌入那一刻就把它存進數據庫,丟了就提取不了。存 PNG,少折騰 JPG。水印圖再被有損壓縮一遍會多一層損失,embed()支持compression_ratio控制輸出質量,但最穩妥是分發無損格式。密碼要對齊,別指望它加密。嵌入和提取的password_img、password_wm必須一致,它們是種子,換了就全亂。裁剪和縮放要留底。用 recover 模塊還原裁剪時,參照物是攻擊前那張嵌好水印的圖,所以發布渠道里留一份原發圖。容量夠用但不無限。可嵌比特數約為(高/8)×(寬/8),一張 1108×738 的圖大約能裝 1.2 萬 bit,塞一句帶 ID 的短文本綽綽有余。blind_watermark 把圖片盲水印從論文概念變成了三五行代碼就能驗證的工具,嵌入、提取、抗攻擊全鏈路都是現成的。建議你先拿自己的一張真實圖,把 examples/example_str.py 里的旋轉、椒鹽、縮放三種攻擊跑一遍,確認你的分發鏈路(尤其是壓縮程度)下水印提取無誤,再接入正式流程。【免費下載鏈接】blind_watermarkBlindInvisible Watermark 圖片盲水印提取水印無須原圖項目地址: https://gitcode.com/GitHub_Trending/bl/blind_watermark創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考