【课程笔记】OpenCV(2)图像处理


前言

课程学习笔记,BV1PV411774y


ROI–截取

截取部分图像数据
import cv2 
import matplotlib.pyplot as plt 
import numpy as np   
%matplotlib inline

img = cv2.imread('01_Picture/01_cat.jpg')
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()  
cat = img[100:300,0:200]  # 选择感兴趣的图片区域
cv_show('cat',cat)
颜色通道提取
b,g,r = cv2.split(img)  # 分离 BGR 通道
# b/g/r 单独展示出来均相当于灰度图
img = cv2.merge((b,g,r))    # 组合 BGR 通道
# 只保留 G 通道
cur_img = img.copy()
cur_img[:,:,0] = 0 
cur_img[:,:,2] = 0
cv_show('G',cur_img)

边界填充

① 边界填充:对图像进行一些变换,让原始图像扩大

② 边界填充的入口参数:

  • BORDER_REPLICATE:复制法,直接复制最边缘像素
  • BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制,fedcba|abcdefgh|hgfedcb
  • BORDER_REFLECT_101:反射法,以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
  • BORDER_WRAP:外包装法,cdefgh|abcdefgh|abcdefg
  • BORDER_CONSTANT:常量法,常数值填充
top_size,bottom_size,left_size,right_size = (50,50,50,50)  # 上、下、左、右填充的大小

# 方式一:复制法
replicate = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REPLICATE) 
# 方式二:反射法
reflect = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT)
# 方式三:反射法二(不要最边缘的像素)
reflect101 = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT_101)      
# 方式四:外包装法
wrap = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_WRAP)
# 方式五:常量法
constant = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_CONSTANT,value=0)
plt.subplot(231), plt.imshow(img,'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate,'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect,'gray'), plt.title('REPLECT')
plt.subplot(234), plt.imshow(wrap,'gray'),plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236), plt.imshow(constant,'gray'),plt.title('CONSTAVI')

plt.show()

简单数值计算

img_cat = cv2.imread('01_Picture/01_cat.jpg')
img_dog = cv2.imread('01_Picture/03_dog.jpg')
img_cat2 = img_cat + 10     # 矩阵中每一个值都加 10
(img_cat + img_cat2)[:5,:,0]    # 0-255,若相加越界则取 %256 
                                # [:5,:,0],查看 B 通道的前 5 行
cv2.add(img_cat,img_cat2)    # 若相加越界则取 255 

图像融合

图像缩放
# 维度不匹配(shape 不同),不能直接相加,需要 resize
img_dog = cv2.resize(img_dog,(500,414))
res = cv2.resize(img,(0,0),fx=3,fy=1)   # (0,0):不指定目标大小,而是倍数放缩
                                        # fx=3:行像素 x 乘 3;fy=1:y 乘 1   
加权融合
res = cv2.addWeighted(img_cat,0.4,img_dog,0.6,0) # 0.4(img_cat) + 0.6(img_dog) + 0
plt.imshow(res)

形态学操作

腐蚀
  • 通常拿二值图像进行操作
  • 减少或删除图像中的前景像素(比如物体的边缘或者特定特征),从而达到缩小对象边界或者消除图像中的噪声等效果
img = cv2.imread('01_Picture/05_Dige.png') 
kernel = np.ones((5,5),np.uint8)    # 卷积核
                                    # 以像素点为中心,5×5 的区域,若存在前景(此图,值为1),则腐蚀(此图,值变为0)
erosion = cv2.erode(img,kernel,iterations=1)    # iterations:迭代次数,即反复执行腐蚀
cv_show('erosion',erosion)
pie = cv2.imread('01_Picture/06_pie.png')
kernel = np.ones((30,30),np.uint8)
erosion_1 = cv2.erode(pie,kernel,iterations=1)  # 对比不同迭代次数的效果
erosion_2 = cv2.erode(pie,kernel,iterations=2)
erosion_3 = cv2.erode(pie,kernel,iterations=3)
res = np.hstack((erosion_1,erosion_2,erosion_3))
cv_show('res',res)
膨胀
  • 相当于腐蚀的逆操作
  • 腐蚀去噪会使目标的边界缩小,通过膨胀加以还原,从而去除噪声、保留目标
kernel = np.ones((3,3),np.uint8)
dige_erosion = cv2.erode(img,kernel,iterations=1)   

kernel = np.ones((3,3),np.uint8)    # 以像素点为中心,3×3 的区域,若存在背景(此图,值为0),则膨胀(此图,值变为1)
dige_dilate = cv2.dilate(dige_erosion,kernel,iterations=1)
cv_show('dilate',dige_dilate)
开运算与闭运算
  • 开:先腐蚀,再膨胀;cv2.MORPH_OPEN
  • 闭:先膨胀,再腐蚀;cv2.MORPH_CLOSE
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)   # morphology:形态学
cv_show('opening',opening)
kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel) 
cv_show('closing',closing)
梯度运算
  • 梯度 = 腐蚀-膨胀;cv2.MORPH_GRADIENT
  • 获取物体的边界信息
pie = cv2.imread('01_Picture/06_pie.png')
kernel = np.ones((7,7),np.uint8)
gradient = cv2.morphologyEx(pie,cv2.MORPH_GRADIENT,kernel)
cv_show('gradient',gradient)
礼帽与黑帽
  • 礼帽 = 原始输入-开运算结果;cv2.MORPH_TOPHAT
  • 黑帽 = 闭运算结果-原始输入;cv2.MORPH_BLACKHAT
