# 基于python的opencv项目实战笔记
链接:https://www.bilibili.com/video/BV1oJ411D71z?p=2
RGB图像有通道,比如2002003;黑白图没有颜色通道
cv2.IMREAD_COLOR:彩色图像
cv2.IMREAD_GRAYSCALE:灰色图像
import cv2 #opencv读取的格式是BGR
import matplotlib.pyplot as plt #读取图片的包
import numpy as np
%matplotlib inline
读取图片:img=cv2.imread('*cat.jpg*')
#图像显示,也可以创建多个床头
cv2.imshow('image'.img)
#显示图片的宽*高*通道
*img*.shape
#等待时间,毫秒级,0表示任意健终止
cv2.waitKey(1000)
cv2.destroyAllWindows()
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#读取灰度图
*img*=cv2.imread('*cat.jpg*',*cv2.IMREAD_GRAYSCALE)*
#保存
cv2.imwrite('*maycat.png*',img)
#格式 ;像素点个数 ;数据类型
type(img) ; img.size; img.dtype
# # 数据读取-视频
###cv2.VideoCapture可以捕获摄像头,用数字来控制不同的设备,例如0.1
###如果是视频文件,直接指定号路径即可
#检测是否打开正确
if vc.is Opened():
oepn,frame = vc.read()
#vc.read() 读取视频的帧数,oepn表示是否能读到,读到返回TRUE,否则FALSE,frame表示当前一帧的图像
else:
open = False
while open:
ret, frame = vc.read()
if frame is None:
break
#如果读frame不是空的话退出循环
if ret == True:
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
cv2.imshow('result',gray)
if cv2.waitKey(10) & 0xFF == 27:
#10表示图像的读取速度,越大就越满。&0xFF == 27表示推出键
break
vc.release()
cv2.destroyAllWindows()
###截取部分图像数据
img=cv2.imread('cat.jpg')
cat = img[0:50,0:200]
cv_show('cat',cat)
###颜色通道提取
b,g,r = cv2.split(img) #切分图像
img = cv2.merge((b,g,r))#合并数组
#只保留R
cur_img = img.copy()
cur_img[:,:,0] = 0
cur_img[:,:,1] = 0
cv_show('R',cur_img)
#只保留b
cur_img = img.copy()
cur_img[:, :, 0] = 0
cur_img[:, :, 1] = 0
cv_show('G', cur_img)
#只保留g
cur_img = img.copy()
cur_img[:, :, 0] = 0
cur_img[:, :, 2] = 0
cv_show('B', cur_img)
###边界填充
top_size, bottom_size, left_size, right_size = (50, 50, 50, 50)
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, borderType=cv2.BORDER_REFLECT) # 反射法:fedcba| abcdefgh| hgfedcb
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REFLECT_101) # 反射法:gfedcb| abcdefgh |gfedcba
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_WRAP) # 外包装法:cdefdh | abcdefg|abcdefg
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_CONSTANT, value=0) # 常量法
###相加
img_cat = cv2.imread('cat.jpg')
img_dog = cv2.imread('dog.jpg')
#img_cat2 = img_cat + 10
img_cat2 = img_cat + 10
img_cat2[:5, :, 0]
img_cat[:5, :, 0]
#维度一样才能相加,294>256(0-255),所以相当于%256,所以38;
(img_cat + img_cat2)[:5, :, 0]
#294>255,越界取255,不越取自身;
cv2.add(img_cat, img_cat2)[:5, :, 0]
###图像融合
#维度不同不能相加cat(414,500,3)dog(429,499,3)
img_cat.shape
img_dog = cv2.resize(img_dog, (500,414))
img_dog.shape
res = cv2.resize(img, (0, 0),fx=1.5, fy=1.5)
plt.imshow(res)
#融合:R=aX1 + bX2 +c a,b是关于X1,X2权重, C是偏置值
res = cv2.addWeighted(img_dog, 0.4, img_cat, 0.6, 0)
plt.imshow(res)u
img=cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imwrite('mycat.png',img)
img_gray = cv2.imread('mycat.png')
res,thresh1 = cv2.threshold(img_gray, 127, 255 ,cv2.THRESH_BINARY)
res,thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
res,thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
res,thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
res,thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
#plt.subplot(2,3,i+1) 表示 2行3列的矩阵,共6张图的第i+1个图
plt.xtick([]) 表示行坐标,plt.xtick也一样
titles = ['Original image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, 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 = cv2.imread('lenaNoise.png')
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#均值滤波
##简单的平均卷积操作
#(3,3)表示卷积核
blur = cv2.blur(img, (3,3))
cv2.imshow('blur',blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
#方框滤波 和 均值滤波基本相同
#基本和均值一样 可以选择归一化
#normalize = True 表示是否归一化
box = cv2.boxFilter(img, -1, (5,5), normalize=True)
cv2.imshow('box',box)
cv2.waitKey(0)
cv2.destroyAllWindows()
#高斯滤波
#高斯滤波的卷积核里的数值是满足高斯分布 相当于更加重视中间的
#越靠近中间越重要
auusian = cv2.GaussianBlur(img,(5,5),1)
cv2.imshow('auusian',auusian)
cv2.waitKey(0)
cv2.destroyAllWindows()
#中值滤波
#相当于用中值替代
median = cv2.medianBlur(img,5)
cv2.imshow('median',median)
cv2.waitKey(0)
cv2.destroyAllWindows()
#展示所有的
#vstack竖直拼接 hstack 水平拼接
res = np.hstack((blur,auusian,median))
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
img = cv2.imread('dige.png')
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#腐蚀
kernel = np.ones((3,3),dtype = np.uint8)
#图像 卷积核大小 腐蚀次数
erosion = cv2.erode(img,kernel,iterations=1)
cv2.imshow('erosion',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
#膨胀
img =cv2.imread('dige.png')
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
dilate = cv2.dilate(img,kernel,iterations=2)
cv2.imshow('dilate',dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
#开运算与闭运算
#开运算: 先腐蚀在膨胀
img = cv2.imread('pie.png')
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
cv2.imshow('opening',opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
#闭运算: 先膨胀在腐蚀
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel)
cv2.imshow('closing',closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
#梯度运算
#梯度 = 膨胀 - 腐蚀
img = cv2.imread('pie.png')
gradient = cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
cv2.imshow('gradient',gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()
###礼帽和黑帽
#礼帽:原始输入-开运算结果
#黑帽:闭运算-原始输入
#礼帽 把刺儿留下
img = cv2.imread('dige.png')
tophat = cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
cv2.imshow('tophat',tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()
#黑帽 剩下原始小轮廓 去掉刺儿
blackhat = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
cv2.imshow('blackhat',blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()
###图像梯度-Sobel算子
Gz[[-1, 0 , +1]
[-2 , 0 , +1]
[-1 , 0 , +1]]
Gy [[ -1 , -2, -1]
[0, 0 , 0]
[+1, +2, +1]]
G类似与卷积, Gz表示横向(从右向左) ,Gy表示纵向(从下向上)
dst = cv2.Sobel(sre , ddepth, dx, dy, ksize)
- ddepth:图像的深度
- dx dy水平竖直方向
- kszie Sobel算子的大小
-
#只显示一半的圆
img = cv2.imread('pie.png', cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
res = np.hstack((img, sobelx))
cv_show('res',res)
#白到黑是整数,黑到白就是负数, 所有的负数会被截断成0, 所以要取绝对值
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)#取绝对值,两边都会有
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobely = cv2.convertScaleAbs(sobely)
res = np.hstack((img, sobelx,sobely))
cv_show('res',res)
#分别计算x y 再求和
sobelxy = cv2.addWeighted(sobelx,0.5, sobely,0.5 , 0)
cv_show('sobelxy', sobelxy)
#不建议直接计算,有时会出现边界不清晰
sobelxy = cv2.Sobel(img, cv2.CV_64F, 1, 1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_show('sobelxy',sobelxy)
#图像梯度-Scharr算子
Gx = [[-3, 0, 3]
[-10, 0, 10]
[-3, 0, 3]]
Gy = [[-3, -10, -3]
[0, 0, 0]
[-3, -10, -3]]
#图像梯度-laplacian算子
G = [0, 1, 0]
[1, -4, 1]
[0, 1, 0]
#不同算子的差异
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(img, cv2.CV_64F, 0,1 , ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
scharrx = cv2.Scharr(img, cv2.CV_64F, 1, 0)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
laplacian = cv2.Laplacian(img, cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((img, sobelxy, scharrxy, laplacian))
cv_show('res', res)
###Canny边缘检测
cv2.Canny(img, minVal, maxVal)
img = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 100)#双阈值
res = np.hstack((v1, v2))
cv_show('res', res)
###高斯金字塔
2.使用先前同样的内核(乘以4)与放大后的图像卷积,获得近似值
(放大)[[10, 30]
[56, 96]]
放大后[[10, 0, 30, 0]
[0, 0, 0, 0]
[56, 0, 96, 0]
[0, 0, 0, 0]]
img = cv2.imread('AM.png')
a = cv_show('img', img)
up = cv2.pyrUp(img)#上采样
b = cv_show('up', up)
down = cv2.pyrDown(img)#下采样
c = cv_show('down',down)
print(img.shape)
print(up.shape)
print(down.shape)
###拉普拉斯金字塔
#- 图像=原始图像-(pyrUp(pyrDown(原始图像)))
down = cv2.pyrDown(img)
down_up = cv2.pyrUp(down)
i = img - down_up
res = np.hstack((i, img))
cv_show('res', res)
###图像轮廓 (轮廓不同于边缘,连接在一起的才叫轮廓)
####cv2.findContours(img, mode, method)
####mode: 轮廓检索模式
#将图片进行处理,转为灰度图
img = cv2.imread('car.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#转换为灰度图
img, result = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)#阈值处理
cv_show('result',result)
#binary就是二值图的结果,就是result , contours是轮廓的信息
binary, contours, hierarchy = cv2.findContours(result, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#检测函数
###绘制轮廓
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
#主要需要copy,因为函数实在原图像上进行轮廓绘制的
img = cv2.imread('car.png')
#draw_img = img.copy()
#(图片, 轮廓信息, 画第几个轮廓,(B,G,R), 线条宽度)
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show('res', res)
cv_show('img', img)
###轮廓特征
#检索第0个轮廓
cnt = contours[0]
#面积
cv2.contourArea(cnt)
#周长,True表示闭合的
cv2.arcLength(cnt, True)
###轮廓近似
img = cv2.imread('contours2.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
draw_img = img.copy()
res = cv2.drawdContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show('res', res)
#轮廓近似
epsilon = 0.1*cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 255, 0), 2)
cv_show('res', res)
###边界矩形
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[2]
draw_img
#矩阵左上点的坐标,w,h是矩阵的宽和高。
x, y, w, h = cv2.boundingRect(cnt)
#(x,y)是矩阵的左上点坐标,(x+w,y+h)是矩阵的右下点坐标,(0,255,0)是画线对应的rgb颜色,2是所画的线的宽度
img = cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv_show('img', img)
area = cv2.contourArea(cnt)
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h
#float() 函数用于将整数和字符串转换成浮点数
extent = float(area)/rect_area
print('轮廓面积与边界矩形比', extent)
#外接圆
(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_show('img', img)
###模板匹配
####模板匹配与卷积原理很像, 模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv有6种,然后将每次计算的结果放到一个矩阵里,作为结果输出。假设原图形是AxB大小, 而模板是axb大小,则输出的结果的矩阵是(A-a+1) * (B-b+1)
methods = [‘cv2.TM_CCOEFF’, ‘cv2.TM_CCOEFF_NORMED’, ‘cv2.TM_CCORR’,
‘cv2.TM_CCORR_NORMED’, ‘cv2.TM_SQDIFF’, ‘cv2.TM_SQDIFF_NORMED’]
img = cv2.imread(‘lena.jpg’, cv2.IMREAD_GRAYSCALE)
template = cv2.imread(‘face.jpg’, cv2.IMREAD_GRAYSCALE)
h, w = template.shape[:2]
methods = [‘cv2.TM_CCOEFF’, ‘cv2.TM_CCOEFF_NORMED’, ‘cv2.TM_CCORR’,
‘cv2.TM_CCORR_NORMED’, ‘cv2.TM_SQDIFF’, ‘cv2.TM_SQDIFF_NORMED’]
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF)
res.shape #输出矩阵的大小
#输出矩阵最小值,最大值,最小坐标位置,最大坐标位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
#一般用归一化方法 比较可靠
for meth in methods:
img2 = img.copy()
method = eval(meth)
print(method)
res = cv2.matchTemplate(img2, template, method)
min_val, max_val, min_loc, max_loc = minMaxLoc(res)
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:g_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', cv2.IMREAD_GRAYSCALE)
h, w = template[:2]
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)# 灰度图
result_img = ['res','img2']
titles = ['res', 'img2']
for i in range(2):
plt.subplot(1, 2, i+1)
plt.imshow(result_img[i], 'gray')
plt.title(titles[i])
plt.xtick([]) # 隐藏坐标轴
plt.ytick([]) # 隐藏坐标轴
plt.show()
###匹配多个对象
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', cv2.IMREAD_GRAYSCALE)
h, w = template[:2]
res = cv2.matchTemplate(img_gray, template,
cv2.TM_CCOEFF_NORMED)
threshold = 0.8
#取匹配程度大于0.8的坐标
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):
bottom_right = (pt[0]+w, pt[1]+h)
cv2.rectangle(img_rgb, pt, bottom_right, (0,0,255), 2)
cv_imshow('img_rgb',img_rgb)
###直方图
####cv2.calcHist(images,channels,mask,histSize,ranges)
img = cv2.imread('cat.jpg',0)
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
hist.shape
#shape 出现(256, 1);256指[0, 256], 二维
#img.ravel()是plt.hist 输入的数据集,.ravel将数组维度拉成一维数组
plt.hist(img.ravel(), 256)
plt.show()
img = cv2.imread('cat.jpg')
color = ('b', 'g', 'r')
#enumerate 序列检索,常用 for in enumerate(序列)
for i, col in enumerate(color):
histr = cv2.calcHist([img], [i], None, [256], [0, 256])
plt.plot(histr, color = col) #plt.plot画点线,color=cal 画笔的颜色
plt.xlim([0, 256]) #设置x轴的数值显示范围
plt.show()
#创建mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
cv_show('mask', mask)
masked_img = cv2.bitwise_and(img, img, mask=mask)
cv_show('masked_img', masked_img)
#有掩码与无掩码进行对比
histfull = cv2.calcHist([img], [0], None, [256], [0, 256])
histmask = cv2.calcHist([img], [0], mask, [256], [0, 256])
#plt.imshow()显示图像格式,最后plt.show()才是显示图像
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(histfull), plt.plot(histmask)
plt.xlim([0, 256])
plt.show()
####直方图均衡化
img = cv2.imread('cat.jpg', 0)
plt.hist(img.ravel(), 256)
plt.show()
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
plt.show()
res = np.hstack((img, equ))
cv_show('res', res)
#自适应直方图均衡化
#将分成8*8的小块,分别均衡化
cat = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
res_cat = cat.apply(img)
res = np.hstack((img, equ, res_cat))
cv_show('res', res)
###傅里叶变换
我们生活在时间的世界中,早上7:00起来吃早饭,8:00去挤地铁,9:00开始上班。。。以时间为参照就是时域分析。
但是在频域中一切都是静止的!
https://zhuanlan.zhihu.com/p/19763358
高频:变化剧烈的灰度分量,例如边界
低频:变化缓慢的灰度分量,例如一片大海
###滤波
低通滤波器:只保留低频,会使得图像模糊
高通滤波器:只保留高频,会使得图像细节增强
opencv中主要就是cv2.dft() 傅里叶变换和cv2.idft() 傅里叶逆变换,输入图像需要先转换成np.float32 格式。
得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能展示(0,255)。
img = cv2.imread('lena.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(1,2,1), plt.imshow(img,cmap = 'gray')
plt.title('input image'), plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2), plt.imshow(magnitude_spectrum, cmap='gray')
plt.title('magnitude spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
img = cv2.imread('lena.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
#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(1,2,1), plt.imshow(img, cmap = 'gray')
plt.title('input image'), plt.xticks([]), plt.yticks([])
plt.subplot(1,2,2), plt.imshow(img_back, cmap = 'gray')
plt.title('result'), plt.xticks([]), plt.yticks([])
plt.show()
img = cv2.imread('lena.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
#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()
####cv2.cornerHarris()
import cv2
import numpy as np
img = cv2.imread('test_1.jpg')
print ('img.shape:',img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
print ('dst.shape:',dst.shape)
img[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
img = cv2.imread('test_1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#查看opencv的版本
cv2.__version__ ##3.4.2.15 pip install opencv-python==3.4.2.15 pip install opencv-contrib-python==3.4.2.15
###得到特征点
sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)#得到关键点
#运用CV2中drawKeypoints 画出关键点
img = cv2.drawKeypoints(gray, kp, img)
cv2.imshow('drawKeypoint', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
###计算特征
kp, des = sift.compute(gray, kp)
print (np.array(kp).shape) #kp转换格式,显示gray图中共有6808个关键点
des.shape#6808个关键点转换成128维的向量
#查看des的向量
des[0]
####Brute-Force蛮力匹配
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img1 = cv2.imread('box.png', 0)
img2 = cv2.imread('box_in_scene.png', 0)
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv_show('img1', img1)
cv_show('img2', img2)
#SIFT函数计算特征和特征点
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
#crossCheck表示两个特征点要互相匹,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是
#NORM_L2: 归一化数组的(欧几里德距离),如果其他特征计算方法需要考虑不同的匹配计算方式,(这是默认的)
#蛮力匹配,若需要自己设置距离的话,加上参数
bf = cv2.BFMatcher(crossCheck=True)
####1对1的匹配,两两匹配
#特征向量进行蛮力匹配且排序
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x:x.distance)
#特征点进行连线
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags=2)
cv_show('img3', img3)
####k对最佳匹配
bf = cv2.BFMatcher()
#在bf上调属性的时候使用KNNMatch,这样可以调取K参数
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m, n in matches:
if m.distance < 0.75 * n.distance:
good.append([m])
img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, None, flags=2)
cv_show('img3', img3)
采用混合高斯模型法
混合高斯模型学习方法
1.首先初始化每个高斯模型矩阵参数。
2.取视频中T帧数据图像用来训练高斯混合模型。来了第一个像素之后用它来当做第一个高斯分布。
3.当后面来的像素值时,与前面已有的高斯的均值比较,如果该像素点的值与其模型均值差在3倍的方差内,则属于该分布,并对其进行参数更新。
4.如果下一次来的像素不满足当前高斯分布,用它来创建一个新的高斯分布。
混合高斯模型测试方法
在测试阶段,对新来像素点的值与混合高斯模型中的每一个均值进行比较,如果其差值在2倍的方差之间的话,则认为是背景,否则认为是前景。将前景赋值为255,背景赋值为0。这样就形成了一副前景二值图。
import numpy as np
import cv2
#读取测试视频
cap = cv2.VideoCapture('test.avi')
#形态学操作,核操作,MORPH_ELLIPSE表示椭圆结构
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
#创建混合高斯模型用于背景建模
fgbg = cv2.createBackgroundSubtractorMOG2()
#从视频的每一帧读到图像,应用到背景提取应用中,得到掩码;
#形态学变换为了去掉噪音点,对行人表框。
#ret, frame = cap.read()返回值含义:参数ret 为True 或者False,代表有没有读取到图片;第二个参数frame表示截取到一帧的图片
while(True):
ret, frame = cap.read()
fgmask = fgbg.apply(frame)
#形态学开运算(先腐蚀,在膨胀)去噪点
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
#寻找视频中的行人轮廓
im, contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
#计算各个轮廓的周长,cv2.arcLength(contours, True)
perimeter = cv2.arcLength(c, True)
if perimeter > 188:
#找出轮廓的相关参数(框的坐上点,与宽高)
x,y,w,h = cv2.boundingRect(c)
#画出矩形
cv2.rectangle(frame,(x,y), (x+w,y+h),(0,255,0),2)
cv2.imshow('frame', frame)
cv2.imshow('fgmask',fgmask)
k = cv2.waitKey(150)
if k == 27:
break
#停止视频与关闭窗口
cap.release()
cv2.destroyAllWindows()
###cv2.calcOpticalFlowPyrLK():
参数:
prevImage 前一帧图像
nextImage 当前帧图像
prevPts 待跟踪的特征点向量
winSize 搜索窗口的大小
maxLevel 最大的金字塔层数
返回:
nextPts 输出跟踪特征点向量(找到的角点)
status 特征点是否找到,找到的状态为1,未找到的状态为0
#ret, frame = cap.read()返回值含义:
参数ret 为True 或者False,代表有没有读取到图片
第二个参数frame表示截取到一帧的图片
##角点检测 corners=cv.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance[, corners[, mask[, blockSize[, useHarrisDetector[, k]]]]])
corners=cv.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, mask, blockSize, gradientSize[, corners[, useHarrisDetector[, k]]])
输入的参数分别是:
image: 输入图像,是八位的或者32位浮点型,单通道图像,所以有时候用灰度图
maxCorners: 返回最大的角点数,是最有可能的角点数,如果这个参数不大于0,那么表示没有角点数的限制。
qualityLevel: 图像角点的最小可接受参数,质量测量值乘以这个参数就是最小特征值,小于这个数的会被抛弃。
minDistance: 返回的角点之间最小的欧式距离。
mask: 检测区域。如果图像不是空的(它需要具有CV_8UC1类型和与图像相同的大小),它指定检测角的区域。
blockSize: 用于计算每个像素邻域上的导数协变矩阵的平均块的大小。
useHarrisDetector:选择是否采用Harris角点检测,默认是false.
k: Harris检测的自由参数。
W_update=np.zeros_like(W);
函数主要是想实现构造一个矩阵W_update,其维度与矩阵W一致,并为其初始化为全0;这个函数方便的构造了新矩阵,无需参数指定shape大小
cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) → img
img,背景图;
pt1,直线起点坐标;
pt2,直线终点坐标;
color,当前绘画的颜色。如在BGR模式下,传递(255,0,0)表示蓝色画笔。灰度图下,只需要传递亮度值即可。;
thickness,画笔的粗细,线宽。若是-1表示画封闭图像,如填充的圆。默认值是1.;
lineType,线条的类型,;
如8-connected类型、anti-aliased线条(反锯齿),默认情况下是8-connected样式ide,cv2.LINE_AA表示反锯齿线条,在曲线的时候视觉效果更佳。;
##numpy.random.randint(low, high=None, size=None, dtype=’l’)
输入:
low—–为最小值
high—-为最大值
size—–为数组维度大小
dtype—为数据类型,默认的数据类型是np.int。
返回值:
返回随机整数或整型数组,范围区间为[low,high),包含low,不包含high;
high没有填写时,默认生成随机数的范围是[0,low)
import numpy as np
import cv2
cap = cv2.VideoCapture('test.avi')
# 角点检测所需参数,使用字典类型创建参数
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7)
# lucas kanade参数
lk_params = dict( winSize = (15,15),
maxLevel = 2)
# 随机颜色条
color = np.random.randint(0,255,(100,3))
# 拿到第一帧图像
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# 返回所有检测特征点,需要输入图像,角点最大数量(效率),品质因子(特征值越大的越好,来筛选)
# 距离相当于这区间有比这个角点强的,就不要这个弱的了,
# 运用角点进行跟踪 ,(前一帧的角点);这是Harris更强大的函数goodFeaturesToTrack;
#https://blog.csdn.net/lida0013/article/details/90110863
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# 创建一个mask
mask = np.zeros_like(old_frame)
while(True):
ret,frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 需要传入前一帧和当前图像以及前一帧检测到的角点
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# st=1表示,st==1会返回Ture或Faluse的索引,只需要在p1中找到的特征点
good_new = p1[st==1]
good_old = p0[st==1]
# 绘制轨迹
for i,(new,old) in enumerate(zip(good_new,good_old)):
a,b = new.ravel() #ravel将多维数据转换成一维
c,d = old.ravel()
mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2) #color创建的时候是数组,tolist将数组或矩阵转换成列表
frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
img = cv2.add(frame,mask)
cv2.imshow('frame',img)
k = cv2.waitKey(150)
if k == 27:
break
# 更新,为了前一帧图像的更新;reshape保证这东西没有什么问题。
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()