前言#
如题所示,记录了本人学习opencv时的具体代码与注释,包括一些常见问题,但可能不会太详细,因为是回顾,所以问题大多解决,后期欢迎评论区提问。桀桀桀!基于pycharm的opencv入门笔记-CSDN博客
如果你用下面的代码报错了,可能是一些库没添加,你可以根据报错提示来下载对应的库。、
显示图片及属性(点灯!)#
首先,选取一个自己喜欢的图片,放入当前项目的文件地址。以下是我选取的图片,以及它的文件名luna.jpg。

import cv2
import matplotlib.pyplot as plt
import numpy as np
简单说,下面两行代码是为了方便后续的作图,引用的相关库。
plt.switch_backend('TkAgg') #matplotlib的其中一个backend的选项
显示图片#
为了方便后续绘制的图片或图像方便缩放或者移动,使用上述代码。
import cv2 #opencv读取的格式是BGR
import matplotlib.pyplot as plt
import numpy as np
plt.switch_backend('TkAgg')#matplotlib的其中一个backend的选项
img=cv2.imread('luna.jpg')#在当前路径下读取图片
print(img) #打印像素数组
def cv_showimg(name,img):
#图像显示,也可以创建多个窗口
cv2.imshow(name,img)
#等待时间,毫秒级,0表示任意键终止
cv2.waitKey(0)
cv2.destroyAllWindows()
cv_showimg('image',img)
运行得到一个名为img的窗口,显示图片。(下文的cv_showimg皆为上述代码中的定义函数)


