Python+OpenCV圖片去水印的多種方案實(shí)現(xiàn)
1. 前言
本文為作者學(xué)習(xí)記錄,使用Python結(jié)合OpenCV,總結(jié)了幾種常見的水印去除方式,簡(jiǎn)單圖片去水印效果良好,但是復(fù)雜圖片有點(diǎn)一言難盡,本文部分代碼僅供參考,并不能針對(duì)所有水印通用,需要根據(jù)具體水印顏色、位置等情況進(jìn)行分析調(diào)整代碼。
2. 顏色介紹
本文總共使用了兩種格式的顏色,一種是BGR
,另一種是HSV
。
關(guān)于如何獲取BGR
的顏色,可以直接使用截圖或者吸取顏色的工具吸取即可。如下圖:
有一點(diǎn)需要注意:Python里面用的是BGR
,截圖工具給的是RGB
,這個(gè)使用的使用需要調(diào)整下順序
HSV
是由色調(diào)(H),飽和度(S),亮度(V)組成,如何獲取HSV
的值,這里提供一段Python的代碼獲取。其中'image/3_water.jpg'
替換成你的圖片路徑。詳細(xì)如下:
import cv2 import numpy as np from matplotlib import pyplot as plt image=cv2.imread('image/3_water.jpg') HSV=cv2.cvtColor(image,cv2.COLOR_BGR2HSV) def getpos(event,x,y,flags,param): if event==cv2.EVENT_LBUTTONDOWN: #定義一個(gè)鼠標(biāo)左鍵按下去的事件 print(HSV[y,x]) cv2.imshow("imageHSV",HSV) cv2.imshow('image',image) cv2.setMouseCallback("imageHSV",getpos) cv2.waitKey(0)
效果圖如下,左邊的為原圖,右邊的為轉(zhuǎn)為HSV
的圖片,點(diǎn)擊你需要獲取顏色的位置,會(huì)在控制臺(tái)打印對(duì)應(yīng)的顏色值。
3. 添加水印
先準(zhǔn)備幾張測(cè)試圖片,給這些圖片打上水印。這里以下面的圖片經(jīng)行演示。
添加水印代碼如下:
import cv2 import numpy as np def create_watermark(image_path): # 讀取圖像 image = cv2.imread(image_path) # 設(shè)置水印文本 watermark_text = 'www.xiaoxiaofeng.com' # 設(shè)置字體 font = cv2.FONT_HERSHEY_SIMPLEX # 設(shè)置字體大小 font_scale = 0.5 # 注意,這里是BGR 藍(lán)色(B)、綠色(G)和紅色(R) font_color = (62, 62, 187) # 設(shè)置字體粗細(xì) thickness = 1 # 獲取圖像的高度和寬度 height, width = image.shape[:2] # 設(shè)置文本位置(右下角) text_position = ( width - 200, height - 20 ) # 例如,在右下角 # 添加水印文本 cv2.putText(image, watermark_text, text_position, font, font_scale, font_color, thickness, cv2.LINE_AA) # 顯示圖像 cv2.imshow('Watermarked Image', image) cv2.waitKey(0) cv2.destroyAllWindows() # 保存圖像 cv2.imwrite('image/2_water.jpg', image) create_watermark('image/2.jpg')
添加完水印的效果如下圖:
4. 去除水印
關(guān)于去除水印,效果最好的應(yīng)該還是訓(xùn)練模型,用模型去除效果肯定比較好,但是對(duì)于簡(jiǎn)單的水印,也沒必要去訓(xùn)練模型,而且訓(xùn)練模型的門檻比較高,自己的"超配00年代"的電腦就別想了。
這里針對(duì)幾種常見的水印,簡(jiǎn)單的描述下去水印的思想,以及實(shí)現(xiàn)代碼。
4.1 文檔類圖片去水印
關(guān)于圖片準(zhǔn)備,這里直接用word創(chuàng)建了一個(gè)帶水印的文檔,然后截圖,圖片如下:
實(shí)現(xiàn)目標(biāo):去除中間背景的中的【笑小楓】的水印。
實(shí)現(xiàn)思想:背景為白色,字體顏色為黑色,水印顏色為灰色,因此可以將水印的灰色替換為白色即可
方案一:
通過觀測(cè),水印的顏色大多為(214, 214, 214)
,但是邊緣的鋸齒處有部分顏色為214-245
之間,這里定義3個(gè)色彩相加之和位于 640-740
之間的,全部替換為白色,當(dāng)然這樣可能會(huì)誤傷一部分顏色,具體需要針對(duì)多種方案比較選用。
import numpy as np import cv2 def remote_water_mark_1(image): # 讀取圖像 image = cv2.imread(image) # 顯示原始圖像 cv2.imshow('Original Image', image) # 設(shè)置替換顏色為白色 replace_color = (255, 255, 255) # 獲取圖片大小 height, width = image.shape[:2] for i in range(height): for j in range(width): # 獲取當(dāng)前像素點(diǎn)的顏色值 varP = image[i, j] # 如果當(dāng)前像素點(diǎn)的顏色值總和在640到760之間,則替換為白色 if sum(varP) > 640 and sum(varP) < 740: image[i, j] = replace_color # 顯示處理后的圖像 cv2.imshow('Result Image', image) cv2.waitKey(0) remote_water_mark_1('image/3.jpg')
去水印后的效果圖如下:
可以看到,圖片底部的水印去掉了,仔細(xì)看圖片中的文字顏色有點(diǎn)細(xì)微變化,這就是因?yàn)椴糠窒袼仡伾徽`傷了導(dǎo)致的。下面看下方案二,可以解決這個(gè)問題。
方案二:
和方案一的思想一致,但是不再使用BGR
的顏色處理圖片,而是使用HSV
對(duì)圖片進(jìn)行處理。通過創(chuàng)建顏色范圍的掩碼,替換掉對(duì)應(yīng)像素的顏色,具體代碼如下:
import numpy as np import cv2 def remote_water_mark_2(image): # 讀取圖像 image = cv2.imread(image) # 顯示原始圖像 cv2.imshow('Original Image', image) # 將圖像從BGR顏色空間轉(zhuǎn)換為HSV顏色空間 hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 定義要替換的顏色范圍(在 HSV 空間中) lower_blue = np.array([0, 0, 214]) upper_blue = np.array([0, 0, 245]) # 在HSV圖像中,根據(jù)定義的顏色范圍創(chuàng)建掩碼 mask = cv2.inRange(hsv_image, lower_blue, upper_blue) # 顯示掩碼圖像 cv2.imshow('mask Image', mask) # 將掩碼中對(duì)應(yīng)位置的顏色替換為紅色(在 HSV 空間中),白底在HSV空間就是紅色。 hsv_image[mask > 0] = [0, 0, 255] # 如果需要,將圖片轉(zhuǎn)換回 BGR 顏色空間 result_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) # 顯示結(jié)果圖像 cv2.imshow('Result Image', result_image) cv2.waitKey(0) remote_water_mark_2('image/3.jpg')
去水印后的效果圖如下,可以通過mask
掩碼圖像(黑色背景,白色水印圖)清晰的看到水印的形狀。這里可以根據(jù)mask
掩碼調(diào)整顏色區(qū)間的參數(shù)??梢钥吹接疫厛D片成功去除水印,并且文字顏色一致。
4.2 固定位置水印去除方式
上文提到了,水印背景顏色如果和圖片顏色類型,可能會(huì)誤傷,出現(xiàn)意向不到問題。所有針對(duì)可以確認(rèn)固定位置的水印,我們盡量處理固定位置,減少對(duì)圖片的損傷。
如下圖:水印固定在右下角,顏色和字體顏色基本一致,這樣如果全圖處理,整張圖片就面目全非了。所以我們可以針對(duì)右下角固定的位置,特殊處理。
代碼如下:
import numpy as np import cv2 def remote_water_mark_3(image): # 讀取圖像 image = cv2.imread(image) # 顯示原始圖像 cv2.imshow('Original Image', image) # 獲取圖像的高度和寬度 height, width = image.shape[:2] # 定義 ROI 的坐標(biāo)和大小 x, y, w, h = width-280, height-40, 280, 40 roi = image[y:y+h, x:x+w] # 將 ROI 從 BGR 顏色空間轉(zhuǎn)換為 HSV 顏色空間 hsv_image = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) # 定義要替換的顏色范圍,范圍盡量越小越好(在 HSV 空間中) lower_blue = np.array([0, 0, 0]) upper_blue = np.array([0, 0, 240]) # 創(chuàng)建掩碼 mask = cv2.inRange(hsv_image, lower_blue, upper_blue) # 替換顏色 hsv_image[mask > 0] = [0, 0, 255] # 將匹配的顏色替換為紅色(在 HSV 空間中) # 如果需要,將圖片轉(zhuǎn)換回 BGR 顏色空間 roi = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) # 將處理后的 ROI 放回原圖 image[y:y+h, x:x+w] = roi # 顯示處理后的圖像 cv2.imshow('Result Image', image) cv2.waitKey(0) remote_water_mark_2('image/1_water.jpg')
處理后的效果如下圖所示
可以看見水印已經(jīng)去掉了。因?yàn)檫@里背景是白色,所以很好處理,但如果背景不是白色,而是一些其他顏色改怎么處理呢?接下來看下面
4.3 復(fù)雜背景色的水印處理
針對(duì)復(fù)雜背景色的圖片,處理時(shí)肯定會(huì)一定程度的損傷圖片了,如果需要相對(duì)精準(zhǔn),可以訓(xùn)練模型處理,單純使用代碼,還是有一定程序限制。如果水印位置不固定,數(shù)量不固定,大小不固定等等,代碼局限性就很大了,純openCV代碼暫還沒找到方案,這里還是以簡(jiǎn)單的示例。
先看下面這張相對(duì)簡(jiǎn)單的圖片
方案一:
使用inpaint
函數(shù)修復(fù)圖片,代碼如下:
import numpy as np import cv2 def remote_water_mark_6(image): # 讀取圖像 image = cv2.imread(image) # 顯示原始圖像 cv2.imshow('Original Image', image) height, width = image.shape[:2] # 創(chuàng)建一個(gè)掩碼,標(biāo)記水印區(qū)域 mask = np.zeros(image.shape[:2], np.uint8) height, width = image.shape[:2] # 假設(shè)水印在這個(gè)區(qū)域,繪制矩形掩碼 cv2.rectangle(mask, (width-220, height-50), (width, height), 255, -1) # 使用inpaint函數(shù)修復(fù)圖像 denoised_image = cv2.inpaint(image, mask, 1, cv2.INPAINT_TELEA) # 顯示結(jié)果圖像 cv2.imshow('Result Image', denoised_image) cv2.waitKey(0) remote_water_mark_6('image/2_water.jpg')
處理后的效果圖如下,可以看到水印處理掉了,但是圖片水印處有略微變形。
針對(duì)下面這張圖片進(jìn)行測(cè)試:
可以看到水印雖然去掉了,但是水印出糊的很厲害
方案二:
此方案為自己寫的,暫未經(jīng)大量圖片測(cè)試,但測(cè)試了部分圖片,效果還可,因此放在這里做個(gè)比較
實(shí)現(xiàn)思想:實(shí)現(xiàn)步驟基本于上面一致,針對(duì)水印顏色區(qū)間像素進(jìn)行顏色替換,替換的顏色值,這里取周邊像素顏色出現(xiàn)次數(shù)最多的顏色做替換。然后對(duì)區(qū)域圖片進(jìn)行噪點(diǎn)處理,盡量中和處理部分于原圖像的匹配度,如果水印下方是文字類型,不可以進(jìn)行噪點(diǎn)處理。
具體代碼如下:
具體使用時(shí)需要根據(jù)水印位置和顏色調(diào)整對(duì)應(yīng)的參數(shù)
import numpy as np import cv2 from collections import Counter def find_most_frequent_color(color_list): """ 找到顏色列表中出現(xiàn)頻率最高的顏色。 Args: color_list (list): 顏色列表,每個(gè)顏色可以是一個(gè)包含三個(gè)整數(shù)的列表,分別表示RGB值。 Returns: tuple: 出現(xiàn)頻率最高的顏色,以元組形式返回,包含三個(gè)整數(shù),分別表示RGB值。 """ # 將顏色列表中的每個(gè)顏色轉(zhuǎn)換為元組形式 color_list = [tuple(color) for color in color_list] # 使用 Counter 統(tǒng)計(jì)每種顏色出現(xiàn)的次數(shù) color_counts = Counter(color_list) # 獲取出現(xiàn)次數(shù)最多的顏色,并返回該顏色 return color_counts.most_common(1)[0][0] def remote_water_mark_5(image): # 讀取圖像 image = cv2.imread(image) # 顯示原始圖像 cv2.imshow('Original Image', image) height, width = image.shape[:2] # 定義 ROI(水印的位置,需要根據(jù)實(shí)際情況調(diào)整) x, y, w, h = width-200, height-35, 200, 35 # ROI 的坐標(biāo)和大小 roi = image[y:y+h, x:x+w] for yy in range(25, -1, -1): for xx in range(195): # 獲取當(dāng)前像素的顏色 pixel_color = roi[yy, xx] pixel_color_sum = sum(pixel_color[:3]) # 檢查當(dāng)前像素的顏色是否與要替換的顏色匹配,需要根據(jù)實(shí)際情況調(diào)整 if (pixel_color_sum > 300 and pixel_color_sum < 650): if sum(roi[yy, xx]) == sum(roi[yy, xx-1]) and sum(roi[yy, xx]) == sum(roi[yy+1, xx]): continue is_fix = False color_set = [roi[yy, xx]] for i in range(5, -1, -1): if is_fix: break temp = roi[yy + i, xx + i] temp1 = roi[yy - i, xx - i] color_set.append(temp) color_set.append(temp1) color_set.append( roi[yy + i, xx + 2]) color_set.append( roi[yy + 2, xx + i]) color_set.append( roi[yy - i, xx - 2]) color_set.append( roi[yy - 2, xx - i]) color_set.append( roi[yy + i, xx - i]) color_set.append( roi[yy - i, xx + i]) if sum(temp) == sum(temp1): roi[yy, xx] = temp is_fix = True elif i == 1: most_frequent_color = find_most_frequent_color(color_set) roi[yy, xx] = most_frequent_color # 濾波窗口大小,如果背景處是文字,不可以進(jìn)行噪點(diǎn)處理,不然會(huì)糊掉 kernel_size = 3 # 對(duì) ROI 進(jìn)行中值濾波 roi = cv2.medianBlur(roi, kernel_size) # 將處理后的 ROI 放回原圖 image[y:y+h, x:x+w] = roi # 顯示處理后的圖像 cv2.imshow('Result Image', image) cv2.waitKey(0) remote_water_mark_5('image/4_water.jpg')
測(cè)試效果如下圖所示:
下面這個(gè)圖,去除了噪點(diǎn)處理的代碼。
4.4 訓(xùn)練模型(未完成)
作者嘗試過進(jìn)行訓(xùn)練模型處理,但在訓(xùn)練數(shù)據(jù)時(shí),電腦CPU咔咔100%,因此放棄。這里就不附代碼供大家參考,因?yàn)闆]有訓(xùn)練出模型,不知道效果如何,也不知道對(duì)不對(duì)。
5. 本文總結(jié)
本文寫了幾種去水印的方案,具體如何選擇,小伙伴們可以根據(jù)實(shí)際情況去選擇,本文也是我使用python去水印一路研究過來的總結(jié)。
因?yàn)閯倓偨佑|python不多,如有錯(cuò)誤之處,大家可以幫忙指出來,感謝!
以上就是Python+OpenCV圖片去水印的多種方案實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Python OpenCV圖片去水印的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python中實(shí)現(xiàn)數(shù)組和列表讀取一列的方法
下面小編就為大家分享一篇python中實(shí)現(xiàn)數(shù)組和列表讀取一列的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04Python?JSON數(shù)據(jù)解析過程(最新推薦)
json模塊提供了將JSON格式的數(shù)據(jù)轉(zhuǎn)換為Python對(duì)象(如列表、字典等)以及將Python對(duì)象轉(zhuǎn)換為JSON格式的數(shù)據(jù)的方法,下面給大家分享使用json模塊解析JSON數(shù)據(jù)的常見方法,感興趣的朋友一起看看吧2024-02-02使用Pandas實(shí)現(xiàn)MySQL窗口函數(shù)的解決方法
本文主要介紹 MySQL 中的窗口函數(shù)row_number()、lead()/lag()、rank()/dense_rank()、first_value()、count()、sum()如何使用pandas實(shí)現(xiàn),同時(shí)二者又有什么區(qū)別,感興趣的朋友一起看看吧2023-02-02Python爬蟲程序架構(gòu)和運(yùn)行流程原理解析
這篇文章主要介紹了Python爬蟲程序架構(gòu)和運(yùn)行流程原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03