習(xí)日記 8.1)
前言前一篇文章講了圖片讀取與顯示今天繼續(xù)看圖像運(yùn)算、閾值處理和噪聲去除。主要涉及圖像運(yùn)算圖像的加法運(yùn)算與加權(quán)融合閾值處理二值化、截?cái)嗟乳撝挡僮饕约皥D像邊框的填充噪聲去除椒鹽噪聲的生成與多種濾波器的去噪效果對(duì)比一、圖像運(yùn)算1.1 使用 NumPy 的加法 運(yùn)算符直接用運(yùn)算符做圖像加法但 NumPy 的加法是取模運(yùn)算import cv2 a1 cv2.imread(3.png) b1 cv2.imread(4.jpg) a1 cv2.resize(a1, (500, 400)) b1 cv2.resize(b1, (500, 400)) NumPy 加法像素值相加后對(duì) 256 取模 c1 a1 10 # 每個(gè)像素值加 10 c2 a1[50:450, 50:400] b1[50:450, 50:400] # ROI 區(qū)域相加當(dāng)像素值超過(guò) 255 時(shí)NumPy 會(huì)將其對(duì) 256 取模。例如250 10 260取模后變成260 % 256 4這會(huì)導(dǎo)致原本應(yīng)該更亮的區(qū)域反而變暗出現(xiàn)“溢出回繞”的現(xiàn)象。1.2 使用 OpenCV 的 cv2.add() 函數(shù)OpenCV 提供了專門(mén)的加法函數(shù)cv2.add()它的處理方式是飽和運(yùn)算——超過(guò) 255 的值會(huì)被截?cái)酁?255a2 cv2.imread(3.png) b2 cv2.imread(4.jpg) b2 cv2.resize(b2, (400, 400)) a2 cv2.resize(a2, (400, 400)) OpenCV 加法超過(guò) 255 的像素值會(huì)被截?cái)酁?255飽和運(yùn)算 c3 cv2.add(a2, b2)運(yùn)算方式函數(shù)溢出處理NumPy 加法img1 img2取模運(yùn)算% 256OpenCV 加法cv2.add(img1, img2)飽和運(yùn)算截?cái)嗟?255小結(jié)在處理圖像加法時(shí)推薦使用cv2.add()因?yàn)樗苊饬巳∧2僮鲙?lái)的“反色”異常視覺(jué)效果更加自然。1.3 圖像加權(quán)融合 —— cv2.addWeighted()有時(shí)候我們希望將兩張圖像按照一定比例混合而不是簡(jiǎn)單地相加。這時(shí)候就可以使用cv2.addWeighted()# 參數(shù)img1, 權(quán)重1, img2, 權(quán)重2, 亮度偏移量 c4 cv2.addWeighted(a2, 0.7, b2, 0.3, 100)公式為dst α · img1 β · img2 γ其中 α 和 β 是兩幅圖像的權(quán)重γ 是亮度調(diào)節(jié)參數(shù)。在上面的代碼中a2占 70% 的權(quán)重b2占 30%最后再加上 100 的亮度偏移。這個(gè)函數(shù)在圖像疊加、水印添加、視頻特效等場(chǎng)景中很常用。二、圖像邊框與閾值處理2.1 為圖像添加邊框 —— cv2.copyMakeBorder()為圖像添加邊框可以用cv2.copyMakeBorder()支持多種填充方式import cv2 ys cv2.imread(4.jpg) top, bottom, left, right 50, 50, 50, 50 1. 常量邊框用固定顏色填充 constant cv2.copyMakeBorder(ys, top, bottom, left, right, borderTypecv2.BORDER_CONSTANT, value[229, 25, 80]) 2. 鏡像邊框以邊緣為軸進(jìn)行鏡像 reflect cv2.copyMakeBorder(ys, top, bottom, left, right, borderTypecv2.BORDER_REFLECT) 3. 鏡像邊框不含邊界與 REFLECT 類(lèi)似但不包含邊界像素 reflect101 cv2.copyMakeBorder(ys, top, bottom, left, right, borderTypecv2.BORDER_REFLECT101) 4. 復(fù)制邊框復(fù)制邊緣像素 replicate cv2.copyMakeBorder(ys, top, bottom, left, right, borderTypecv2.BORDER_REPLICATE) 5. 環(huán)繞邊框用對(duì)面邊界的像素填充 warp cv2.copyMakeBorder(ys, top, bottom, left, right, borderTypecv2.BORDER_WRAP)五種邊框類(lèi)型的效果對(duì)比邊框類(lèi)型OpenCV 常量說(shuō)明常量邊框BORDER_CONSTANT用指定顏色值填充邊框區(qū)域鏡像邊框BORDER_REFLECT以邊緣像素為鏡像軸向外鏡像擴(kuò)展如 fedcba|abcdefgh|hgfedcb反射101BORDER_REFLECT101以邊緣像素為對(duì)稱中心如 gfedcb|abcdefgh|gfedcba復(fù)制邊框BORDER_REPLICATE直接復(fù)制最邊緣的像素值如 aaaaaa|abcdefgh|hhhhhhh環(huán)繞邊框BORDER_WRAP用對(duì)面邊界的像素來(lái)填充如 cdefgh|abcdefgh|abcdefg默認(rèn)推薦BORDER_REFLECT101 是 OpenCV 中許多函數(shù)如濾波的默認(rèn)邊框處理方式它在大多數(shù)場(chǎng)景下表現(xiàn)最佳。2.2 閾值處理 —— cv2.threshold()閾值處理是圖像分割中最基礎(chǔ)的方法之一設(shè)定一個(gè)閾值將像素值與閾值比較根據(jù)比較結(jié)果對(duì)像素分類(lèi)。OpenCV 提供了五種閾值處理類(lèi)型image cv2.imread(4.jpg, 0) # 以灰度模式讀取 參數(shù)源圖像, 閾值, 最大值, 閾值類(lèi)型 ret, binary cv2.threshold(image, 175, 255, cv2.THRESH_BINARY) # 二值化 ret1, binaryinv cv2.threshold(image, 175, 255, cv2.THRESH_BINARY_INV) # 反二值化 ret2, trunc cv2.threshold(image, 175, 255, cv2.THRESH_TRUNC) # 截?cái)?ret3, tozero cv2.threshold(image, 175, 255, cv2.THRESH_TOZERO) # 閾值歸零 ret4, tozeroinv cv2.threshold(image, 175, 255, cv2.THRESH_TOZERO_INV) # 反閾值歸零閾值類(lèi)型處理規(guī)則效果描述THRESH_BINARYdst maxVal 若 src thresh否則 0超過(guò)閾值為白色否則為黑色THRESH_BINARY_INVdst 0 若 src thresh否則 maxVal二值化的反轉(zhuǎn)版本THRESH_TRUNCdst thresh 若 src thresh否則 src超過(guò)閾值的像素被截?cái)酁殚撝礣HRESH_TOZEROdst src 若 src thresh否則 0低于閾值的像素歸零THRESH_TOZERO_INVdst 0 若 src thresh否則 src高于閾值的像素歸零返回值ret是實(shí)際使用的閾值在使用 Otsu 等自適應(yīng)方法時(shí)可能與傳入值不同binary等是處理后的圖像。應(yīng)用場(chǎng)景閾值處理常用于文檔掃描二值化、物體輪廓提取、前景/背景分離等任務(wù)。三、圖像噪聲與濾波3.1 椒鹽噪聲的生成椒鹽噪聲Salt-and-Pepper Noise是圖像中常見(jiàn)的噪聲類(lèi)型表現(xiàn)為隨機(jī)出現(xiàn)的黑白像素點(diǎn)像撒了鹽和胡椒一樣。可以手動(dòng)模擬這種噪聲import numpy as np def add_peppersalt_noise(image, n10000): 向圖像添加椒鹽噪聲 Args: image: 輸入圖像 n: 噪聲點(diǎn)數(shù)量 Returns: 添加了噪聲的圖像 result image.copy() h, w image.shape[:2] # 獲取圖像的高和寬 for i in range(n): x np.random.randint(0, h) # 隨機(jī)行坐標(biāo) y np.random.randint(0, w) # 隨機(jī)列坐標(biāo) if np.random.randint(0, 2) 0: result[x][y] 0 # 黑點(diǎn)胡椒噪聲 else: result[x][y] 255 # 白點(diǎn)鹽噪聲 return result這段代碼會(huì)在圖像的隨機(jī)位置生成黑白噪聲點(diǎn)模擬真實(shí)場(chǎng)景中的椒鹽噪聲。3.2 均值濾波 —— cv2.blur() 與 cv2.boxFilter()均值濾波是最簡(jiǎn)單的線性濾波方法它用像素鄰域的平均值來(lái)替代中心像素的值# 均值濾波5x5 的卷積核 blur_1 cv2.blur(noise, (5, 5)) 方框?yàn)V波當(dāng) normalizeTrue 時(shí)與均值濾波等效 boxFilter_1 cv2.boxFilter(noise, -1, (3, 3), normalizeTrue) 方框?yàn)V波normalizeFalse 時(shí)求和但不平均容易溢出 boxFilter_2 cv2.boxFilter(noise, -1, (3, 3), normalizeFalse)參數(shù)說(shuō)明-1輸出圖像的深度-1表示與輸入圖像一致(3, 3)卷積核大小normalizeTrue是否對(duì)結(jié)果進(jìn)行歸一化處理注意當(dāng)normalizeFalse時(shí)方框?yàn)V波不再除以核面積像素值容易超過(guò) 255導(dǎo)致畫(huà)面一片白。3.3 高斯濾波 —— cv2.GaussianBlur()高斯濾波使用高斯函數(shù)作為權(quán)重分配離中心越近的像素權(quán)重越大去噪的同時(shí)能更好地保留邊緣信息# 高斯濾波核大小 (3,3)標(biāo)準(zhǔn)差為 1 Gaussian_Noise cv2.GaussianBlur(noise, (3, 3), 1)參數(shù)說(shuō)明(3, 3)是高斯核的大小必須是奇數(shù)1是 X 方向的標(biāo)準(zhǔn)差如果設(shè)為 0則根據(jù)核大小自動(dòng)計(jì)算。3.4 中值濾波 —— cv2.medianBlur()中值濾波是非線性濾波它用鄰域像素的中值替代中心像素對(duì)椒鹽噪聲的去除效果尤其出色# 中值濾波核大小為 3 medianB cv2.medianBlur(noise, 3)3.5 濾波效果對(duì)比結(jié)論對(duì)于椒鹽噪聲中值濾波是首選方案。它能在有效去除椒鹽噪聲的同時(shí)最大限度地保留圖像的邊緣細(xì)節(jié)。四、綜合實(shí)戰(zhàn)4.1 實(shí)戰(zhàn)一攝像頭實(shí)時(shí)畫(huà)面與背景圖融合這是一個(gè)綜合運(yùn)用圖像運(yùn)算的實(shí)戰(zhàn)案例實(shí)現(xiàn)攝像頭實(shí)時(shí)畫(huà)面與背景圖片的融合效果import cv2 cap cv2.VideoCapture(0) background cv2.imread(4.jpg) background cv2.resize(background, (640, 480)) background_gray cv2.cvtColor(background, cv2.COLOR_BGR2GRAY) if not cap.isOpened(): print(無(wú)法打開(kāi)攝像頭) exit() while True: ret, frame cap.read() if not ret: break frame cv2.resize(frame, (640, 480)) frame_gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 彩色融合各占 50% 透明度 c1 cv2.addWeighted(frame, 0.5, background, 0.5, 100) 灰度融合各占 50% 透明度 c2 cv2.addWeighted(frame_gray, 0.5, background_gray, 0.5, 100) cv2.imshow(Color Fusion, c1) cv2.imshow(Gray Fusion, c2) 按下 ESC 鍵退出 if cv2.waitKey(60) 27: break cap.release() cv2.destroyAllWindows()4.2 實(shí)戰(zhàn)二視頻椒鹽噪聲處理對(duì)視頻文件逐幀添加椒鹽噪聲并使用中值濾波進(jìn)行去噪import cv2 import numpy as np def add_peppersalt_noise(image, n8000): result image.copy() h, w image.shape[:2] for i in range(n): x np.random.randint(0, h) y np.random.randint(0, w) if np.random.randint(0, 2) 0: result[x][y] 0 else: result[x][y] 255 return result cap cv2.VideoCapture(test.avi) if not cap.isOpened(): print(無(wú)法打開(kāi)視頻文件) exit() while True: ret, frame cap.read() if not ret: break # 添加椒鹽噪聲 noise add_peppersalt_noise(frame) 中值濾波去噪 medianB cv2.medianBlur(noise, 3) 同時(shí)顯示三個(gè)窗口 cv2.imshow(Original, frame) # 原視頻 cv2.imshow(Noise, noise) # 含噪聲視頻 cv2.imshow(Denoised, medianB) # 去噪后視頻 if cv2.waitKey(60) 27: break cap.release() cv2.destroyAllWindows()五、總結(jié)今天的學(xué)習(xí)內(nèi)容涵蓋了 OpenCV 圖像處理的三個(gè)核心模塊模塊核心函數(shù)要點(diǎn)圖像運(yùn)算cv2.add(),cv2.addWeighted()區(qū)分 NumPy 取模加法與 OpenCV 飽和加法掌握加權(quán)融合閾值處理cv2.threshold(),cv2.copyMakeBorder()五種閾值類(lèi)型 五種邊框填充方式濾波去噪cv2.blur(),cv2.boxFilter(),cv2.GaussianBlur(),cv2.medianBlur()椒鹽噪聲首選中值濾波這些知識(shí)都是后續(xù)學(xué)習(xí)更高級(jí)圖像處理操作如邊緣檢測(cè)、形態(tài)學(xué)操作、輪廓提取等的基礎(chǔ)建議動(dòng)手運(yùn)行每一段代碼觀察不同參數(shù)帶來(lái)的效果變化。