属性#
打印出图片的像素点,即像素色块的方阵序列。
print(img.shape) #读取图片的属性
结果为
打印图片的像素高度,宽度以及颜色通道,图像的高度为 959像素,宽度为 959像素,并且有 3 个颜色通道(红、绿、蓝)。
#cv2.IMREAD_COLOR:彩色图像
#cv2.IMREAD_GRAYSCALE:灰度图像
图像可以由彩色,也能由灰度的形式表现。
img=cv2.imread('luna.jpg',cv2.IMREAD_GRAYSCALE)#将图片灰度化
cv_showimg('image',img)
cv2.imwrite('myluna.jpg',img)#保存图片
结果
视频的读取与处理#
与显示图片之前一样,先将视频boat.mp4(我的)添加至文件地址。
vc=cv2.VideoCapture('boat.mp4')#在当前路径下读取视频
if vc.isOpened():#检查是否打开正确
open, frame = vc.read()#frame是图像数组,即一帧图像
else:
open = False
while open:#遍历视频中的每一帧
ret, frame = vc.read()
if frame is None:
break
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#转换为灰度图
cv2.imshow('result',gray)
if cv2.waitKey(10) & 0xFF == 27:#27为退出键
break
vc.release()
cv2.destroyAllWindows
结果是,将视频的每一帧提取出来,进行灰度处理,再播放由处理后的灰度帧组成的视频,演示视频不方便放,可以自己试试。
代码 if cv2.waitKey(10) & 0xFF == 27:#27为退出键 即视频播放过程中按下ESC键,视频退出播放,可以将27改为其他数字,则对应的退出按钮也会改变。
截取部分图像数据(ROI)#
相当于裁剪图片大小,根据上文图片属性可知luna.jpg的高度为 959像素,宽度为 959像素。
img=cv2.imread('luna.jpg')
luna=img[300:800,100:500]
cv_showimg('luna',luna)
截取高度为300-800,宽度为100-500,结果为
窗口名称为luna
颜色通道提取#
img=cv2.imread('luna.jpg')#在当前路径下读取图片
b,g,r=cv2.split(img)#分离颜色通道,blue,green,red
img=cv2.merge((b,g,r))#重组
#只保留R, B:0,G:1,R:2
cur_img=img.copy()#创建原始图像的副本
cur_img[:,:,0] = 0#把B设置成0
cur_img[:,:,1] = 0#把G设置成0
cv_showimg('R',cur_img)#最后只能保留2通道red
举个例子,先分离颜色通道,再重新组装成图像(实际没变)。复制原先的图像,并命名为cur_img,通过操作将副本的blue,green通道关闭(B:0,G:1,R:2),保留了red。
结果
边界填充#
边界填充就是给图片的边界续上一段,补上一段的感觉。常见的边界填充分为五种,
1.复制,在边界补上和原先一样的边界
2.反射,在两边进行复制
3.反射,以最边缘为轴,作对称,补上和原先一样的边界
4.外包装,上下边界一样复制,将原图包装或者镶嵌进去
5.常量,使用常数值填充,value=0表示边框填充为黑色,RGB值为 (0, 0, 0),也可以写作value=[0, 0, 0]
top_size, bottom_size, left_size, right_size = (50,50,50,50)#上下左右
#Type:复制,反射(在两边进行复制),反射(以最边缘位轴,对称),外包装法,常量法(常数值填充)
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_CONSTANT,value=0)
import matplotlib.pyplot as plt
plt.subplot(231),plt.imshow(img,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(replicate,'gray'),plt.title('REFLECT')
plt.subplot(235),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()

数值计算#
img_luna=cv2.imread('luna.jpg')
img_luna2=img_luna +10
img_luna[:5,:,0]
img_luna2[:5,:,0]
print((img_luna+img_luna2)[:5,:,0])#超过255,用这个数取余255
print(cv2.add(img_luna,img_luna2)[:5,:,0])#超过255,就是255
先解释下img_luna[:5,:,0],在 OpenCV 中,通常它的形状是行数,列数,还有通道数,:5 表示前五行,: 则是全部列,0是第0个通道,在 BGR 图像中,0是用来选择 BGR 中的蓝色通道。
将img_luna中的每个像素加10,cv2.add函数会进行饱和相加,如果某个像素值超过 255,它会被设置为 255,数值计算后面会有用。
结果
图像融合#
import matplotlib.pyplot as plt
import numpy as np
plt.switch_backend('TkAgg')#matplotlib的其中一个backend的选项
img_luna=cv2.imread('luna.jpg')
img_lovegood=cv2.imread('lovegood.jpg')
print(img_luna.shape)
img_lovegood=cv2.resize(img_lovegood,(959, 959))
print(img_lovegood.shape)
res = cv2.addWeighted(img_luna, 0.4, img_lovegood, 0.6, 10)
plt.imshow(res)
plt.show()#使用matplotlib时最后一定要加
将两张图片进行融合,每张图片的尺寸维度和混合权重可以设置。
结果
图片阈值#
阈值可以理解为图片的像素值,比如说亮度。凡事先将图片灰度化[捂脸],通常有5个方法。
第一个,超过阈值(比如127)了,那就是255,反之则为0(亮为白点,暗为黑点)
第二个,未超过阈值(比如127)了,那就是255,反之则为0(亮为黑点,暗为白点)
第三个,截断,超过阈值即为阈值,未超过阈值就是本身
第四个,大于阈值为本身,小于或者等于阈值即为0
第五个,小于阈值为本身,其余为0
import matplotlib.pyplot as plt
import numpy as np
plt.switch_backend('TkAgg')#matplotlib的其中一个backend的选项
img_lovegood=cv2.imread('lovegood.jpg')
img_lovegood_gray=cv2.imread('lovegood.jpg',cv2.IMREAD_GRAYSCALE)#将图片灰度化
ret, thresh1 = cv2.threshold(img_lovegood_gray, 127, 255, cv2.THRESH_BINARY)#超过阈值(127)即为255,反之则为0(亮为白点,暗为黑点)
ret, thresh2 = cv2.threshold(img_lovegood_gray, 127, 255, cv2.THRESH_BINARY_INV)#上面反转,超过阈值(127)为0,反之则为255(亮为黑点,暗为白点)
ret, thresh3 = cv2.threshold(img_lovegood_gray, 127, 255, cv2.THRESH_TRUNC)#截断值,大于阈值即为阈值(大于127=127),小于阈值不变为本身
ret, thresh4 = cv2.threshold(img_lovegood_gray, 127, 255, cv2.THRESH_TOZERO)#大于阈值不变为本身,其余为0
ret, thresh5 = cv2.threshold(img_lovegood_gray, 127, 255, cv2.THRESH_TOZERO_INV)#上面反转,小于阈值不变为本身,其余为0
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img_lovegood, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2,3, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
结果
滤波(图像平滑处理)#
原图
简单来说,滤波就相当于磨皮。
均值滤波#
img_charming_girl=cv2.imread('table luna.jpg')
cv_showimg('img', img_charming_girl)
smaller = cv2.resize(img_charming_girl, (0,0), fx=0.6, fy=0.6)#把图片缩小
blur = cv2.blur(smaller, (3,3))
cv_showimg('blur', blur)
因为原图较大,先将原图缩小,然后使用均值滤波。
方框滤波#
box = cv2.boxFilter(smaller, -1, (3,3), normalize=True)#or False
高斯和中值滤波#
#高斯滤波
aussian = cv2.GaussianBlur(smaller, (5,5), 1)
#中值滤波(good)
median = cv2.medianBlur(smaller, 5)
高斯滤波与卷积核的计算相关,较小的值会保留更多细节,大一些会模糊化,原理不深入探讨。个人感觉中值滤波更好,下面附上所有滤波的对比。

第一张是原图,后面依次。
形态学操作#
腐蚀(去毛刺)#
通过缩小图像中的物体(通常是白色区域)去掉不需要的细节,比如小的突出部分。

最典型的一张图片,经过三次腐蚀得到
每次腐蚀的多少也是根据所选卷积核的大小得到的,这里不过多阐述。
img_fushi = cv2.imread('fushi3.png')
smaller = cv2.resize(img_fushi, (0,0), fx=0.4, fy=0.4)#把图片缩小
# cv_showimg('img', res)
kernel = np.ones((5,5), np.uint8)#选择核的矩阵
erosion_1 = cv2.erode(smaller, kernel, iterations = 1)
erosion_2 = cv2.erode(smaller, kernel, iterations = 2)
erosion_3 = cv2.erode(smaller, kernel, iterations = 3)
res_erosion = np.hstack((smaller,erosion_1, erosion_2, erosion_3))###np.vstack也行
cv_showimg('res_erosion', res_erosion)
而将(5,5)改为(8,8)后,差距显而易见。
膨胀#
腐蚀后可进行膨胀操作,将以(5,5)卷积核腐蚀后的结果以(3,3)膨胀三次。
kernel = np.ones((3,3), np.uint8)
dilate_1 = cv2.dilate(erosion_1, kernel, iterations = 1)#把腐蚀后的结果传入进行膨胀
dilate_2 = cv2.dilate(erosion_1, kernel, iterations = 2)
dilate_3 = cv2.dilate(erosion_1, kernel, iterations = 3)
res_dilate = np.hstack((dilate_1, dilate_2, dilate_3))###np.vstack也行
cv_showimg('res_dilate', res_dilate)

开运算#
开运算就是先腐蚀再膨胀,下图为例。
img = cv2.imread('fushi2.png')
smaller = cv2.resize(img, (0,0), fx=0.4, fy=0.4)#把图片缩小
kernel = np.ones((5,5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
cv_showimg('opening', opening)
结果
效果还不错。
闭运算#
img = cv2.imread('fushi2.png')
smaller = cv2.resize(img, (0,0), fx=0.4, fy=0.4)#把图片缩小
kernel = np.ones((5,5), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv_showimg('closing', closing)
结果
似乎没什么效果,没关系,我们试一下(8,8)
结果
[捂脸][捂脸][捂脸]
梯度#
梯度=膨胀-腐蚀
img = cv2.imread('fushi2.png')
kernel = np.ones((5,5), np.uint8)#选择5*5矩阵的核
dilate = cv2.dilate(img, kernel, iterations = 1)#膨胀1次
erosion = cv2.erode(img, kernel, iterations = 1)#腐蚀1次
res = np.hstack((dilate, erosion))
cv_showimg('res', res)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)#进行梯度运算,膨胀-腐蚀
cv_showimg('gradient', gradient)
先展示膨胀和腐蚀的结果

进行梯度运算后

礼帽与黑帽#
礼帽=原始输入-开运算结果
#礼帽
img = cv2.imread('fushi2.png')
kernel = np.ones((5,5), np.uint8)#选择5*5矩阵的核
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)#礼帽
cv_showimg('tophat', tophat)
结果
黑帽=闭运算-原始输入
##黑帽
img = cv2.imread('fushi2.png')
kernel = np.ones((5,5), np.uint8)#选择5*5矩阵的核
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)#黑帽
cv_showimg('blackhat', blackhat)
结果
可以发现结果就是两次运算与原图的相减。
轮廓#
图像轮廓#
mode:轮廓检索模式 cv2.findContours(img, mode, method) RETR_EXTERNAL:只检索最外面的轮廓 RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中 RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外界边界,第二层是空洞的边界 RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次(最常用的)
method:轮廓逼近方法 CHAIN_APPROX_NONE: 以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)(长方形四边) CHAIN_APPROX_SIMPLE:压缩水平的,垂直的和斜的部分,也就是,函数只保留他们的终点部分(长方形四顶点)
####为更高的准确度,使用二值法
gray = cv2.imread('fushi2.png',cv2.IMREAD_GRAYSCALE)#将图片灰度化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# cv_showimg('thresh', thresh)
##contours是一堆轮廓点(轮廓信息),hierarchy是层级
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)##由于版本问题,必须删除一个参数
############绘制轮廓
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
#需要copy,不然原图会变
img = cv2.imread('fushi2.png')
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)##(0,0,255)是BGR,-1是整体轮廓,2是线条的宽度
cv_showimg('res', res)

