[opencv][python] 学习手册3:练习代码2
46_图像降噪-均值滤波.py
47_图像降噪-均值滤波api.py
48_图像降噪-中值滤波api.py
49_图像降噪-加权均值滤波.py
50_高斯模糊.py
51_Sobel算子.py
52_Sobel算子_api.py
53_Scharr函数_Sobel改进版.py
54_拉普拉斯算子.py
55_补充-锐化滤波.py
文章目录
46_图像降噪_椒盐噪声原理
原理
- 创建和原图同大小随机矩阵点 pepper_noise,点的总个数 height X width,每个点的随机取值范围 [0, 255]
- 定义噪声率 ratio = 0.1,即 椒噪声的分界值为 25.6
- 将 pepper_noise 随机矩阵中的点二值化,小于 25.6 的噪声位置赋值 -255(椒噪声)
代码
"""
需求:
1. 生成椒盐噪声
"""
import logging
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 配置日志
logging.basicConfig(level=logging.INFO)
height = 600
width = 800
# 创建和原图同大小随机矩阵
pepper_noise = np.random.randint(0, 256, (height, width))
pepper_noise = pepper_noise.astype(np.uint8)
logging.info("pepper_noise:[{0}]\nshape:[{1}]\ndtype:[{2}]".format(pepper_noise,
pepper_noise.shape,
pepper_noise.dtype))
# 计算直方图,方式一,并绘制 api: cv.calcHist([src_gray], [0], None, [256], [0, 256])
hist_pepper_noise = cv.calcHist([pepper_noise], [0], None, [256], [0, 256])
fig1 = plt.figure()
fig1.canvas.set_window_title("hist_pepper_noise")
plt.plot(hist_pepper_noise)
# 计算直方图,方式二,并绘制
fig2 = plt.figure()
fig2.canvas.set_window_title("hist_pepper_noise_plt")
plt.hist(pepper_noise.ravel(), bins=256, rwidth=0.5)
# # 定义10%的噪声 256×10%=25.6
ratio = 0.1
# 若值小于25.6 则置为-255,否则为0
pepper_noise = np.where(pepper_noise < ratio * 256, -255, 0)
# 计算直方图,方式二,并绘制
fig3 = plt.figure()
fig3.canvas.set_window_title("hist_pepper_noise_plt_ratio")
plt.hist(pepper_noise.ravel(), bins=256, rwidth=0.5)
# cv.imshow("pepper_noise", pepper_noise)
plt.show()
# cv.waitKey(0)
运行结果
E:\Software\A_anaconda\envs\python3\python.exe E:/WorkSpace/WS_CV_2D/day03/46_图像降噪_生成噪声.py
INFO:root:pepper_noise:[[[219 149 177 ... 55 3 74]
[147 137 198 ... 118 143 181]
[ 28 244 119 ... 208 101 206]
...
[203 219 166 ... 27 107 18]
[182 69 245 ... 208 241 144]
[ 98 3 3 ... 187 198 172]]]
shape:[(600, 800)]
dtype:[uint8]
- 左上,右上图显示的是二值化之前随机噪声直方图,横坐标表示颜色值范围 [0, 255],纵坐标表示矩阵中对应的颜色个数
- 左下图显示的是二值化之后的噪声直方图,可以看见,横坐标只有两个有效值 [0, -255],纵坐标对应的二值化后的颜色个数
46_图像降噪-生成椒盐噪声_单通道
原理
- 根据之前的椒噪声原理,椒噪声被赋值 -255,盐噪声被赋值 255,类型为 int(整数)
- 将目标图像,椒噪声,盐噪声的的类型转化为 float(浮点类型),并相加,则图像矩阵值是包含正负的浮点数
- 在对结果矩阵进行越界处理时,将大于 255 的值设置为 255(盐点、盐噪声), 小于 0 的值设置为 0(椒点、椒噪声)
代码
"""
需求:
对图像加上噪声
单通道图像
"""
import cv2 as cv
import numpy as np
filename = r"../img/mountain.jpg"
img = cv.imread(filename, cv.IMREAD_GRAYSCALE)
height = img.shape[0]
width = img.shape[1]
# 创建和原图同大小随机矩阵 胡椒噪声
pepper_noise = np.random.randint(0, 256, (height, width))
# 创建和原图同大小随机矩阵 盐噪声
salt_noise = np.random.randint(0, 256, (height, width))
# 定义10%的噪声 256×10%=25.6
ratio = 0.1
# 若值小于25.6 则置为-255,否则为0
pepper_noise = np.where(pepper_noise < ratio * 256, -255, 0)
# 若值大于25.6 则置为255,否则为0
salt_noise = np.where(salt_noise < ratio * 256, 255, 0)
# 将uint8类型转成浮点类型
img.astype("float")
pepper_noise.astype("float")
salt_noise.astype("float")
# 将 胡椒噪声 添加到原图中
dst_img = img + pepper_noise
# 校验越界问题
dst_img = np.where(dst_img > 255, 255, dst_img)
dst_img = np.where(dst_img < 0, 0, dst_img)
cv.imshow("pepper img", dst_img.astype("uint8"))
# 将 盐噪声 添加到原图中
dst_img = img + salt_noise
# 校验越界问题
dst_img = np.where(dst_img > 255, 255, dst_img)
dst_img = np.where(dst_img < 0, 0, dst_img)
cv.imshow("salt img", dst_img.astype("uint8"))
# 将 椒盐噪声 添加到原图中
dst_img = img + pepper_noise + salt_noise
# 校验越界问题
dst_img = np.where(dst_img > 255, 255, dst_img) # 设置盐噪声
dst_img = np.where(dst_img < 0, 0, dst_img) # 设置椒噪声
cv.imshow("pepper salt img", dst_img.astype("uint8"))
cv.waitKey(0)
运行结果
46_图像降噪-生成椒盐噪声_三通道
原理
对于三通道图像,需要将椒盐噪声矩阵通过 merge 函数融合成三通道矩阵,然后才能与原图像相加,否则会报错(无法广播)
代码
"""
需求:
对图像加上噪声
三通道图像
"""
import logging
import cv2 as cv
import numpy as np
logging.basicConfig(level=logging.INFO)
filename = r"../img/grbq.jpg"
img = cv.imread(filename, cv.IMREAD_COLOR)
height = img.shape[0]
width = img.shape[1]
cv.imshow("src", img)
# 创建和原图同大小随机矩阵 胡椒噪声
pepper_noise = np.random.randint(0, 256, (height, width))
# 创建和原图同大小随机矩阵 盐噪声
salt_noise = np.random.randint(0, 256, (height, width))
# 定义10%的噪声 256×10%=25.6
ratio = 0.1
# 若值小于25.6 则置为-255,否则为0
pepper_noise = np.where(pepper_noise < ratio * 256, -255, 0)
# 若值大于25.6 则置为255,否则为0
salt_noise = np.where(salt_noise < ratio * 256, 255, 0)
# 将uint8类型转成浮点类型
img.astype("float")
pepper_noise.astype("float")
salt_noise.astype("float")
pepper_noise_c3 = cv.merge([pepper_noise, pepper_noise, pepper_noise])
salt_noise_c3 = cv.merge([salt_noise, salt_noise, salt_noise])
logging.info("pepper_noise_c3\nshape::[{0}]\ndtype::[{1}]".format(pepper_noise_c3.shape, pepper_noise_c3.dtype))
logging.info("salt_noise_c3\nshape::[{0}]\ndtype::[{1}]".format(salt_noise_c3.shape, salt_noise_c3.dtype))
# 将 胡椒噪声 添加到原图中
dst_img = img + pepper_noise_c3
# 校验越界问题
dst_img = np.where(dst_img > 255, 255, dst_img)
dst_img = np.where(dst_img < 0, 0, dst_img)
dst_pepper = dst_img.copy()
cv.imshow("pepper img", dst_img.astype("uint8"))
# 将 盐噪声 添加到原图中
dst_img = img + salt_noise_c3
# 校验越界问题
dst_img = np.where(dst_img > 255, 255, dst_img)
dst_img = np.where(dst_img < 0, 0, dst_img)
dst_salt = dst_img.copy()
cv.imshow("salt img", dst_img.astype("uint8"))
# 将 椒盐噪声 添加到原图中
dst_img = img + pepper_noise_c3 + salt_noise_c3
# 校验越界问题
dst_img = np.where(dst_img > 255, 255, dst_img)
dst_img = np.where(dst_img < 0, 0, dst_img)
dst_salt_pepper = dst_img.copy()
cv.imshow("pepper salt img", dst_img.astype("uint8"))
# cv.imwrite("../img/room_salt.jpg", dst_salt)
# cv.imwrite("../img/room_pepper.jpg", dst_pepper)
# cv.imwrite("../img/room_salt_pepper.jpg", dst_salt_pepper)
cv.waitKey(0)
运行结果
E:\Software\A_anaconda\envs\python3\python.exe E:/WorkSpace/WS_CV_2D/day03/46_图像降噪_生成噪声_3.py
INFO:root:pepper_noise_c3
shape::[(421, 704, 3)]
dtype::[int32]
INFO:root:salt_noise_c3
shape::[(421, 704, 3)]
dtype::[int32]
Process finished with exit code 0
46_图像降噪-均值滤波.py
原理(截取自课件)
- 线性滤波是图像处理最基本的方法,它允许我们对图像进行处理,产生很多不同的效果。
- 首先,我们需要一个二维的滤波器矩阵(卷积核)和一个要处理的二维图像。
- 然后,对于图像的每一个像素点,计算它的邻域像素和滤波器矩阵的对应元素的乘积,
- 然后加起来,作为该像素位置的值。这样就完成了滤波过程。
- 对图像和滤波矩阵进行逐个元素相乘再求和的操作就相当于将一个二维的函数移动到另一个二维函数的所有位置,这个操作就叫卷积
均值滤波
代码
"""
均值滤波
将卷积核内的所有灰度值加起来,然后计算出平均值,用这个平均值填充卷积核正中间的值,
这样做可以降低图像的噪声,同时也会导致图像变得模糊
[
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
] x 1/9
进行卷积操作时,使用 cv 的 api filter2D
需求:
进行单通道降噪操作
1. 读取图像噪声图,将图像装换成灰度图
2. 定义均值滤波卷积核
3. 使用 api filter2D 进行卷积运算
4. 显示图像,等待按键
"""
import logging
import cv2 as cv
import numpy as np
logging.basicConfig(level=logging.INFO)
# 1. 读取图像噪声图,将图像装换成灰度图
filename_org = r"../img/room.jpg"
filename = r"../img/room_salt_pepper.jpg"
org = cv.imread(filename_org, cv.IMREAD_COLOR)
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 定义均值滤波卷积核
kernel = np.array([
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
]) / 9
# 3. 使用 api filter2D 进行卷积运算
"""
dst = cv.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]] )
src input image.
dst output image of the same size and the same number of channels as src.
when ddepth=-1, the output image will have the same depth as the source.
"""
dst = cv.filter2D(gray, -1, kernel)
dst_c3 = cv.filter2D(src, -1, kernel)
# 4. 显示图像,等待按键
cv.imshow("org", org)
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("dst", dst)
cv.imshow("dst_c3", dst_c3)
key = cv.waitKey(0)
logging.info("key = [{0}]".format(key))
运行结果
47_图像降噪-均值滤波_api.py
代码
"""
均值滤波
将卷积核内的所有灰度值加起来,然后计算出平均值,用这个平均值填充卷积核正中间的值,
这样做可以降低图像的噪声,同时也会导致图像变得模糊
[
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
] x 1/9
进行卷积操作时,使用 cv 的 api filter2D
需求:
进行单通道降噪操作
1. 读取图像噪声图,将图像装换成灰度图
2. 定义均值滤波卷积核
3. 使用 api filter2D 进行卷积运算
4. 显示图像,等待按键
"""
import logging
import cv2 as cv
import numpy as np
logging.basicConfig(level=logging.INFO)
# 1. 读取图像噪声图,将图像装换成灰度图
filename_org = r"../img/room.jpg"
filename = r"../img/room_salt_pepper.jpg"
org = cv.imread(filename_org, cv.IMREAD_COLOR)
src = cv.imread(filename, cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 2. 定义均值滤波卷积核
kernel = np.array([
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
]) / 9
# 3. 使用 api filter2D 进行卷积运算
"""
dst = cv.filter2D( src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]] )
src input image.
dst output image of the same size and the same number of channels as src.
when ddepth=-1, the output image will have the same depth as the source.
"""
dst = cv.filter2D(gray, -1, kernel)
dst_c3 = cv.filter2D(src, -1, kernel)
# 4. 显示图像,等待按键
cv.imshow("org", org)
cv.imshow("src", src)
cv.imshow("gray", gray)
cv.imshow("dst", dst)
cv.imshow("dst_c3", dst_c3)
key = cv.waitKey(0)
logging.info("key = [{0}]".format(key))
运行结果(同上)
48_图像降噪-中值滤波_api.py
中值滤波
- 对邻近的像素点进行灰度排序,然后取中间值,它能有效去除图像中的椒盐噪声
- 操作原理: 卷积域内的像素值从小到大排序 取中间值作为卷积输出
代码
"""
需求:
1. 使用 medianBlur 函数对图像进行处理
"""
import logging
import cv2 as cv
logging.basicConfig(level=logging.INFO)
src = cv.imread(r"../img/room_salt.jpg", cv.IMREAD_COLOR)
src = cv.imread(r"../img/room_pepper.jpg", cv.IMREAD_COLOR)
src = cv.imread(r"../img/room_salt_pepper.jpg", cv.IMREAD_COLOR)
# 中值滤波
dst = cv.medianBlur(src, 3)
cv.imshow("src", src)
cv.imshow("dst", dst)
key = cv.waitKey(0)
logging.info("key = [{0}]".format(key))
运行结果
中值滤波能够很好的消除椒盐噪声
49_图像降噪-加权均值滤波.py
加权均值滤波
同均值滤波,增加了权重
# 当前使用的卷积核
# 定义卷积核、 滤波器、滤波矩阵
kernel = np.array([[1, 2, 1],
[2, 4, 2],
[1, 2, 1]]) / 16
代码
"""
需求:
1.
"""
import logging
import cv2 as cv
import numpy as np
logging.basicConfig(level=logging.INFO)
# src = cv.imread(r"../img/room_salt.jpg", cv.IMREAD_COLOR)
# src = cv.imread(r"../img/room_pepper.jpg", cv.IMREAD_COLOR)
src = cv.imread(r"../img/room_salt_pepper.jpg", cv.IMREAD_COLOR)
# 定义卷积核、 滤波器、滤波矩阵
kernel = np.array([[1, 2, 1],
[2, 4, 2],
[1, 2, 1]]) / 16
# 执行运算
dst = cv.filter2D(src, -1, kernel)
cv.imshow("src", src)
cv.imshow("dst", dst)
key = cv.waitKey(0)
logging.info("key = [{0}]".format(key))
运行结果
效果没有中值滤波好
50_高斯模糊.py
原理
代码
"""
需求:
1.
"""
import cv2 as cv
def change_value(value):
# 标准差
dst = cv.GaussianBlur(src, (5, 5), value)
cv.imshow("dst", dst)
src = cv.imread("../img/room.jpg")
cv.imshow("src", src)
# cv.imshow("dst", src)
cv.namedWindow("dst", cv.WINDOW_AUTOSIZE)
cv.createTrackbar("constant", "dst", 0, 100, change_value)
change_value(0)
cv.waitKey()
cv.destroyAllWindows()
运行结果
51_Sobel算子.py
原理
- Sobel算子是像素图像边缘检测中最重要的算子之一。
- 在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。
- 在图像的任何一点使用此算子,将会产生该点对应的梯度矢量
为了提高计算机效率我们通常会使用: G = |Gx|+|Gy|
代码
使用自定义 sobel 算子 + filter2D api 进行图像梯度处理(计算图像的边缘)
# 水平梯度
kernel = np.array([[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]])
# 垂直梯度
kernel = np.array([[1, 0, -1],
[2, 0, -2],
[1, 0, -1]])
"""
需求:
1.
"""
import cv2 as cv
import numpy as np
src = cv.imread("../img/brain.jpg")
cv.imshow("src", src)
# 水平梯度
kernel = np.array([[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]])
dst1 = cv.filter2D(src, -1, kernel)
cv.imshow("dst1", dst1)
# 垂直梯度
kernel = np.array([[1, 0, -1],
[2, 0, -2],
[1, 0, -1]])
dst2 = cv.filter2D(src, -1, kernel)
cv.imshow("dst2", dst2)
result = dst1 + dst2
cv.imshow("result", result)
cv.waitKey()
运行结果
dst1 水平梯度图,dst2 竖直梯度图
52_Sobel算子_api.py
水平梯度 – x方向
竖直梯度 – y方向
代码
"""
需求:
1. 使用 Sobel api 进行图像梯度处理(计算图像的边缘)
"""
import cv2 as cv
src = cv.imread("../img/brain.jpg")
cv.imshow("src", src)
# 1.图像 2.输出类型与输入一致,3.计算x方向(水平)梯度,4.计算y方向(竖直)的梯度
dst1 = cv.Sobel(src, -1, 0, 1)
cv.imshow("dst1", dst1)
# 1.图像 2.输出类型与输入一致,3.计算x方向梯度,4.计算y方向的梯度
dst2 = cv.Sobel(src, -1, 1, 0)
cv.imshow("dst2", dst2)
result = dst1 + dst2
cv.imshow("result", result)
cv.waitKey()
运行结果(同上)
53_Scharr函数_Sobel改进版.py
由于使用Sobel算子计算的时候有一些偏差, 所以opencv提供了sobel的升级版Scharr函数,计算比sobel更加精细.
代码
"""
需求:
Sobel计算梯度的时候存在误差
"""
import cv2 as cv
src = cv.imread("../img/brain.jpg")
# x 方向(水平)进行梯度运算
x_h_dst = cv.Scharr(src, -1, 1, 0)
# y 方向(竖直)进行梯度运算
y_v_dst = cv.Scharr(src, -1, 0, 1)
dst = x_h_dst + y_v_dst
cv.imshow("src", src)
cv.imshow("x_dst", x_h_dst)
cv.imshow("y_dst", y_v_dst)
cv.imshow("dst", dst)
cv.waitKey()
运行结果
54_拉普拉斯算子.py
原理
- 通过拉普拉斯变换后增强了图像中灰度突变处的对比度,使图像中小的细节部分得到增强,使图像的细节比原始图像更加清晰。
- 普通算子,增强算子
代码
尝试手动实现拉普拉斯算子运算(自定义算子 + filter2D函数)
"""
需求:
1. 拉普拉斯函数 api 对图像进行处理
"""
import cv2 as cv
src = cv.imread("../img/grbq.jpg")
# src = cv.imread("../img/brain.jpg")
cv.imshow("src", src)
# 使用拉普拉斯算子
dst = cv.Laplacian(src, cv.CV_32F)
# dst = cv.Laplacian(src, -1)
# 取绝对值,将数据转到uint8类型
# Scales, calculates absolute values, and converts the result to 8-bit.
dst = cv.convertScaleAbs(dst)
cv.imshow("dst", dst)
cv.waitKey()
cv.destroyAllWindows()
运行结果
55_补充-锐化滤波.py
原理
- 图像的锐化和边缘检测很像,首先找到边缘,然后把边缘加到原来的图像上面,这样就强化了图像的边缘,使图像看起来更加锐利了
- 实际上是计算当前点和周围点的差别,然后将这个差别加到原来的位置上。另外,中间点的权值要比所有的权值和大于1,意味着这个像素要保持原来的值。
- 算子、卷积核
- 我们还可以按照公式来创建锐化滤波核:
代码
"""
需求:
1.
"""
import cv2 as cv
import numpy as np
src = cv.imread("../img/hehua.jpg")
# 锐化卷积核
kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
# Convolves an image with the kernel. 使用卷积核对图像进行卷积
# applies an arbitrary linear filter to an image. 利用线性滤波器处理图像
dst = cv.filter2D(src, -1, kernel)
cv.imshow("src", src)
cv.imshow("dst", dst)
cv.waitKey()
运行结果