kernel = np.ones((5,5),np.uint8)
tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
cv_show('tophat',tophat)
kernel = np.ones((5,5),np.uint8)
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
cv_show('blackhat',blackhat)

图像梯度

图像中物体边缘的梯度大,纯色物体内部梯度为0

Sobel算子

cv2.Sobel(src, ddepth, dx, dy, ksize),返回值为Sobel算子处理后的图像

  • ddepth:图像的深度
  • dx/dy:置为 1 表示选择水平/竖直方向
  • ksize:Sobel 算子的大小

G x (水平卷积) = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ A  ;右减左 G_x\text{(水平卷积)} = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} *A \text{ ;右减左} Gx(水平卷积)= 121000121 A ;右减左

G y (竖直卷积) = [ − 1 − 2 − 1 0 0 0 1 2 1 ] ∗ A  ;下减上 G_y\text{(竖直卷积)} = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{bmatrix} *A \text{ ;下减上} Gy(竖直卷积)= 101202101 A ;下减上

img = cv2.imread('01_Picture/06_pie.png')
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)  # cv2.CV_64F:用于扩展计算位数

# cv2 会将负数截断成 0,所以要取绝对值
sobelx = cv2.convertScaleAbs(sobelx)
cv_show('sobelx',sobelx)
sobely = cv2.Sobel(pie,cv2.CV_64F,0,1,ksize=3)  # 竖直方向
sobely = cv2.convertScaleAbs(sobely)

# 分别计算后,再加权求和,不建议直接将 dx 和 dy 同时置为 1
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  # 0.5(sobelx) + 0.5(sobely) + 0
cv_show('sobelxy',sobelxy)
Scharr算子

G x = [ − 3 0 3 − 10 0 10 − 3 0 3 ] ∗ A  and  G y = [ − 3 − 10 − 3 0 0 0 3 10 3 ] ∗ A G_x = \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \end{bmatrix} *A \text{ and } G_y = \begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ 3 & 10 & 3 \end{bmatrix} *A Gx= 31030003103 A and Gy= 30310010303 A

Laplacian算子
  • 使用二阶导(一阶导的变化率),对噪音点更敏感,通常与其他方法结合使用
  • 如果中心点是边界,它与周围像素点差异的幅度会较大,Laplacian算子根据此特点可以把边界识别出来
    G = [ 0 1 0 1 − 4 1 0 1 0 ] G = \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix} G= 010141010
img = cv2.imread('01_Picture/07_Lena.jpg',cv2.IMREAD_GRAYSCALE)

sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)

laplacian = cv2.Laplacian(img,cv2.CV_64F) # 没有 x、y,因为是求中心点与周围点的比较
laplacian = cv2.convertScaleAbs(laplacian)

res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show('res',res)

阈值操作

ret, dst = cv2.threshold(src, thresh, maxval, type),返回阈值和输出图

  • src: 输入图,只能输入单通道图像,通常来说为灰度图
  • thresh: 阈值
  • maxval: 当像素值超过了阈值 (或者小于阈值,根据 type 来决定),所赋予的值
  • type:二值化操作的类型,包含以下5种类型:
    • cv2.THRESH_BINARY 超过阈值部分取maxval,否则取0
    • cv2.THRESH_BINARY_INV THRESH_BINARY的反转,超过阈值部分取0,否则取maxval
    • cv2.THRESH_TRUNC 大于阈值部分取阈值,否则不变
    • cv2.THRESH_TOZERO 大于阈值部分不改变,否则取0
    • cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
img_gray = cv2.imread('01_Picture/01_cat.jpg',cv2.IMREAD_GRAYSCALE)    
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)   
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV) # THRESH_BINARY_INV 相对 THRESH_BINARY 黑的变成白的,白的变成黑的       
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)     
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']        
images = [img_gray, thresh1, thresh2, thresh3, thresh4, thresh5]  

for i in range(6):
    plt.subplot(2,3,i+1), plt.imshow(images[i],'gray')  
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

图像平滑

使用滤波,去除噪声

均值滤波
# 平均卷积:卷积核区域的值累加,取平均,作为中心点的值

img = cv2.imread('01_Picture/04_LenaNoise.png') # 带噪音的图像
blur = cv2.blur(img,(3,3))  # (3,3) 为核的大小,通常核都是奇数 3、5、7
cv_show('blur',blur)
方框滤波
# 在 Python 中,-1 表示自适应填充对应的值
# 此处 -1 表示颜色通道数自适应一致

box = cv2.boxFilter(img,-1,(3,3),normalize=False)  
cv_show('box',box)

# 做归一化,得到的结果与均值滤波一样
# 不做归一化,则是只累加,不取平均,越界的值取 255
高斯滤波
# 卷积核满足高斯分布:离中心越近的,值越大,离中心越远的,值越小

aussian = cv2.GaussianBlur(img,(5,5),1)
cv_show('aussian',aussian)
中值滤波
# 排序后,将中值作为中心点的值

median = cv2.medianBlur(img,5)
cv_show('median',median)
res = np.hstack((blur,aussian,median))  # 矩阵横着拼接
#res = np.vstack((blur,aussian,median)) # 矩阵竖着拼接
cv_show('res',res)
  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值