2021-08-23

学习目标:

学习图像处理基本概念


学习内容:

1. 图像处理的概念与基本操作 2. OpenCV库基本操作 3. OpenCV库进阶操作 4. 使用OpenCV摄像头与加载视频 5. 图像分类任务概念导入 6. PaddleClas数据增强代码解析

参考资料:https://blog.csdn.net/Lovely_him/article/details/114355234


学习时间:

2021年8月23日16:52:52


学习产出:

1. PIL读取图片
from PIL import Image
# 打开图片,返回一个图片对象
img = Image.open('lena.jpg')
# 使用PIL分离颜色通道
r,g,b = img.split()
# 获取第一个通道转的灰度图,和上一个函数功能类似
img.getchannel(0)# 参数012对应不同通道,即RGB
# 不断调试,找到猫的边缘,裁剪出一小块交接区
img.crop((1450,1450,1500,1500))

2.CV操作

%matplotlib inline  #这个是给Notebook用的,用于plt的显示
import cv2
import matplotlib.pyplot as plt
# 加载彩色图
img = cv2.imread('lena.jpg', 1)
# 将彩色图的BGR通道顺序转成RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 显示图片
plt.imshow(img)
# 查看图片的形状
img.shape
# 将彩色图的BGR通道顺序转成RGB,注意,在这一步直接丢掉了alpha通道
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 显示图片
# 将彩色图的BGR通道直接转为灰度图
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 显示这张灰度图
plt.imshow(img,'gray')
# 保存图片,成功的话会返回一个True
cv2.imwrite('lena-grey.jpg',img)
# 创建一副图片
img = cv2.imread('lena.jpg')
# 通道分割
b, g, r = cv2.split(img)
# 通道合并
img = cv2.merge((b, g, r))  
# 将彩色图的BGR通道顺序转成RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

3.OpenCV库进阶操作
阈值分割

  • 使用固定阈值、自适应阈值和Otsu阈值法"二值化"图像
  • OpenCV函数:cv2.threshold(), cv2.adaptiveThreshold()
cv2.adaptiveThreshold()函数参数:
参数1:要处理的原图
参数2:最大阈值,一般为255
参数3:小区域阈值的计算方式
— ADAPTIVE_THRESH_MEAN_C:小区域内取均值
— ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
参数4:阈值方式(跟前面讲的那5种相同)
参数5:小区域的面积,如11就是11*11的小块
参数6:最终阈值等于小区域计算出的阈值再减去此值
# 自适应阈值对比固定阈值
img = cv2.imread('lena.jpg', 0)

# 固定阈值
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# 自适应阈值, ADAPTIVE_THRESH_MEAN_C:小区域内取均值
th2 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 4)
# 自适应阈值, ADAPTIVE_THRESH_GAUSSIAN_C:小区域内加权求和,权重是个高斯核
th3 = cv2.adaptiveThreshold(
    img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 17, 6)

titles = ['Original', 'Global(v = 127)', 'Adaptive Mean', 'Adaptive Gaussian']
images = [img, th1, th2, th3]
plt.figure(figsize=(12,12))
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])

在这里插入图片描述

图像几何变换

  • 实现旋转、平移和缩放图片

  • OpenCV函数:cv2.resize(), cv2.flip(), cv2.warpAffine()

  • 缩放就是调整图片的大小,使用cv2.resize()函数实现缩放。可以按照比例缩放,也可以按照指定的大小缩放:
    我们也可以指定缩放方法interpolation,更专业点叫插值方法,默认是INTER_LINEAR,全部可以参考:InterpolationFlags

缩放过程中有五种插值方式:
cv2.INTER_NEAREST 最近邻插值
cv2.INTER_LINEAR 线性插值
cv2.INTER_AREA 基于局部像素的重采样,区域插值
cv2.INTER_CUBIC 基于邻域4x4像素的三次插值
cv2.INTER_LANCZOS4 基于8x8像素邻域的Lanczos插值

