# 卷积
# 图像卷积就是卷积核在图像上按行滑动遍历像素时不断的相乘求和的过程
# 步长就是卷积核在图像上移动的步幅
# padding指的是填充0的圈数
# 图像卷积中,卷积核一般为奇数
# filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
# - ddepth是卷积之后图片的位深, 即卷积之后图片的数据类型, 一般设为-1, 表示和原图类型一致.
# - kernel是卷积核大小, 用元组或者ndarray表示, 要求数据类型必须是float型.
# - anchor 锚点, 即卷积核的中心点, 是可选参数, 默认是(-1,-1)
# - delta 可选参数, 表示卷积之后额外加的一个值, 相当于线性方程中的偏差, 默认是0.
# - borderType 边界类型.一般不设.
# opencv图像卷积操作
import cv2 as cv
import numpy as np
img= cv.imread("./dog.jpeg")
kernel = np.ones((5,5),np.float32)/25
# ddepth=-1表示图像的数据类型不变
dst = cv.filter2D(img,-1,kernel)
cv.imshow("img",np.hstack((img,dst)))
cv.waitKey(0)
cv.destroyAllWindows()
# 方盒滤波
# boxfilter(scr,ddepth,ksize)
# - normalize = True时, a = 1 / (W * H) 滤波器的宽高
# - normalize = False是. a = 1
# 一般情况我们都使用normalize = True的情况. 这时 方盒滤波 等价于 均值滤波
# blur(src, ksize[, dst[, anchor[, borderType]]]) 均值滤波.
import cv2 as cv
import numpy as np
img= cv.imread("./dog.jpeg")
kernel = np.ones((5,5),np.float32)/25
dst_box = cv.boxFilter(img,-1,(5,5))
dst_blur = cv.blur(img,(5,5))
cv.imshow("img",np.hstack((img,dst_box,dst_blur)))
cv.waitKey(0)
cv.destroyAllWindows()
# 高斯滤波GuassianBlur
# 高斯滤波的核心思想就是让邻近的像素具有更高的重要度,
# 对周围像素计算加权平均值,较近的像素具有较大的权重值
# 高斯函数符合高斯分布(也叫正态分布)
# 高斯滤波就是符合高斯分布的卷积核对图片进行卷积操作。
# GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])
# - kernel 高斯核的大小.
# - sigmaX, X轴的标准差
# - sigmaY, Y轴的标准差, 默认为0, 这时sigmaY = sigmaX
# - 如果没有指定sigma值, 会分别从ksize的宽度和高度中计算sigma.
# 选择不同的sigma值会得到不同的平滑效果, sigma越大, 平滑效果越明显.
# 没有指定sigma时, ksize越大, 平滑效果越明显
import cv2 as cv
import numpy as np
img= cv.imread("./dog.jpeg")
dst1 = cv.GaussianBlur(img,ksize = (5,5),sigmaX = 1)
dst2 = cv.GaussianBlur(img,ksize = (5,5),sigmaX = 10)
cv.imshow("img",np.hstack((img,dst1,dst2)))
cv.waitKey(0)
cv.destroyAllWindows()
# 中值滤波medianBlur
# 中值滤波的原理:
# 假设有一个数组[1556789],取其中的中间值(即中位数)作为卷积后的结果值即可
# 中值滤波对椒盐噪声效果明显
import cv2 as cv
import numpy as np
img= cv.imread("./dog.jpeg")
dst = cv.medianBlur(img,ksize = 5)
cv.imshow("img",np.hstack((img,dst)))
cv.waitKey(0)
cv.destroyAllWindows()
# 双边滤波bilateralBlur
# 双边滤波对于图像的边缘信息能更好的保存
# 其原理为一个空间距离相关的高斯函数与一个灰度距离相关的高斯函数相乘
# 空间距离:指的是当前点与中心点的欧氏距离
# 灰度距离:指的是当前灰度与中心点灰度的差的绝对值:
# 双边滤波本质上就是高斯滤波,双边滤波和高斯滤波不同的是,
# 双边滤波即利用了位置信息又利用了像素信息来定义滤波窗口的权重,
# 而高斯滤波只用了位置信息
# 对于高斯滤波,仅用空间距离的权值系数核与图像卷积后,
# 确定中心点的灰度值。即认为离中心点越近的点,其权重系数越大。
# 双边滤波中加入了对灰度信息的权重,
# 即在邻域内,灰度值越接近中心点灰度值的点的权重更大,灰度值相差大的点权重越小。
# 此权重大小,则由值域高斯函数确定。
# 两者权重系数相乘,得到最终的卷积模板。
# 由于双边滤波需要每个中心点邻域的灰度信息来确定其系数,
# 所以其速度与比一般的滤波慢很多,而且计算量增长速度为核大小的平方。
# 双边滤波可以保留边缘,同时对边缘内的区域进行平滑处理
# 双边滤波的作用将相当于做了美颜
# bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])
# - sigmaColor是计算像素信息使用的sigma
# - sigmaSpace是计算空间信息使用的sigma
# 双边滤波
import cv2 as cv
import numpy as np
img= cv.imread("./dog.jpeg")
dst = cv.bilateralFilter(img,7,50,50)
cv.imshow("img",np.hstack((img,dst)))
cv.waitKey(0)
cv.destroyAllWindows()
# sobel算子
# 边缘是像素值发生跃迁的位置,是图像的显著特征
# sobel算子对图像求一阶导数,一阶导数越大,说明像素在这个方向的变化越大,边缘信号越强
# 因为图像的灰度值都是离散的数字,sobel算子采用离散差分算子计算图像像素点亮度值的近似梯度
# 图像是二维的,即沿着宽度、高度两个方向
# 因此,使用两个卷积核对原图像进行处理
import cv2 as cv
import numpy as np
img= cv.imread("./chess.png")
dx = cv.Sobel(img,ddepth = cv.CV_64F,dx = 1,dy = 0,ksize = 5)
dy = cv.Sobel(img,ddepth = cv.CV_64F,dx = 0,dy = 1,ksize = 5)
dst = cv.addWeighted(dx,1,dy,1,0)
cv.imshow("img",np.hstack((img,dst)))
cv.waitKey(0)
cv.destroyAllWindows()
# Scharr算子
# scharr[scr,ddepth,dx,dy,ksize=3]
# opencv提供了scharr函数,但该函数仅作用于大小为3的内核,
# 该函数的运算与sobel函数一样快,但是结果却更加精确,放大了像素的变换
# - Scharr算子只支持3 * 3 的kernel所以没有kernel参数了.
# - Scharr算子只能求x方向或y方向的边缘.
# - Sobel算子的ksize设为-1就是Scharr算子.
# - Scharr擅长寻找细小的边缘, 一般用的较少.
import cv2 as cv
import numpy as np
img= cv.imread("./chess.png")
dx = cv.Scharr(img,ddepth = cv.CV_64F,dx = 1,dy = 0)
dy = cv.Scharr(img,ddepth = cv.CV_64F,dx = 0,dy = 1)
dst = cv.addWeighted(dx,1,dy,1,0)
cv.imshow("img",np.hstack((img,dst)))
cv.waitKey(0)
cv.destroyAllWindows()
# laplace算子
# sobel算子就是模拟一阶求导,导数越大的说明变换越剧烈,越有可能是边缘
# Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
# 可以同时求两个方向的边缘
# 对噪音敏感,一般需要先进行去噪,在调用拉普拉斯
import cv2 as cv
import numpy as np
img= cv.imread("./chess.png")
dst = cv.Laplacian(img,ddepth = cv.CV_64F,ksize = 3)
cv.imshow("img",np.hstack((img,dst)))
cv.waitKey(0)
cv.destroyAllWindows()
# canny边缘检测
# 最优边缘检测的三个主要评价标准:
# 低错误率:标识出尽可能多的实际边缘,同时尽可能的减少噪声产生误报
# 高定位性:表示出的边缘要与图像中的实际边缘尽可能接近
# 最小响应:图像中边缘只能标识一次
# canny边缘检测的一般步骤:
# 去噪,边缘检测易受到噪声影响,在进行边缘检测前通常要进行去噪,一般选用高斯滤波去除噪声
# 计算梯度,对平滑后的图像采用sobel算子计算梯度和方向
# 非极大值抑制--看图
# - 在获取了梯度和方向后, 遍历图像, 去除所有不是边界的点.
# - 实现方法: 逐个遍历像素点, 判断当前像素点是否是周围像素点中具有相同方向梯度的最大值.
# - 下图中, 点A,B,C具有相同的方向, 梯度方向垂直于边缘.
# - 判断点A是否为A,B,C中的局部最大值, 如果是, 保留该点;否则,它被抑制(归零)
import cv2 as cv
import numpy as np
#导入图片
img = cv.imread('./lena.png')#
# 阈值越小, 细节越丰富
lena1 = cv.Canny(img, 100, 200)
lena2 = cv.Canny(img, 64, 128)
cv.imshow("img",img)
cv.imshow('lena', np.hstack((lena1, lena2)))
cv.waitKey(0)
cv.destroyAllWindows()