轮廓特征与近似#
轮廓特征包括面积和周长,可以采用
cnt = contours[0]
#面积
contourArea = cv2.contourArea(cnt)
print(contourArea)
#周长,True表示闭合的
arcLength = cv2.arcLength(cnt, True)
print(arcLength)
得到轮廓特征。
以下图为例,

img = cv2.imread('jinsi.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#将图片灰度化,在得到轮廓特征,更精确
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)#二值法
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)##由于版本问题,必须删除一个参数
cnt = contours[0]##如果图中只有一个轮廓,直接用第一个元素
draw_img = img.copy()
res = cv2.drawContours(draw_img, cnt, -1, (0, 0, 255), 2)##(0,0,255)是BGR,-1是整体轮廓,2是线条的宽度
cv_showimg('res', res)
先使用二值法进行图像处理,如果图中只有一个轮廓,就直接用数组的第一个元素,用红色描出轮廓,设置宽度。

轮廓近似法#
espilon = 0.01 * cv2.arcLength(cnt, True)##0.1倍周长
approx = cv2.approxPolyDP(cnt, espilon, True)##轮廓近似的数组
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)##(0,0,255)是BGR,-1是整体轮廓,2是线条的宽度
cv_showimg('res', res)

边界矩形#
img = cv2.imread('jinsi.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#灰度化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)#二值法
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
x,y,w,h = cv2.boundingRect(cnt)#得到边界矩形
img = cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)#做出矩形框,(0,255,0)绿色
cv_showimg('img', img)
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)#边界矩形

