OpenCV图像处理

OpenCV轻松入门(学习笔记)

参考:

参考课本——OpenCV轻松入门


声明

本博客内容中根据个人项目需求对上述参考材料进行改写 ,
非抄袭,也非原创 (但大部分原创)
若有侵权行为务必告知
E-mail: yuansh3354@163.com

本文内容仅为笔记,方便自己后续做DL时候进行参考,不会用于其他任何用途

安装opencv-python:

pip install opencv-python
pip install opencv-contrib-python


图像的读取和显示和保存

import cv2  # opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

plt.rcParams['savefig.dpi'] = 500 #图片像素
plt.rcParams['figure.dpi'] = 500 #分辨率

img = cv2.imread('cat.jpg')  # 读取图片,默认导入是BGR格式

#博文中支持使用这种方法显示图片,但是我个人不喜欢,因此注释掉
# def cv_show(img_name='image', img=None, show_time=0):
#     cv2.namedWindow(img_name, cv2.WINDOW_NORMAL) #输出的图片可以任意缩放
#     cv2.imshow(img_name, img)  # 显示图片
#     cv2.waitKey(show_time*1000)
#     # 设置图片显示时长,当为0时显示时间无穷大(按任意键退出)。
#     # 显示时长单位:秒
#     cv2.destroyAllWindows()  # 关闭所有窗口


# cv_show('1', img, 10)
# cv2.imwrite('cat_gray.jpg', img)  # 保存图片
def to_rgb(img):
    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # image 格式转化
    return(img)

def imshow(img=None, img_name=None, save=False):
    if save:
        cv2.imwrite(img_name,img)
    print("image size: ", img.shape)
    img = to_rgb(img) # opencv读取的格式是BGR,plt是以rgb格式显示图片
    plt.xticks([])
    plt.yticks([])
    plt.imshow(img)

通道的剥离和组合

通道与合并拆分:

  • cv2.split(img)
  • cv2.merge((r,g,b))
    注意:这里可以使用切片法对图像进行修改或者截取
import cv2
img = cv2.imread('lena.jpg')

b,g,r = cv2.split(img)# cv2.split(img)[0] 等同于 img[:,:,0]取第一个通道
b[100:200,50:200] = 0
g[100:200,50:200] = 0
img_new = cv2.merge((b,g,r))# 处理完某个通道,再重新组合b g r3个通道
# 图像截取
ids = np.hstack((img,img_new))
imshow(ids)

在这里插入图片描述

图像融合

融合一般分为两种:

  • 通道融合
  • 简单融合(矩阵加法)
    下面展示的是简单融合
    从左到右:原图、直接加法、使用add方法
import cv2
img = cv2.imread('lena.jpg')
img_add = img + img
img_add_ = cv2.add(img,img)

ids = np.hstack((img,img_add,img_add_))
imshow(ids)

在这里插入图片描述

加权图像融合

  • cv2.addWeighted(src1, alpha, src2, beta, gamma)

这四个参数都是必须参数

γ \gamma γ:可以认为是亮度调节系数

公式具体执行如下:
i m g o u t = i m g 1 ∗ α + i m g 2 ∗ β + γ img_{out} = img_1 * \alpha + img_2 * \beta + \gamma imgout=img1α+img2β+γ

# 直接加(务必注意image_size必须一样)
img_cat = cv2.imread('cat.jpg')  # 414x500x3
img_dog = cv2.imread('dog.jpeg')
img_dog = cv2.resize(img_dog,(img_cat.shape[1],img_cat.shape[0]))
ids1 = cv2.addWeighted(img_cat,0.5,img_dog,0.5,1)
ids2 = cv2.addWeighted(img_cat,0.5,img_dog,0.5,10)
ids3 = cv2.addWeighted(img_cat,0.5,img_dog,0.5,100)
ids = np.hstack((ids1,ids2,ids3))
imshow(ids)

在这里插入图片描述

填充

  • BORDER_REPLICATE:复制法,也就是复制最边缘像素。
  • BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb
  • BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
  • BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
  • BORDER_CONSTANT:常量法,常数值填充。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('lena.jpg')
top_size,bottom_size,left_size,right_size = (50,50,50,50)
img_replace = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REPLICATE)
img_reflect = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,cv2.BORDER_REFLECT)
img_reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
img_wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
img_constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)


img = to_rgb(img)
img_replace = to_rgb(img_replace)
img_reflect = to_rgb(img_reflect)
img_reflect101 = to_rgb(img_reflect101)
img_wrap = to_rgb(img_wrap)
img_constant = to_rgb(img_constant)