img = cv2.imread('cat.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 按照指定的宽度、高度缩放图片
res = cv2.resize(img, (400, 500))
# 按照比例缩放,如x,y轴均放大一倍
res2 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
plt.subplot(121)
plt.imshow(res)
plt.subplot(122)
plt.imshow(res2)

翻转图片
镜像翻转图片,可以用cv2.flip()函数: 其中,参数2 = 0:垂直翻转(沿x轴),参数2 > 0: 水平翻转(沿y轴),参数2 < 0: 水平垂直翻转。

平移图片
要平移图片,我们需要定义下面这样一个矩阵,tx,ty是向x和y方向平移的距离:
平移是用仿射变换函数cv2.warpAffine()实现的:

# 平移图片
import numpy as np
# 获得图片的高、宽
rows, cols = img.shape[:2]

# 定义平移矩阵,需要是numpy的float32类型
# x轴平移200,y轴平移500
M = np.float32([[1, 0, 200], [0, 1, 500]])
# 用仿射变换实现平移
dst = cv2.warpAffine(img, M, (cols, rows))

plt.imshow(dst)

绘制各种几何形状、添加文字
OpenCV函数:cv2.line(), cv2.circle(), cv2.rectangle(), cv2.ellipse(), cv2.putText()

画矩形 (图像识别)

# 画一个矩形,左上角坐标(40, 40),右下角坐标(80, 80),框颜色为绿色
img = cv2.rectangle(img, (40, 40), (80, 80), (0, 255, 0),2) 
# 画一个矩形,左上角坐标(40, 40),右下角坐标(80, 80),框颜色为绿色,填充这个矩形
img = cv2.rectangle(img, (40, 40), (80, 80), (0, 255, 0),-1) 
plt.imshow(img)

添加文字
使用cv2.putText()添加文字,它的参数也比较多,同样请对照后面的代码理解这几个参数:
参数2:要添加的文本
参数3:文字的起始坐标(左下角为起点)
参数4:字体
参数5:文字大小(缩放比例)

# 添加文字,加载字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 添加文字hello
cv2.putText(img, 'hello', (10, 200), font,
            4, (255, 255, 255), 2, lineType=cv2.LINE_AA)

图片相加
要叠加两张图片,可以用cv2.add()函数,相加两幅图片的形状(高度/宽度/通道数)必须相同。numpy中可以直接用res = img + img1相加,但这两者的结果并不相同:

图片相加
图像混合cv2.addWeighted()也是一种图片相加的操作,只不过两幅图片的权重不一样,γ相当于一个修正值:

cv2.add()用来叠加两幅图片,cv2.addWeighted()也是叠加两幅图片,但两幅图片的权重不一样。
cv2.bitwise_and(), cv2.bitwise_not(), cv2.bitwise_or(), cv2.bitwise_xor()分别执行按位与/或/非/异或运算。掩膜就是用来对图片进行全局或局部的遮挡。

平滑图像
模糊/平滑图片来消除图片噪声
OpenCV函数:cv2.blur(), cv2.GaussianBlur(), cv2.medianBlur(), cv2.bilateralFilter()

它们都属于卷积,不同滤波方法之间只是卷积核不同(对线性滤波而言) 低通滤波器是模糊,高通滤波器是锐化
低通滤波器就是允许低频信号通过,在图像中边缘和噪点都相当于高频部分,所以低通滤波器用于去除噪点、平滑和模糊图像。高通滤波器则反之,用来增强图像边缘,进行锐化处理。
常见噪声有椒盐噪声和高斯噪声,椒盐噪声可以理解为斑点,随机出现在图像中的黑点或白点;高斯噪声可以理解为拍摄图片时由于光照等原因造成的噪声。

均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值,用cv2.blur()实现,如3×3的卷积核:kernel=1/9*[[1,1,1],[1,1,1],[1,1,1]]

img = cv2.imread('lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
blur = cv2.blur(img, (10, 10))  # 均值模糊
plt.imshow(blur)
# 就是模糊了,我也不知道不同模糊有什么区别,只有很糊和一般糊。还有比较糊……

方框滤波跟均值滤波很像,如3×3的滤波核如下:k=a*[[1,1,1],[1,1,1],[1,1,1]]
用cv2.boxFilter()函数实现,当可选参数normalize为True的时候,方框滤波就是均值滤波,上式中的a就等于1/9;normalize为False的时候,a=1,相当于求区域内的像素和。

前面两种滤波方式,卷积核内的每个值都一样,也就是说图像区域中每个像素的权重也就一样。高斯滤波的卷积核权重并不相同:中间像素点权重最高,越远离中心的像素权重越小。
显然这种处理元素间权值的方式更加合理一些。图像是2维的,所以我们需要使用2维的高斯函数,比如OpenCV中默认的3×3的高斯卷积核:k=[[0.0625,0.125,0.0625],[0.125,0.25,0.0625],[0.0625,0.125,0.0625]]
OpenCV中对应函数为cv2.GaussianBlur(src,ksize,sigmaX): 参数3
σx值越大,模糊效果越明显。高斯滤波相比均值滤波效率要慢,但可以有效消除高斯噪声,能保留更多的图像细节,所以经常被称为最有用的滤波器。均值滤波与高斯滤波的对比结果如下(均值滤波丢失的细节更多)

中值又叫中位数,是所有数排序后取中间的值。中值滤波就是用区域内的中值来代替本像素值,所以那种孤立的斑点,如0或255很容易消除掉,适用于去除椒盐噪声和斑点噪声。中值是一种非线性操作,效率相比前面几种线性滤波要慢。

median = cv2.medianBlur(img, 9)  # 中值滤波
plt.imshow(median)

模糊操作基本都会损失掉图像细节信息,尤其前面介绍的线性滤波器,图像的边缘信息很难保留下来。然而,边缘(edge)信息是图像中很重要的一个特征,所以这才有了双边滤波。用cv2.bilateralFilter()函数实现:可以看到,双边滤波明显保留了更多边缘信息。

blur = cv2.bilateralFilter(img, 9, 75, 75)  # 双边滤波
plt.imshow(blur)
#  图像锐化
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) #定义一个核
dst = cv2.filter2D(img, -1, kernel=kernel)
plt.imshow(dst)

边缘检测
Canny边缘检测的简单概念、OpenCV函数:cv2.Canny()
Canny边缘检测方法常被誉为边缘检测的最优方法:cv2.Canny()进行边缘检测,参数2、3表示最低、高阈值,下面来解释下具体原理。

Canny边缘提取的具体步骤如下:

使用5×5高斯滤波消除噪声:边缘检测本身属于锐化操作,对噪点比较敏感,所以需要进行平滑处理。 计算图像梯度的方向:
首先使用Sobel算子计算两个方向上的梯度$ G_x 和和和 G_y $,然后算出梯度的方向:
保留这四个方向的梯度:0°/45°/90°/135°,有什么用呢?我们接着看。 取局部极大值:
梯度其实已经表示了轮廓,但为了进一步筛选,可以在上面的四个角度方向上再取局部极大值 滞后阈值:
经过前面三步,就只剩下0和可能的边缘梯度值了,为了最终确定下来,需要设定高低阈值:
1.像素点的值大于最高阈值,那肯定是边缘
2.同理像素值小于最低阈值,那肯定不是边缘
3.像素值介于两者之间,如果与高于最高阈值的点连接,也算边缘,所以上图中C算,B不算 Canny推荐的高低阈值比在2:1到3:1之间。

img = cv2.imread('lena.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
edges = cv2.Canny(img, 30, 70)  # canny边缘检测
plt.imshow(edges)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值