由此还可以作外接圆
(x,y), radius = cv2.minEnclosingCircle(cnt)#得到边界外接圆
center = (int(x), int(y))
radius = int(radius)
img = cv2.circle(img, center, radius, (0,255,0),2)
cv_showimg('img', img)

#
图像梯度#
Sobel算子#
例一#

以上图为例。
先介绍下相关函数
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
#ddepth: 图像的深度(通常为-1,表示输出和输入深度是一样的),(cv2.CV_64F表示能使用负数)
#dx和dy分别表示水平和竖直方向
#ksize是Sobel算子的大小(几乘几的矩阵大小)
先使dx=1,dy=0(算水平不算竖直)(没取绝对值,只有白到黑那一半),
img = cv2.imread('pi.png')
# cv_showimg('img', img)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize = 3)#dx=1,dy=0(算水平不算竖直)(没取绝对值,只有白到黑那一半)
cv_showimg('sobelx', sobelx)
结果
上述代码中未加绝对值,白到黑是正数,黑到白是负数,所有负数会被截断成0,所以要取绝对值。
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize = 3)#dx=1,dy=0(算水平不算竖直)(先把正负数都算出来)
sobelx = cv2.convertScaleAbs(sobelx)#Abs是算负数的绝对值
结果
再将x,y相掉,
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize = 3)#dx=0,dy=1(算竖直不算水平)
sobely = cv2.convertScaleAbs(sobely)#Abs是算负数的绝对值
cv_showimg('sobely', sobely)
得到
最后将x,y相结合,得到xy梯度
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
cv_showimg('sobelxy', sobelxy)
得到
然后就有人要问了,为什么不直接计算xy梯度,而要分别计算出x梯度和y梯度然后相结合才得出xy梯度呢?我们看下直接计算xy梯度的效果。
#直接计算xy梯度(不建议)
sobelxy = cv2.Sobel(img, cv2.CV_64F, 1, 1, ksize = 3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_showimg('sobelxy', sobelxy)
结果
,得到的差异还是挺大的,四周边框消失,白点更多,更密集。
例二#
img = cv2.imread('luna.jpg',cv2.IMREAD_GRAYSCALE)
# cv_showimg('img', img)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize = 3)#dx=1,dy=0(算水平不算竖直)(先把正负数都算出来)
sobelx = cv2.convertScaleAbs(sobelx)#Abs是算负数的绝对值
# cv_showimg('sobelx', sobelx)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize = 3)#dx=0,dy=1(算竖直不算水平)
sobely = cv2.convertScaleAbs(sobely)#Abs是算负数的绝对值
# cv_showimg('sobely', sobely)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
cv_showimg('sobelxy', sobelxy)
###整体进行计算(不建议)
sobelxy = cv2.Sobel(img, cv2.CV_64F, 1, 1, ksize = 3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_showimg('sobelxy', sobelxy)
x梯度结果
y梯度结果
xy梯度(x梯度和y梯度相结合)

直接计算xy梯度

对比就出来了。
几种算子的对比#
除了Sobel算子外,还有Scharr算子,laplacian算子,不在一一阐述。
img = cv2.imread('loveluna.jpg',cv2.IMREAD_GRAYSCALE)
smaller = cv2.resize(img, (0,0), fx=0.25, fy=0.25)#把图片缩小
sobelx = cv2.Sobel(smaller, cv2.CV_64F, 1, 0, ksize = 3)#dx=1,dy=0(算水平不算竖直)(先把正负数都算出来)
sobelx = cv2.convertScaleAbs(sobelx)#Abs是算负数的绝对值
sobely = cv2.Sobel(smaller, cv2.CV_64F, 0, 1, ksize = 3)#dx=0,dy=1(算竖直不算水平)
sobely = cv2.convertScaleAbs(sobely)#Abs是算负数的绝对值
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
scharrx = cv2.Scharr(smaller, cv2.CV_64F, 1, 0)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.Scharr(smaller, cv2.CV_64F, 0, 1)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
laplacian = cv2.Laplacian(smaller, cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((smaller, sobelxy, scharrxy, laplacian))
cv_showimg('res', res)
对比结果
边缘检测#
这里使用Canny边缘检测,
1)使用高斯滤波器,以平滑图像,滤除噪声 2)计算图像中每个像素点的梯度强度和方向 3)应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散相应 4)应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘 5)通过抑制孤立的弱边缘最终完成边缘检测
以一张小猫图片为例,上来先缩图[捂脸][捂脸][捂脸]

img = cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)
smaller = cv2.resize(img, (0,0), fx=0.3, fy=0.3)#把图片缩小
v1 = cv2.Canny(smaller, 120, 250)
v2 = cv2.Canny(smaller, 50, 100)
res= np.hstack((smaller, v1, v2))
cv_showimg('res', res)
结果
金字塔#
图像金字塔#
对图像,先上采样,再下采样,即先放大再缩小,最终得到的图片是较模糊的。
####################图像金字塔,金字塔制作方法
img = cv2.imread('loveluna.jpg')
smaller = cv2.resize(img, (0,0), fx=0.3, fy=0.3)#把图片缩小
# cv_showimg('img', img)
print(smaller.shape)
up = cv2.pyrUp(smaller)##上采样(放大)
# cv_showimg('up', up)
print(up.shape)
down = cv2.pyrDown(smaller)##下采样(缩小)
# cv_showimg('down', down)
print(down.shape)
up_down = cv2.pyrDown(up)##先向上采样后向下采样,得到的图像比原来模糊
# cv_showimg('up_down', up_down)
print(up_down.shape)
res = np.hstack((smaller, up_down))
cv_showimg('res', res)
结果

拉普拉斯金字塔#
拉普拉斯金字塔 先低通滤波,然后缩小尺寸,放大尺寸,图像相减。。
img = cv2.imread('loveluna.jpg')
smaller = cv2.resize(img, (0,0), fx=0.5, fy=0.5)#把图片缩小
# cv_showimg('img', img)
down = cv2.pyrDown(smaller)
down_up = cv2.pyrUp(down)
i_1 = smaller - down_up
cv_showimg('i_1', i_1)
结果
有点感人。
模板匹配#
简单来说,就是使用对比检测的方法判断某局部图像在整体图像中的位置。
TM_SQDIFF:计算平方不同,计算出的值越小,越相关 TM_CCORR:计算相关性,计算出的值越大,越相关 TM_CCOEFF:计算相关系数,计算出的值越大,越相关 TM_SQDIFF_NORMED:计算归一化平方不同,计算出的值越接近0,越相关 TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关 TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
接下来一一使用