plt.figure(figsize=(10,10))
plt.subplot(231),plt.imshow(img,'gray'),plt.title('ORIGINAL'),plt.xticks([]),plt.yticks([])
plt.subplot(232),plt.imshow(img_replace,'gray'),plt.title('Replace'),plt.xticks([]),plt.yticks([])
plt.subplot(233), plt.imshow(img_reflect, 'gray'), plt.title('REFLECT'),plt.xticks([]),plt.yticks([])
plt.subplot(234), plt.imshow(img_reflect101, 'gray'), plt.title('REFLECT_101'),plt.xticks([]),plt.yticks([])
plt.subplot(235), plt.imshow(img_wrap, 'gray'), plt.title('WRAP'),plt.xticks([]),plt.yticks([])
plt.subplot(236), plt.imshow(img_constant, 'gray'), plt.title('CONSTANT'),plt.xticks([]),plt.yticks([])
plt.subplots_adjust( wspace=0.1, hspace=-.15)
#wspace 子图横向间距, hspace 代表子图间的纵向距离,left 代表位于图像不同位置
plt.show();

在这里插入图片描述

按位运算

  • cv2.bitwise_and()

个人认为这个比较实用

通常来说,在语义分割模型中,我们通过使用 maskraw_imag 的按位运算可以直接截取蒙版内的 ROI 区域

import cv2
import numpy as np

img1 = cv2.imread('TCGA_CS_4941_19960909_12.tif')
img2 = cv2.imread('TCGA_CS_4941_19960909_12_mask.tif')

img = cv2.bitwise_and(img1, img2)

ids = np.hstack((img1,img2,img))

imshow(ids)

在这里插入图片描述

查看所有逻辑运算的差异

通过以下的结果可以看到;

  • 与运算可以得到蒙版部分
  • 或运算可以得到除了蒙版以外的部分
import cv2
import numpy as np

img1 = cv2.imread('TCGA_CS_4941_19960909_12.tif')
img2 = cv2.imread('TCGA_CS_4941_19960909_12_mask.tif')

ids1 = cv2.bitwise_and(img1, img2) # 与
ids2 = cv2.bitwise_not(img1)# 取反
ids3 = cv2.bitwise_or(img1, img2)# 或
ids4 = cv2.bitwise_xor(img1, img2)# 异或

ids = np.hstack((img1,ids1,ids2,ids3,ids4))
imshow(ids)

在这里插入图片描述

Image 平面位分解

8位灰度图中,每个像素的值可以如下按位分解

i m g o u t = a 7 ∗ 2 7 + a 6 ∗ 2 6 + a 5 ∗ 2 5 + a 4 ∗ 2 4 + a 3 ∗ 2 3 + a 2 ∗ 2 2 + a 1 ∗ 2 1 + a 0 ∗ 2 0 img_{out} = a_7∗2^7+a_6∗2^6+a_5∗2^5+a_4∗2^4+a_3∗2^3+a_2∗2^2+a_1∗2^1+a_0∗2^0 imgout=a727+a626+a525+a424+a323+a222+a121+a020

按每位分解可以得到位图(位平面),a7是最高有效位平面,a0是最低有效位平面

平面位越高,与原图的相似性越强
位面分解原理(课本中用了好几个篇幅进行介绍(P53-58),我这里做个总结):

  • 将像素点转化为8位的2进制(上面的公式)
  • 根据8位的2进制,从右到左分别位0-7位
  • 将对应的位的值拿出来就是对应的位面图了
# img 的位面图展示
# 根据公式计算位面图,默认输出第8位
# rgb的位面分解单独进行即可
def Get_Potential_Plane(img=None,plane_id=7):
    r,c = img.shape # 提取image尺寸
    x = np.zeros((r,c,1),dtype=np.uint8) # 构建全为0的矩阵
    x[:,:,0]=2**plane_id #表示2的i次方,这里是2的7 次方
    r=np.zeros((r,c,1),dtype=np.uint8)
    r[:,:,0]=cv2.bitwise_and(img, x[:,:,0])
    """
    将图片中的像素点转为2进制的值,然后和全为2的7次方按位与。
    由于2的7次方,只有在第8位为1其余全为零,按位与后除第8位为1的其余位置全为0,
    也就是像素点中,值小于128的全为0,反之全为1
    """
    mask=r[:,:,0]>0
    r[mask]=255 #将像素值大于0的都设为255,目的在于提高亮度,否在值过低就接近黑色了
    return r 

import cv2 
import numpy as np

img = cv2.imread('lena.jpg',0)

for i in range(8):
    locals()['img_'+str(i)] = Get_Potential_Plane(img,i)
    
