基于python的opencv项目实战笔记

# 基于python的opencv项目实战笔记

链接:https://www.bilibili.com/video/BV1oJ411D71z?p=2

0.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

0.3、图像阈值

  • ret, dst = cv2.threshold(src, thresh, maxval, type)
  • src:输入图,只能输入单通道图像, 通常来说是灰度图
  • dst:输出图
  • thresh:阈值 例127
  • maxval:当像素值超过了阈值(或者小于阈值,由type决定),所赋予的值;
  • type: 二值化操作的类型:
  • cv2.THRESH_BINARY 超过阈值部分取maxval,否则取0
  • cv2.THRESH_BINARY_INV 上述的反转 INV表示取反, 例max=255, a>127取255, INV的话,就是a<127 取255
  • cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
  • cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
  • cv2.THRESH_TOZERO_INV 上述的反转
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()

0.4、形态学处理

 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()

0.5、图像梯度处理

###图像梯度-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)

0.6、边缘检测

###Canny边缘检测

  • 1.使用高斯滤波器,以平滑图像,滤除噪声
  • 2.计算图像每个像素点的梯度强度和方向
  • 3.应用非极大值抑制,以消除边缘检测带来的杂散效应
  • 4.应用双阈值检测来确定真实和潜在的边缘
    梯度值>maxVal处理为边界;minVal<梯度
  • 5.通过抑制孤立的弱边缘最终完成边缘检测
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)

0.7、图像金字塔与轮廓检测

###高斯金字塔

  • 高斯金字塔下采样:将图像与高斯内核卷积,将所有的偶数行和列去除
  • 高斯金字塔上采样:1.将图像在每个方向扩大为原来的俩倍,新增的行和列以0填充
  •         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: 轮廓检索模式

  • RETR_EXTERNAL: 只检索最外面的轮廓
  • RETR_LIST: 检索所有的轮廓,并将其保存在一条链表当中
  • RETR_CCOMP: 检索所有的轮廓,并将他们组织为俩层:顶层是各部分的外部边界,第二层是空洞的边界
  • RETR_TREE: 检索所有的轮廓,并重构嵌套轮廓的整个层次
    ####method:轮廓逼近方法
  • CHAIN_APPROX_NONE: 以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)
  • CHAIN_APPROX_SIMPLE: 压缩水平的、垂直的和斜的部分,也就是:函数只保留他们的终点部分
    ###为了更高的准确率,使用二值图像
#将图片进行处理,转为灰度图
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)

  • TM_SQDIFF: 计算平方不同,计算出来的值越小,越相关
  • TM_CCORR: 计算相关性,计算出来的值越大,越相关
  • TM_CCOEFF: 计算相关系数,计算出来的越大,越相关
  • TM_SQDIFF_NORMED: 计算归一化平方不同,计算出来的值越接近0,越相关
  • TM_CCORR_NORMEND: 计算归一化相关性, 计算出来的值越接近1, 越相关
  • TM_CCOEFF_NORMED: 计算归一化相关系数, 计算出来的值越接近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)

0.8、直方图与傅里叶变换

###直方图
####cv2.calcHist(images,channels,mask,histSize,ranges)

  • images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]
  • channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果入图像是灰度图它的值就是 [0]如果是彩色图像 的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
  • mask: 掩模图像。统整幅图像的直方图就把它为 None。但是如 果你想统图像某一分的直方图的你就制作一个掩模图像并 使用它。
  • histSize:BIN(柱子) 的数目。也应用中括号括来
  • ranges: 像素值范围常为 [0,256]
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()  

11、图像特征harris角点检测

####cv2.cornerHarris()

  • img: 数据类型为 float32 的入图像
  • blockSize: 角点检测中指定区域的大小
  • ksize: Sobel求导中使用的窗口大小
  • k: 取值参数为 [0,04,0.06]
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()

12、图像特征opencv SIFT函数

  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]

13、特征匹配

####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)

14、背景建模

采用混合高斯模型法
混合高斯模型学习方法
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()

17、光流估计

###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()

你可能感兴趣的:(python,opencv)