为整体图片

为局部图片
img = cv2.imread('charming girl.jpg', 0)
template = cv2.imread('girl face.png', 0)
h, w = template.shape[:2]
print("img.shape is",img.shape)
print("template.shape is",template.shape)
methods = ['cv2.TM_CCOEFF','cv2.TM_CCORR_NORMED','cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
print("res.shape is",res.shape)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print("min_val is",min_val)
print("max_val is",max_val)
print("min_loc is",min_loc)##左上角的点
print("max_loc is",max_loc)
for meth in methods:
img2 = img.copy()
#匹配方法的真值
method = eval(meth)
print(method)
res = cv2.matchTemplate(img, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
#如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
#画矩形
cv2.rectangle(img2, top_left, bottom_right, 255, 2)
plt.subplot(121), plt.imshow(res, cmap = 'gray')
# plt.xticks([]), plt.yticks([]) #隐藏坐标轴
plt.subplot(122),plt.imshow(img2, cmap = 'gray')
# plt.xticks([]), plt.yticks([]) #隐藏坐标轴
plt.suptitle(meth)
plt.show()






直方图#
绘制#
cv2.calcHist(images, channels, mask, histSize, ranges) images:原图像格式为unit8或float32,传入函数时用[]先把正负数都算出来 channels:用[],如果入图像是灰度图,它的值就是[0],如果是彩色图像的传入的参数可以是[0][1][2]它们对应BGR mask:掩模图像,统整幅图像的直方图就把它为None,但是如果想统图像某一分的直方图,就制作一个掩模图像并使用它 histSize: BIN的数目。也应用[],直方图每个范围大小 range: 像素值范围常为[0, 256]
img = cv2.imread('lovegood.jpg')
hist = cv2.calcHist([img], [0], None, [256], [0,256])
# print("hist.shape is",hist.shape)
plt.hist(img.ravel(), 256)
plt.show()
#####遍历三种颜色的直方图
img = cv2.imread('many cats.jfif')
color = ('b', 'g', 'r')
for i, col in enumerate(color):
histr = cv2.calcHist([img], [i], None, [256], [0,256])
plt.plot(histr, color = col)
plt.xlim([0,256])
plt.show()
遍历三种颜色的直方图

掩码(mask)#
掩码操作是为了截取图像的一部分,先创建掩码,掩码的像素数组必须小于待截取图像的大小,接着截取图像


最后列出进行对比,并绘制该区域直方图,

#mask操作(掩码)##截取图像操作
#创建mask
img = cv2.imread('lovegood.jpg')
print(img.shape)
mask = np.zeros(img.shape[:2], np.uint8)#无符号整形
mask[200:450, 200:450] = 255
cv_showimg('mask', mask)
img = cv2.imread('lovegood.jpg', 0)
# cv_showimg('img', img)
masked_img = cv2.bitwise_and(img, img, mask=mask)#与操作
cv_showimg('masked_img', masked_img)
#
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256])
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full),plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
直方图均衡化#
不多说,效果很好
img = cv2.imread('lovegood.jpg', 0)
smaller = cv2.resize(img, (0,0), fx=0.6, fy=0.6)#把图片缩小
plt.hist(smaller.ravel(), 256)
# plt.show()
equ = cv2.equalizeHist(smaller)#直方图均衡化
plt.hist(equ.ravel(), 256)
# plt.show()
res = np.hstack((smaller, equ))
cv_showimg("res", res)
#自适应均衡化
clahe = cv2.createCLAHE(clipLimit = 2.0, tileGridSize = (8, 8))
res_clahe = clahe.apply(smaller)
res = np.hstack((smaller, equ, res_clahe))
cv_showimg('res', res)