ids = np.hstack((img_0,img_1,img_2,img_3,img_4,img_5,img_6,img_7))
plt.figure(figsize=(12,16))
imshow(ids)

在这里插入图片描述

RGB版本

# RGB按位运算
img = cv2.imread('lena.jpg')
img_b, img_g, img_r = cv2.split(img)

for i in range(8):
    locals()['img_r_'+str(i)] = Get_Potential_Plane(img_r, i)
    locals()['img_g_'+str(i)] = Get_Potential_Plane(img_g, i)
    locals()['img_b_'+str(i)] = Get_Potential_Plane(img_b, i)
    locals()['img_'+str(i)] = cv2.merge((locals()['img_b_'+str(i)],
                                         locals()['img_g_'+str(i)], 
                                         locals()['img_r_'+str(i)]))


ids = np.hstack((img_0, img_1, img_2, img_3, img_4, img_5, img_6, img_7))
plt.figure(figsize=(12, 16))
imshow(ids)

在这里插入图片描述

阈值处理

返回值是:阈值和图

阈值的处理,主要分为两种:

  • 固定阈值处理

    • 二值化:大于阈值的设为255,小于阈值的设为0

    • 反向二值化

    • 截断阈值:超过阈值部分为阈值,其余不变

    • 超阈值零处理: 超过阈值的部分设为0

    • 低阈值零处理

  • 自适应阈值处理

    • 区域加权平均

      • 权值相等-mean

      • 高斯加权-gaus

    • 遍历-otsi

import cv2
import matplotlib.pyplot as plt
img = cv2.imread('lena.jpg',0)
# 二值化阈值处理
ret,img_bi = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# 反向二值化阈值处理
ret,img_bi_inv = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
# 截断阈值处理
ret,img_tr = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
# 低阈值零处理
ret,img_zero = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
# 超阈值零处理
ret,img_zero_inv = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
# 自适应阈值处理(权重相等)
athdmean = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,5,3)
# 自适应阈值处理(距离变化)
athdgaus = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,5,3)
# otsu处理(自适应阈值)
# 该方法会遍历所有的可能值,然后输出最佳的结果
t2,otsu = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

titles = ['二值化阈值处理','反向二值化阈值处理','截断阈值处理',
          '低阈值零处理','超阈值零处理','自适应阈值处理(权重相等)',
         '自适应阈值处理(距离变化)','otsu处理(自适应阈值)']
images = [img_bi,img_bi_inv,img_tr,img_zero,img_zero_inv,athdmean,athdgaus,otsu]

for i in range(8):
    plt.subplot(2,4,i+1)
    plt.imshow(images[i],'gray')
    #plt.title(titles[i])
    plt.xticks([]),plt.yticks([])   # 不显示坐标轴
plt.show();

在这里插入图片描述

平滑处理

作用:降噪,其主要原理是将噪声像素点改为与周围像素点临近的近似值

常用的方法分为:

  • 均值波滤(标准化后的方框波滤,是一个特例)
  • 方框波滤
  • 高斯波滤(用的是高斯核)
  • 中值波滤
  • 双边波滤(综合考虑到空间和色彩信息,可以有效的处理边缘信息,值太大会产生卡通效果)
  • 2D卷积
import cv2
import numpy as np

img = cv2.imread('lenaNoise.png')
plt.rcParams['figure.figsize'] = (20,20)

# 波滤操作
blur = cv2.blur(img,(3,3)) # 均值
boxFilter = cv2.boxFilter(img,-1,(3,3),normalize=False) # 方框,当选择标准化后,方框和均值的操作结果相同
gussian = cv2.GaussianBlur(img,(3,3),1)#高斯波滤
median = cv2.medianBlur(img,5) # 中值波滤
binary = cv2.bilateralFilter(img,55,150,150)#双边波滤


ids = np.hstack((img,blur,boxFilter,gussian,median,binary))
imshow(ids)

在这里插入图片描述

梯度计算

  • sobel 算子

  • scharry 算子

  • laplacian 算子

img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3) # 计算x梯度
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3) # 计算y梯度
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)
laplacian = cv2.convertScaleAbs(laplacian)   

res = np.hstack((img,sobelxy,scharrxy,laplacian))
imshow(res)

在这里插入图片描述

Canny 边缘检测

STEP:

  1. 去燥

  2. 计算梯度方向

  3. 非极大值抑制

  4. 双阈值确定边缘

  5. 抑制孤立的弱边缘

img = cv2.imread("cat.jpg", cv2.IMREAD_GRAYSCALE)

v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 100)  # 阈值设置的合适,就可以把细节信息展示更多,发丝和细纹理都显现出来了

res = np.hstack((img, v1, v2))
imshow(res)

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值