實驗一、圖像的讀取和運算
import cv2
import numpy as np
from matplotlib import pyplot as plt
def show_img(name,image):
cv2.imshow(name,image)
cv2.waitKey()
cv2.destroyAllWindows()
# 讀入圖片
img = cv2.imread('./image/leonard.jpg')
# 顯示圖片
show_img('leonard.jpg',img)
# 保存圖片
cv2.imwrite('save.jpg',img)
True
# 圖片運算
img1 = cv2.imread('./image/leonard.jpg')
img2 = cv2.imread('./image/leonard1.jpg')
add = cv2.add(img1,img2)
subtract = cv2.subtract(img1,img2)
multiply = cv2.multiply(img1,img2)
divide = cv2.divide(img1,img2)
img1 = cv2.imread('./image/leonard.jpg')
img2 = cv2.imread('./image/leonard1.jpg')
add = cv2.add(img1,img2)
subtract = cv2.subtract(img1,img2)
multiply = cv2.multiply(img1,img2)
divide = cv2.divide(img1,img2)
plt.subplot(161),plt.imshow(img1),plt.title('img1')
plt.subplot(162),plt.imshow(img2),plt.title('img2')
plt.subplot(163),plt.imshow(add),plt.title('add')
plt.subplot(164),plt.imshow(subtract),plt.title('subtract')
plt.subplot(165),plt.imshow(multiply),plt.title('multiply')
plt.subplot(166),plt.imshow(divide),plt.title('divide')
plt.show()
實驗二、圖像的灰度變換及直方圖均衡化
任務:
以一幅 256×256 象素的數字圖像為實驗對象,觀察圖像的二值化效果和直方圖分布。
對圖像的直方圖進行均衡化。
import cv2
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 圖像二值化
img = cv2.imread('./image/leonard_256x256.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
cv_show('img_gray',img_gray)
print(img_gray)
print(img_gray.shape)
[[125 111 84 ... 20 18 18]
[149 127 96 ... 16 19 16]
[155 126 100 ... 15 20 17]
...
[ 49 56 62 ... 19 11 9]
[ 43 47 64 ... 16 6 4]
[ 33 56 61 ... 18 6 3]]
(256, 256)
# 圖像直方圖
hist = cv2.calcHist([img],[0],None,[256],[0,256])
print(hist.shape) # (256, 1)一維數組,有256個數據,分別代表每個值出現的次數
# print(hist)
# img.ravel()將二維圖像轉換為一維的數據
plt.hist(img.ravel(),256)
plt.show()
(256, 1)
# 均衡化處理
import numpy as np
# 直接均衡化,均衡化后圖像有些地方太亮,失去了細節信息
equ = cv2.equalizeHist(img_gray)
# 自適應直方圖均衡化 保留了細節
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_clahe = clahe.apply(img_gray)
# 直方圖對比
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure()
plt.subplot(311)
plt.hist(img_gray.ravel(),256,label='原始圖像')
plt.legend(loc='upper right')
plt.subplot(312)
plt.hist(equ.ravel(),256,label='均衡化')
plt.legend(loc='upper right')
plt.subplot(313)
plt.hist(res_clahe.ravel(),256,label='自適應均衡化')
plt.legend(loc='upper right')
plt.show()
# 圖像對比
res = np.hstack((img_gray,equ,res_clahe))
cv_show('res',res)
實驗三、圖像的平衡和銳化處理
任務:
- 以一幅 256×256 象素的數字圖像為對象
采用中值濾波處理進行平滑處理
和 Soble 算子圖像銳化方法
import cv2
import numpy as np
from IPython.display import Image
# 0 表示灰度圖
img = cv2.imread('./image/leonard_256x256_Noise.jpg',0)
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 自定義的平均濾波
kernel = np.ones((5,5),np.float32)/25
print(kernel)
[[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]]
# 第二個參數為圖像的深度,-1表示和原圖一樣
dst = cv2.filter2D(img,-1,kernel)
# 圖像變得很模糊,看着有點難受的感覺
res = np.hstack((img,dst))
cv_show('Original&Averaging',res)
均值濾波
卷積框覆蓋區域的所有像素的平均均值來代替中心元素
blur = cv2.blur(img,(5,5))
# 效果和平均濾波一樣
res = np.hstack((img,blur))
cv_show('Original&Blur',res)
Image(filename = './image/1.png', width=400)
高斯濾波
可以有效的去除高斯噪點
(卷積核里的值符合高斯分布,中心的值最大,其余方框根據距離中心元素的距離遞減,構成一個高斯小山包)
# 第三個參數為標准差,0表示函數自行計算
gaussianblur = cv2.GaussianBlur(img,(5,5),0)
res = np.hstack((img,gaussianblur))
cv_show('Original&GaussianBlur',res)
Image(filename = './image/2.png', width=400)
中值濾波(中值模糊)
用卷積框對應像素的中值來替換中心像素的值
常用於去除椒鹽噪聲
median = cv2.medianBlur(img,5)
res = np.hstack((img,gaussianblur))
cv_show('Original&medianBlur',res)
Image(filename='./image/3.png',width=400)
雙邊濾波
以保持邊界清晰的情況況下有效的去除噪聲
0 領域直徑 兩個75是 空間高斯函數標准差 灰度值相似性高斯函數標准差
bilatera = cv2.bilateralFilter(img,0,75,75)
res = np.hstack((img,bilatera))
cv_show('Original&bilateralFilter',res)
Image(filename='./image/4.png',width=400)
圖像梯度
圖像更加的細節
sobel算子
# ddepth:圖像的深度(輸入輸出一樣-1)
# dx和dy分別表示水平和豎直方向 dx :右邊-左邊,中間為0 dy:上邊-下邊,中間0
# ksize是Sobel算子的大小
sobelx= cv2.Sobel(img,-1,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely= cv2.Sobel(img,-1,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy= cv2.Sobel(img,-1,1,1,ksize=3) # 直接合並
sobelxy1 = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) # 分開按權重合並
res = np.hstack((img,sobelx,sobely,sobelxy,sobelxy1))
cv_show('res',res)
Image(filename='./image/5.png',width=1000)
scharr算子
# 相比sobel算子就是核(值)變大了,結果更敏感一些
scharrx = cv2.Scharr(img,-1,1,0)
scharry = cv2.Scharr(img,-1,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
res = np.hstack((img,scharrx,scharry,scharrxy))
cv_show('res',res)
Image(filename='./image/6.png',width=800)
laplacian算子
0 1 0
1 -4 1
0 1 0
laplacian = cv2.Laplacian(img,-1)
cv_show('laplacian',laplacian)
Image(filename='./image/7.png',width=200)
sobel算子效果一般,scharr效果更細節,laplacian比sobel更不明顯
實驗四-圖像的膨脹、腐蝕和細化
任務:
- 對指定圖像進行腐蝕、膨脹和細化,
- 把得到的結果圖像都顯示於屏幕上
# 方便查看圖片導入的包
from IPython.display import Image
# 導入包,和圖片顯示函數
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 讀入圖片(以灰度圖形式)
img = cv2.imread('./image/ka.png',0)
# 定義卷積核
kernel = np.ones((5,5),np.uint8)
kernel
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]], dtype=uint8)
腐蝕
作用:
- 腐蝕邊緣,白色區域減小
- 可以有效的去除白噪聲,也可以用來斷開兩個連在一起的物體
# iterations迭代執行次數
erosion = cv2.erode(img,kernel,iterations=1)
res = np.hstack((img,erosion))
cv_show('img&erosion',res)
Image(filename = './pic/1.png', width=400)
腐蝕
作用:
- 增加白色區域
- 一般去噪聲時,先用腐蝕,再膨脹
- 也可以用來連接兩個分開的物體
dilation = cv2.dilate(img,kernel,iterations=1)
res = np.hstack((img,dilation))
cv_show('img&dilation',res)
Image(filename='./pic/2.png',width=400)
開運算
作用:
- 先腐蝕再膨脹
- 用來去除噪聲
img_Noise = cv2.imread('./image/ka_Noise.png',0)
opening = cv2.morphologyEx(img_Noise,cv2.MORPH_OPEN,kernel)
res = np.hstack((img_Noise,opening))
cv_show('img_Noise&opening',res)
Image(filename='./pic/3.png',width=400)
閉運算
作用:
- 先膨脹再腐蝕
- 常用來填充前景物體中的小洞,或小黑點
img_Noise1 = cv2.imread('./image/ka_Noise1.png',0)
closing = cv2.morphologyEx(img_Noise1,cv2.MORPH_CLOSE,kernel)
res = np.hstack((img_Noise1,closing))
cv_show('img_Noise1&closing',res)
Image(filename='./pic/4.png',width=400)
形態學梯度
- 膨脹與腐蝕的區別
- 結果看上去就像前景物體的輪廓
- 膨脹 - 腐蝕
gradint = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
res = np.hstack((img,gradint))
cv_show('img&gradint',res)
Image(filename='./pic/5.png',width=400)
禮帽
- 原圖 - 開運算
kernel = np.ones((9,9),np.uint8)
tophat = cv2.morphologyEx(img_Noise,cv2.MORPH_TOPHAT,kernel)
res = np.hstack((img_Noise,tophat))
cv_show('img_Noise&tophat',res)
Image(filename='./pic/6.png',width=400)
黑帽
- 閉運算 - 原始圖像
blackhat = cv2.morphologyEx(img_Noise1,cv2.MORPH_BLACKHAT,kernel)
res = np.hstack((img_Noise1,blackhat))
cv_show('img_Noise1&blackhat',res)
Image(filename='./pic/7.png',width=400)
總結
- 腐蝕:減小白色區域,增加黑色區域,分開連在一起並且顏色差異不大的物體
- 膨脹: 增加白色區域,突出白色
- 開運算:先腐蝕,在膨脹,可去除明亮的小點
- 閉運算:先膨脹,再腐蝕,可去除明亮物體中的小黑點
- 禮帽:頂帽運算往往用來分離比鄰近點亮一些的斑塊
- 黑帽:用來分離比鄰近點暗一些的斑塊
實驗五、圖像閾值處理與邊緣檢測
任務:
- 對指定圖像進行自適應門限值分割和邊緣提取
# 方便查看圖片導入的包
from IPython.display import Image
# 導入包,和圖片顯示函數
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 導入圖片(原圖)
img = cv2.imread('./image/leonard_256x256.jpg',0)
cv_show('img',img)
圖像閾值處理
- src:表示的是圖片源
- thresh:表示的是閾值(起始值)
- maxval:表示的是最大值
- type:表示的是這里划分的時候使用的是什么類型的算法,常用值為0(cv2.THRESH_BINARY)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
print(ret) # ret就是最小值(起始值),th1是圖像
ret,th2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,th3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,th4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,th5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
res = np.hstack((th1,th2,th3,th4,th5))
cv_show('res',res)
127.0
Image(filename='./image/1.png')
# 不同參數的圖像,常用前兩種
# THRESH_BINARY 大於127取255,否知取0
# THRESH_BINARY_INV 反之
自適應閾值
- 第一個原始圖像
- 第二個像素值上限
- 第三個自適應方法Adaptive Method:
- cv2.ADAPTIVE_THRESH_MEAN_C :領域內均值
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C :領域內像素點加權和,權 重為一個高斯窗口
- 第四個值的賦值方法:只有cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV
- 第五個Block size:規定領域大小(一個正方形的領域)
- 第六個常數C,閾值等於均值或者加權值減去這個常數(為0相當於閾值 就是求得領域內均值或者加權值),這種方法理論上得到的效果更好,相當於在動態自適應的調整屬於自己像素點的閾值,而不是整幅圖像都用一個閾值。
# 中值濾波
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,1)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,1)
res = np.hstack((img,th1,th2,th3))
cv_show('res',res)
Image(filename='./image/2.png')
Canny邊緣檢測
-
- 使用高斯濾波器,以平滑圖像,濾除噪聲。
-
- 計算圖像中每個像素點的梯度強度和方向。
-
- 應用非極大值(Non-Maximum Suppression)抑制,以消除邊緣檢測帶來的雜散響應。
-
- 應用雙閾值(Double-Threshold)檢測來確定真實的和潛在的邊緣。
-
- 通過抑制孤立的弱邊緣最終完成邊緣檢測。
canny函數參數:
- 后兩個參數minVal,maxVal
- 梯度大於maxVal處理為邊界
- 在兩者之間,連接有邊界保留,否者舍棄
- 小於minVal,舍棄
img = cv2.imread('./image/leonard_256x256.jpg',0)
# 高斯濾波
aussian = cv2.GaussianBlur(img, (3, 3), 1)
edges = cv2.Canny(aussian,100,200)
res = np.hstack((aussian,edges))
cv_show('res',res)
Image(filename='./image/3.png',width=400)
img = cv2.imread('./image/leonard_256x256.jpg',0)
# 高斯濾波
aussian = cv2.GaussianBlur(img, (3, 3), 1)
edges = cv2.Canny(aussian,245,255)
res = np.hstack((aussian,edges))
cv_show('res',res)
Image(filename='./image/4.png',width=400)