傅里叶变换#
这节了解下就行。
高频:变化剧烈的灰度分量
低频:变化缓慢的灰度分量
滤波:低通:只保留低频,使图像模糊
高通:只保留高频,使图像细节增强
img = cv2.imread('charming girl.jpg', 0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)#执行傅里叶变换
dft_shift = np.fft.fftshift(dft)
#得到灰度图能表现的形式
magnitude_spectrum = 20 * np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))##将实部和虚部进行处理
#低频在中间的表达
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'),plt.xticks([]),plt.yticks([])
plt.show()
####低通滤波
img = cv2.imread('charming girl.jpg', 0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)#执行傅里叶变换
dft_shift = np.fft.fftshift(dft)#将左上角放到中间
#得到灰度图能表现的形式
rows, cols = img.shape
crow, ccol = int(rows/2), int(cols/2) #中心位置
###低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1##左30,右30,上下30分别置为1(除了中间是1,其余都是0)
#IDFT##傅里叶变化向原始图像中逆变换的过程
fshift = dft_shift * mask#将掩码与图像结合
f_ishift = np.fft.ifftshift(fshift)#将中间还回去
img_back = cv2.idft(f_ishift)#将中间还回去
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])##将实部和虚部进行处理
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'),plt.xticks([]),plt.yticks([])
plt.show()
####################高通滤波
img = cv2.imread('charming girl.jpg', 0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)#执行傅里叶变换
dft_shift = np.fft.fftshift(dft)#将左上角放到中间
#得到灰度图能表现的形式
rows, cols = img.shape
crow, ccol = int(rows/2), int(cols/2) #中心位置
###低通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0##左30,右30,上下30分别置为1(除了中间是0,其余都是1)
#IDFT##傅里叶变化向原始图像中逆变换的过程
fshift = dft_shift * mask#将掩码与图像结合
f_ishift = np.fft.ifftshift(fshift)#将中间还回去
img_back = cv2.idft(f_ishift)#将中间还回去
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])##将实部和虚部进行处理
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'),plt.xticks([]),plt.yticks([])
plt.show()
低通,高通滤波结果


最后#
加油各位,that is all,thank you!