前面學了一些關于opencv圖像處理的內容,現在繼續。
一 圖像填充
????????邊界填充(Border Padding)?,即在圖像四周添加指定寬度的像素區域。其核心函數是cv2.copyMakeBorder()
,通過不同的填充方式(borderType
)處理圖像邊緣,常用于避免卷積操作(如濾波)時邊界信息丟失或調整圖像尺寸。有下面四種參數
- 黑色邊框?(常數填充)
BORDER_CONSTANT
? - ?鏡像反射含邊緣?(如照鏡子)??
BORDER_REFLECT
- ?鏡像反射不含邊緣?(更平滑)?
BORDER_REFLECT_101
- ?拉伸邊緣像素?(復制最外側像素)?
BORDER_REPLICATE
- ?循環平鋪圖像?(類似紋理重復)BORDER_WRAP
代碼部分
1?常數填充
這里top,bottom,left,right=50,50,50,50,表示要向上下左右要填充的大小,這里填充的是黑色,RGB值為0,0,0。如果是填充其他值可以修改。
zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
constant=cv2.copyMakeBorder(zxc, top, bottom, left, right,borderType=cv2.BORDER_CONSTANT,value=(0,0,0))
cv2.imshow('zxc',zxc)
cv2.imshow('constant',constant)
cv2.waitKey(0)
2 邊緣折射填充
?BORDER_REFLECT和
?BORDER_REFLECT101方法差不多,但通過圖我們可以看出來,第一種邊緣部分有點點突兀,而第二種就比較平滑。
import cv2zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
reflact=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_REFLECT)
reflact101=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_REFLECT101)
cv2.imshow('zxc',zxc)
cv2.imshow('constant',reflact)
cv2.imshow('reflect',reflact101)
cv2.waitKey(0)
3 拉伸填充
import cv2zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
replicate=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_REPLICATE)
cv2.imshow('zxc',zxc)
cv2.imshow('constant',replicate)
cv2.waitKey(0)
4 循環平鋪填充
import cv2zxc=cv2.imread('img.png')
top,bottom,left,right=50,50,50,50
cv2.imshow('zxc',zxc)
wrap=cv2.copyMakeBorder(zxc,top,bottom,left,right,borderType=cv2.BORDER_WRAP)
cv2.imshow('reflect',wrap)
cv2.waitKey(0)
二?圖像加運算
第一篇文章也說了,opencv把圖片轉化為了一個一個 像素值,那么就可以進行加,這里有兩種方法,一個是直接加,一個是用add方法。注意這里相加,要尺寸大小一樣才能相加。
1 直接加
對兩張圖像每個像素值直接相加(例:像素A(150) + 像素B(120) = 270 → 截斷為255)
import cv2long=cv2.imread('img_3.png')
tu=cv2.imread('img_5.png')
long=cv2.resize(long,(800,600))
tu=cv2.resize(tu,(800,600))
c=long+tu
cv2.imshow('long',long)
cv2.imshow('tu',tu)
cv2.imshow('aa',c)
cv2.waitKey(0)
2?cv2.addWeighted加權相加
這種更平滑,不會有出現超過255像素值的那種情況
import cv2long=cv2.imread('img_3.png')
tu=cv2.imread('img_5.png')
long=cv2.resize(long,(800,600))
tu=cv2.resize(tu,(800,600))
d=cv2.addWeighted(long,0.5,tu,0.5,0)cv2.imshow('bb',d)
cv2.waitKey(0)
三 閾值處理
閾值處理就是對圖片像素值設定一個閾值,大于這個就是就設置為其他像素或怎么的,下面看代碼詳解。
?閾值化選項? | ?條件:像素值 > thresh? | ?條件:像素值 ≤ thresh? |
---|---|---|
cv2.THRESH_BINARY | 設置為?maxval | 設置為?0 |
cv2.THRESH_BINARY_INV | 設置為?0 | 設置為?maxval |
cv2.THRESH_TRUNC | 截斷為?thresh | 保持原始灰度值不變 |
cv2.THRESH_TOZERO | 保持原始灰度值不變 | 設置為?0 |
cv2.THRESH_TOZERO_INV | 設置為?0 | 保持原始灰度值不變 |
1?cv2.THRESH_BINARY
這里還先對圖像作了灰度圖處理,有利于對閾值操作。這里閾值處理后會返回兩個值,一個是閾值,另一個就是處理好的圖像。具體原理看上方表格
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,binary=cv2.threshold(a,170,255,cv2.THRESH_BINARY)cv2.imshow('a',a)
cv2.imshow('binary',binary)
cv2.waitKey(0)
2?cv2.THRESH_BINARY_INV
這個就是上面的一個后面加了INV,其實就是上面處理好的圖中,黑色變白色,白色變黑色,反轉了一下。
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,binaryinv=cv2.threshold(a,170,255,cv2.THRESH_BINARY_INV)cv2.imshow('a',a)
cv2.imshow('binary',binaryinv)
cv2.waitKey(0)
3?cv2.THRESH_TRUNC
這里設定的閾值為170,然后超過的就記作170,低于的就按照原像素值1
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,trunc=cv2.threshold(a,170,255,cv2.THRESH_TRUNC)cv2.imshow('a',a)
cv2.imshow('binary',trunc)
cv2.waitKey(0)
4THRESH_TOZERO和THRESH_TOZERO_INV
保持原始灰度值不變 | 設置為?0 |
設置為?0 | 保持原始灰度值不變 |
import cv2a=cv2.imread('img_2.png',0)
a=cv2.resize(a,(800,600))
_,tozero=cv2.threshold(a,170,255,cv2.THRESH_TOZERO)
_,tozeroinv=cv2.threshold(a,170,255,cv2.THRESH_TOZERO_INV)
cv2.imshow('a',a)
cv2.imshow('binary',tozero)
cv2.imshow('binaryinv',tozeroinv)
cv2.waitKey(0)
五?圖像平滑處理
這里有四種常用圖像濾波方法可以進行圖像平滑處理
下面我先對圖片加上椒鹽噪聲。
1. ?均值濾波 (Mean Filtering)??
?原理?:
對圖像中每個像素點,取其鄰域內(如3×3、5×5)所有像素的算術平均值作為該點的新值。
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('jz',jz)
cv2.waitKey(0)
我們先定義了一個函數,對圖像添加了椒鹽噪聲,然后進行了均值濾波處理
這里處理結果顯然不是很好.
2 高斯濾波 (Gaussian Filtering)??
?原理?:
對鄰域內像素進行加權平均,權重由二維高斯函數生成,距離中心點越近權重越大
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
gs=cv2.GaussianBlur(ntu,(3,3),0)
cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('gs',gs)
cv2.waitKey(0)
3 方框濾波
核心計算邏輯?
- 對圖像中每個像素的?
3×3
?鄰域內所有像素值直接求和,?不進行歸一化?(即不除以像素數量?9
)。 - 數學表達:output(x,y)=i=?1∑1?j=?1∑1?input(x+i,y+j)
- 對圖像中每個像素的?
?與歸一化方框濾波的區別?
- ?歸一化模式?(
normalize=True
):
等價于均值濾波(cv2.blur()
),輸出鄰域像素平均值,結果平滑但保留亮度范圍。 - ?非歸一化模式?(
normalize=False
):
輸出為鄰域像素值之和,結果常因數值溢出呈現 ?全白或高亮區域?。
- ?歸一化模式?(
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
fk1=cv2.boxFilter(ntu,-1,ksize=(3,3),normalize=True)
fk2=cv2.boxFilter(ntu,-1,ksize=(3,3),normalize=False)cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('fk1',fk1)
cv2.imshow('fk2',fk2)
cv2.waitKey(0)
下面的第一張圖我沒有加歸一化,這樣的話就好第一種方法均值濾波差不多了。但加完之后圖片就太模糊了。
4?中值濾波 (Median Filtering)??
?原理?:
取鄰域內所有像素值的中位數替代中心像素值。
?計算步驟?:
- 提取鄰域像素值
- 排序后取中間位置的值
?適用場景?:
- 高效去除椒鹽噪聲?(黑白點狀噪聲)
- 需保留銳利邊緣的場景
?特點?: - ? 完全消除孤立噪聲點
- ? 邊緣保護能力極強
- ? 計算開銷較大(需排序)
import random
import cv2def zs(src,n):c=src.copy()print(c.shape)for i in range(n):x=random.randint(1,c.shape[0]-1)y=random.randint(1,c.shape[1]-1)if random.randint(0,1) == 0:c[x,y]=255else:c[x,y]=0return ctu=cv2.imread('img_5.png')
ntu=zs(tu,10000)
jz=cv2.blur(ntu,(3,3))
zz=cv2.medianBlur(ntu,5)
cv2.imshow('tu',tu)
cv2.imshow('ntu',ntu)
cv2.imshow('zz',zz)
cv2.waitKey(0)
從結果上看,這種方法對處理椒鹽噪聲是特別好的。