源码和数据集获取地址:
链接:https://pan.baidu.com/s/104AGSp-4JMfENzUYv4bjhg
提取码:4g7c
实验一、图像的读取和运算
import cv2
import numpy as np
from matplotlib import pyplot as plt
def show_img(name,image):
cv2.imshow(name,image)
cv2.waitKey()
cv2.destroyAllWindows()
# 读入图片
img = cv2.imread('./image/leonard.jpg')
# 显示图片
show_img('leonard.jpg',img)
# 保存图片
cv2.imwrite('save.jpg',img)
True
# 图片运算
img1 = cv2.imread('./image/leonard.jpg')
img2 = cv2.imread('./image/leonard1.jpg')
add = cv2.add(img1,img2)
subtract = cv2.subtract(img1,img2)
multiply = cv2.multiply(img1,img2)
divide = cv2.divide(img1,img2)
img1 = cv2.imread('./image/leonard.jpg')
img2 = cv2.imread('./image/leonard1.jpg')
add = cv2.add(img1,img2)
subtract = cv2.subtract(img1,img2)
multiply = cv2.multiply(img1,img2)
divide = cv2.divide(img1,img2)
plt.subplot(161),plt.imshow(img1),plt.title('img1')
plt.subplot(162),plt.imshow(img2),plt.title('img2')
plt.subplot(163),plt.imshow(add),plt.title('add')
plt.subplot(164),plt.imshow(subtract),plt.title('subtract')
plt.subplot(165),plt.imshow(multiply),plt.title('multiply')
plt.subplot(166),plt.imshow(divide),plt.title('divide')
plt.show()
实验二、图像的灰度变换及直方图均衡化
任务:
以一幅 256×256 象素的数字图像为实验对象,观察图像的二值化效果和直方图分布。
对图像的直方图进行均衡化。
import cv2
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 图像二值化
img = cv2.imread('./image/leonard_256x256.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
cv_show('img_gray',img_gray)
print(img_gray)
print(img_gray.shape)
[[125 111 84 ... 20 18 18]
[149 127 96 ... 16 19 16]
[155 126 100 ... 15 20 17]
...
[ 49 56 62 ... 19 11 9]
[ 43 47 64 ... 16 6 4]
[ 33 56 61 ... 18 6 3]]
(256, 256)
# 图像直方图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
print(hist.shape) # (256, 1)一维数组,有256个数据,分别代表每个值出现的次数
# print(hist)
# img.ravel()将二维图像转换为一维的数据
plt.hist(img.ravel(),256)
plt.show()
(256, 1)
# 均衡化处理
import numpy as np
# 直接均衡化,均衡化后图像有些地方太亮,失去了细节信息
equ = cv2.equalizeHist(img_gray)
# 自适应直方图均衡化 保留了细节
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_clahe = clahe.apply(img_gray)
# 直方图对比
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure()
plt.subplot(311)
plt.hist(img_gray.ravel(),256,label='原始图像')
plt.legend(loc='upper right')
plt.subplot(312)
plt.hist(equ.ravel(),256,label='均衡化')
plt.legend(loc='upper right')
plt.subplot(313)
plt.hist(res_clahe.ravel(),256,label='自适应均衡化')
plt.legend(loc='upper right')
plt.show()
# 图像对比
res = np.hstack((img_gray,equ,res_clahe))
cv_show('res',res)
实验三、图像的平衡和锐化处理
任务:
- 以一幅 256×256 象素的数字图像为对象
采用中值滤波处理进行平滑处理
和 Soble 算子图像锐化方法
import cv2
import numpy as np
from IPython.display import Image
# 0 表示灰度图
img = cv2.imread('./image/leonard_256x256_Noise.jpg',0)
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 自定义的平均滤波
kernel = np.ones((5,5),np.float32)/25
print(kernel)
[[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]
[0.04 0.04 0.04 0.04 0.04]]
# 第二个参数为图像的深度,-1表示和原图一样
dst = cv2.filter2D(img,-1,kernel)
# 图像变得很模糊,看着有点难受的感觉
res = np.hstack((img,dst))
cv_show('Original&Averaging',res)
均值滤波
卷积框覆盖区域的所有像素的平均均值来代替中心元素
blur = cv2.blur(img,(5,5))
# 效果和平均滤波一样
res = np.hstack((img,blur))
cv_show('Original&Blur',res)
Image(filename = './image/1.png', width=400)
高斯滤波
可以有效的去除高斯噪点
(卷积核里的值符合高斯分布,中心的值最大,其余方框根据距离中心元素的距离递减,构成一个高斯小山包)
# 第三个参数为标准差,0表示函数自行计算
gaussianblur = cv2.GaussianBlur(img,(5,5),0)
res = np.hstack((img,gaussianblur))
cv_show('Original&GaussianBlur',res)
Image(filename = './image/2.png', width=400)
中值滤波(中值模糊)
用卷积框对应像素的中值来替换中心像素的值
常用于去除椒盐噪声
median = cv2.medianBlur(img,5)
res = np.hstack((img,gaussianblur))
cv_show('Original&medianBlur',res)
Image(filename='./image/3.png',width=400)
双边滤波
以保持边界清晰的情况况下有效的去除噪声
0 领域直径 两个75是 空间高斯函数标准差 灰度值相似性高斯函数标准差
bilatera = cv2.bilateralFilter(img,0,75,75)
res = np.hstack((img,bilatera))
cv_show('Original&bilateralFilter',res)
Image(filename='./image/4.png',width=400)
图像梯度
图像更加的细节
sobel算子
# ddepth:图像的深度(输入输出一样-1)
# dx和dy分别表示水平和竖直方向 dx :右边-左边,中间为0 dy:上边-下边,中间0
# ksize是Sobel算子的大小
sobelx= cv2.Sobel(img,-1,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely= cv2.Sobel(img,-1,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy= cv2.Sobel(img,-1,1,1,ksize=3) # 直接合并
sobelxy1 = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) # 分开按权重合并
res = np.hstack((img,sobelx,sobely,sobelxy,sobelxy1))
cv_show('res',res)
Image(filename='./image/5.png',width=1000)
scharr算子
# 相比sobel算子就是核(值)变大了,结果更敏感一些
scharrx = cv2.Scharr(img,-1,1,0)
scharry = cv2.Scharr(img,-1,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
res = np.hstack((img,scharrx,scharry,scharrxy))
cv_show('res',res)
Image(filename='./image/6.png',width=800)
laplacian算子
0 1 0
1 -4 1
0 1 0
laplacian = cv2.Laplacian(img,-1)
cv_show('laplacian',laplacian)
Image(filename='./image/7.png',width=200)
sobel算子效果一般,scharr效果更细节,laplacian比sobel更不明显
实验四-图像的膨胀、腐蚀和细化
任务:
- 对指定图像进行腐蚀、膨胀和细化,
- 把得到的结果图像都显示于屏幕上
# 方便查看图片导入的包
from IPython.display import Image
# 导入包,和图片显示函数
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 读入图片(以灰度图形式)
img = cv2.imread('./image/ka.png',0)
# 定义卷积核
kernel = np.ones((5,5),np.uint8)
kernel
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]], dtype=uint8)
腐蚀
作用:
- 腐蚀边缘,白色区域减小
- 可以有效的去除白噪声,也可以用来断开两个连在一起的物体
# iterations迭代执行次数
erosion = cv2.erode(img,kernel,iterations=1)
res = np.hstack((img,erosion))
cv_show('img&erosion',res)
Image(filename = './pic/1.png', width=400)
腐蚀
作用:
- 增加白色区域
- 一般去噪声时,先用腐蚀,再膨胀
- 也可以用来连接两个分开的物体
dilation = cv2.dilate(img,kernel,iterations=1)
res = np.hstack((img,dilation))
cv_show('img&dilation',res)
Image(filename='./pic/2.png',width=400)
开运算
作用:
- 先腐蚀再膨胀
- 用来去除噪声
img_Noise = cv2.imread('./image/ka_Noise.png',0)
opening = cv2.morphologyEx(img_Noise,cv2.MORPH_OPEN,kernel)
res = np.hstack((img_Noise,opening))
cv_show('img_Noise&opening',res)
Image(filename='./pic/3.png',width=400)
闭运算
作用:
- 先膨胀再腐蚀
- 常用来填充前景物体中的小洞,或小黑点
img_Noise1 = cv2.imread('./image/ka_Noise1.png',0)
closing = cv2.morphologyEx(img_Noise1,cv2.MORPH_CLOSE,kernel)
res = np.hstack((img_Noise1,closing))
cv_show('img_Noise1&closing',res)
Image(filename='./pic/4.png',width=400)
形态学梯度
- 膨胀与腐蚀的区别
- 结果看上去就像前景物体的轮廓
- 膨胀 - 腐蚀
gradint = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
res = np.hstack((img,gradint))
cv_show('img&gradint',res)
Image(filename='./pic/5.png',width=400)
礼帽
- 原图 - 开运算
kernel = np.ones((9,9),np.uint8)
tophat = cv2.morphologyEx(img_Noise,cv2.MORPH_TOPHAT,kernel)
res = np.hstack((img_Noise,tophat))
cv_show('img_Noise&tophat',res)
Image(filename='./pic/6.png',width=400)
黑帽
- 闭运算 - 原始图像
blackhat = cv2.morphologyEx(img_Noise1,cv2.MORPH_BLACKHAT,kernel)
res = np.hstack((img_Noise1,blackhat))
cv_show('img_Noise1&blackhat',res)
Image(filename='./pic/7.png',width=400)
总结
- 腐蚀:减小白色区域,增加黑色区域,分开连在一起并且颜色差异不大的物体
- 膨胀: 增加白色区域,突出白色
- 开运算:先腐蚀,在膨胀,可去除明亮的小点
- 闭运算:先膨胀,再腐蚀,可去除明亮物体中的小黑点
- 礼帽:顶帽运算往往用来分离比邻近点亮一些的斑块
- 黑帽:用来分离比邻近点暗一些的斑块
实验五、图像阈值处理与边缘检测
任务:
- 对指定图像进行自适应门限值分割和边缘提取
# 方便查看图片导入的包
from IPython.display import Image
# 导入包,和图片显示函数
import cv2
import numpy as np
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
# 导入图片(原图)
img = cv2.imread('./image/leonard_256x256.jpg',0)
cv_show('img',img)
图像阈值处理
- src:表示的是图片源
- thresh:表示的是阈值(起始值)
- maxval:表示的是最大值
- type:表示的是这里划分的时候使用的是什么类型的算法,常用值为0(cv2.THRESH_BINARY)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
print(ret) # ret就是最小值(起始值),th1是图像
ret,th2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,th3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,th4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,th5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
res = np.hstack((th1,th2,th3,th4,th5))
cv_show('res',res)
127.0
Image(filename='./image/1.png')
# 不同参数的图像,常用前两种
# THRESH_BINARY 大于127取255,否知取0
# THRESH_BINARY_INV 反之
自适应阈值
- 第一个原始图像
- 第二个像素值上限
- 第三个自适应方法Adaptive Method:
- cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权 重为一个高斯窗口
- 第四个值的赋值方法:只有cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV
- 第五个Block size:规定领域大小(一个正方形的领域)
- 第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值 就是求得领域内均值或者加权值),这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图像都用一个阈值。
# 中值滤波
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,1)
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,1)
res = np.hstack((img,th1,th2,th3))
cv_show('res',res)
Image(filename='./image/2.png')
Canny边缘检测
-
- 使用高斯滤波器,以平滑图像,滤除噪声。
-
- 计算图像中每个像素点的梯度强度和方向。
-
- 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
-
- 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
-
- 通过抑制孤立的弱边缘最终完成边缘检测。
canny函数参数:
- 后两个参数minVal,maxVal
- 梯度大于maxVal处理为边界
- 在两者之间,连接有边界保留,否者舍弃
- 小于minVal,舍弃
img = cv2.imread('./image/leonard_256x256.jpg',0)
# 高斯滤波
aussian = cv2.GaussianBlur(img, (3, 3), 1)
edges = cv2.Canny(aussian,100,200)
res = np.hstack((aussian,edges))
cv_show('res',res)
Image(filename='./image/3.png',width=400)
img = cv2.imread('./image/leonard_256x256.jpg',0)
# 高斯滤波
aussian = cv2.GaussianBlur(img, (3, 3), 1)
edges = cv2.Canny(aussian,245,255)
res = np.hstack((aussian,edges))
cv_show('res',res)
Image(filename='./image/4.png',width=400)