【新手向】opencv学习,第一周:从读取图片到模板匹配

别无他用,主要是用来记录自己的学习过程。

一. 数据读取

  • 图片读取
cv2.imread():用于读取函数

@param_1  : filename Name of file to be loaded. # 文件地址
@param_2  :  flags Flag that can take values of cv::ImreadModes # 读取文件的方法

# 有三种选择
	cv2.IMREAD_COLOR : 加载彩色图片,这个参数默认,可以直接写 1
	cv2.IMREAD_GRAYSCALE : 以灰度模式加载图片,可以直接写 0 
	cv2.IMREAD_UNCHANGED : 包括alpha,可以直接写 -1
img = cv2.imread('path')  # path:为读取图片的地址,读取进来的格式为BGR
cv2.imshow('image',img)   # param_1 : 展示图片窗口名称,param_2 : 需要显示的图片 

# 在后面需要两句话,否则就会一直展示
cv2.waitKey(0)            # 这里0为任意按键,你也可以设置成你想要的按键
cv2.destroyAllWindows()   # 关闭所有窗口

# 读取一张图片,以灰度图的方式展示
img_gr = cv2.imread('jinnie.jpeg', cv2.IMREAD_GRAYSCALE)
  • 视频读取
vc = cv2.VideoCapture('file_path') # 输入文件地址
# 检查是否打开正确
open = vc.isOpened() # 会返回一个布尔值
while open:
    # 按帧读取视频,open 返回的是bool,frame为每一帧的图像,三维度矩阵,格式为BGR
    ret, frame = vc.read()
    # 如果读取到了空帧,就结束
    if frame is None:
        break
    # 正确打开
    if ret ==True:
        # 将每一帧图像都转换为灰度图:cv2.cvtColor(p1,p2), 是颜色空间转换函数,p1是需要转换的图片,p2是转换成何种格式
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('result', gray)
        #  这里的cv2.waitKey(10)里面的数值需要自己拿捏,给的少就是倍速,给的多就是慢放
        if cv2.waitKey(10) & 0xFF == 27:
            break
vc.release()
cv2.destroyAllWindows()
  • 图片保存
cv.imwrite(path,img) # 写入一张图片
  • 图片融合
IMG = cv2.addWeighted(img1, a1, img2, a2, b)
'''
a1 : img1 需要占的权重
a2 : img2 需要的权重
b  : 偏置量
就像 new_ph = a1*img1 + a2*img2 +b 
'''
  • 图片展示,窗口调节
方法一
'''
# 窗口大小不可以改变:
cv2.namedWindow("image",cv2.WINDOW_AUTOSIZE)

# 窗口大小自适应比例:
cv2.namedWindow("image",cv2.WINDOW_FREERATIO)

# 窗口大小保持比例:
cv2.namedWindow("image",cv2.WINDOW_KEEPRATIO) 

# 显示色彩变成暗色(好像没有什么用的样子,不能理解):
cv2.namedWindow('image',cv2.WINDOW_GUI_EXPANDED)

# 与cv2.imshow的关系
cv2.imshow(‘窗口标题’,image),如果前面没有cv2.namedWindow,就自动先执行一个cv2.namedWindow()
'''
cv2.nameWindow('filename', cv2.WINDOW_AUTOSIZE)

方法二:
'''
src:输入图像
dsize:输出图像的大小。如果该参数为 0,表示缩放之后的大小需要通过公式计算,dsize = Size(round(fx*src.cols),round(fy*src.rows))。其中 fx 与 fy 是图像 Width 方向和 Height 方向的缩放比例。
fx:Width 方向的缩放比例,如果是 0,按照 dsize * width/src.cols 计算
fy:Height 方向的缩放比例,如果是 0,按照 dsize * height/src.rows 计算
interpolation:插值算法类型,或者叫做插值方式,默认为双线性插值(5种插入方式)
	INTER_NEAREST:最近邻插值
	INTER_LINEAR:线性插值(默认)
	INTER_AREA:区域插值
	INTER_CUBIC:三次样条插值
	INTER_LANCZOS4:Lanczos 插值
'''
cv2.resize(img, None, fx=a, fy=b)
# threshold(源图片, 阈值, 填充色, 阈值类型)
# 该函数返回的第一个值就是输入的thresh值,第二个就是处理后的图像
ret, dst = cv2.threshold(src, thresh, maxval, type)
'''
param_1 : src : 输出图,只能输入单通道图像,一般为灰度图
param_2 : dst : 输出图
param_3 : thresh  : 阈值
param_4 : maxval  : 表示阈值类型
	cv2.THRESH_BINARY 超过阈值的像素设置为maxVal,不超过的设置为0
	cv2.THRESH_BINARY_INV 1的反转(不超过阈值的像素设置为maxVal,超过的设置为0)
	cv2.THRESH_TRUNC 超过阈值设为阈值
	cv2.THRESH_TOZERO 低于阀值设为0
	cv2.THRESH_TOZERO_INV (大于阀值设为0)
# 阈值
ret
'''
  • 图片处理
    -均值滤波(简单的平均卷积操作)
    输出图像的每一个像素是核窗口内输入图像对应像素的像素的平均值( 所有像素加权系数相等),其实说白了它就是归一化后的方框滤波
    均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。特别是椒盐噪声

    cv2.blur(照片名称,卷积核大小)
    cv2.blur(img, (3,3))
    

    -方框滤波
    通过卷积核去处理图像,使用了正则化的话,则结果与均值滤波相同

    box = cv2.boxFilter(img2, -1, (3,3), normalize =False)
    

    -高斯滤波
    高斯模糊的卷积核里的数值是满足高斯分布的,相当于更重视中间.

    img_gaussian = cv2.GaussianBlur(img, (卷积核), 1)
    

    -中值滤波
    中值滤波器是一种非线性滤波器,常用于消除图像中的椒盐噪声。与低通滤波不同的是,中值滤波有利于保留边缘的尖锐度,但它会洗去均匀介质区域中的纹理。

    cv2.medianBlur(img, ksize)
    

    -形态学_腐蚀_膨胀
    膨胀与腐蚀能实现多种多样的功能,主要如下:
    1、消除噪声
    2、分割(isolate)出独立的图像元素,在图像中连接(join)相邻的元素。
    3、寻找图像中的明显的极大值区域或极小值区域
    4、求出图像的梯度

    膨胀(详解看这里):

    kernel = np.ones((3, 3), np.uint8)
    erosion = cv2.erode(img, kernel, iterations = 1)
    # iterations: 次数
    

    腐蚀:

    dilate = cv2.dilate(erosion_xihuan_1, kernel, iterations =1)
    
  • 开运算和闭运算
    详解

     # 开:先腐蚀,再膨胀
     kernel = np.ones((3, 3), np.uint8)
     opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
     # 第二个参数可以有很多变化
     # 解释的很详细 
    
    # 闭:先膨胀,再腐蚀
    kernel = np.ones((3, 3), np.uint8)
    closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    
  • 梯度运算

    kernel = np.ones((3, 3), np.uint8)
    erosion_xihuan_1 = cv2.dilate(img, kernel, iterations = 5)
    erosion_xihuan_2 = cv2.erode(img, kernel, iterations = 5)
    error = erosion_xihuan_1-erosion_xihuan_2
    res = np.hstack((erosion_xihuan_1,erosion_xihuan_2,error))
    
  • 礼帽和黑帽

    • 礼帽 = 原始 - 开运算¶
    • 黑帽 = 闭运算 - 原始
        #礼帽
        kernel = np.ones((10,10), np.uint8) # 自己定义的核
        tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
        # 黑帽
        blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
    
  • 梯度运算—SOBEL算子—边缘检测

'''
Sobel算子算法的优点是计算简单,速度快。但是由于只采用了2个方向的模板,
只能检测水平和垂直方向的边缘,因此这种算法对于纹理较为复杂的图像,
其边缘检测效果就不是很理想。该算法认为:凡灰度新值大于或等于阈值的像素点时都是边缘点。
这种判断欠合理,会造成边缘点的误判,因为许多噪声点的灰度值也很大。
'''
sobelx = cv2.Sobel(img2, cv2.CV_64F, 1,0, ksize = 3)
sobely = cv2.Sobel(img2, cv2.CV_64F, 0,1, ksize = 3)
# CV_64FC1   64F代表每一个像素点元素占64位浮点数,通道数为1
# CV_64FC3   64F代表每一个像素点元素占64点×3个浮点数,通道数为3
'''
CV_ - this is just a prefix
64 -表示双精度
32 -表示单精度
F  - 浮点
Cx - 通道数,例如RGB就是三通道
'''
  • 其他算子
  • charr算子—强化边缘检测
    (两者差别比较)
    scharr算子实际上是sobel算子的优化,scharr算子在处理边缘时比sobel精度高一些。两种算子唯一的区别就是他们的卷积核不同,他们无论在计算时间还是复杂度都是一样的。
  • laplacian算子
lap = cv2.Laplacian(img, cv2.CV_64F)
# 原图减去Laplacian结果为加强对比度
v1 = cv2.Canny(img, 80, 150,L2gradient=True)
# 一共两个阈值
'''
80,150为两个阈值
低于阈值1的像素点会被认为不是边缘;
高于阈值2的像素点会被认为是边缘;
在阈值1和阈值2之间的像素点,若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘。
L2gradient: 是否使用更加精确的梯度计算方法,默认是False
'''
  • 图像金字塔

  • (详解)
    常见两类图像金字塔

    • 高斯金字塔 ( Gaussian pyramid): 用来向下/降采样,主要的图像金字塔
      # 上采样
      up = cv2.pyrUp(img)
      # 下采样
      down = cv2.pyrDown(img)
      '''
      但需要注意的是,PryUp和PryDown不是互逆的,即PryUp不是降采样的逆操作。
      这种情况下,图像首先在每个维度上扩大为原来的两倍,新增的行(偶数行)以0填充。
      然后给指定的滤波器进行卷积(实际上是一个在每个维度都扩大为原来两倍的过滤器)去估计“丢失”像素的近似值。
      PryDown( )是一个会丢失信息的函数。为了恢复原来更高的分辨率的图像,我们要获得由降采样操作丢失的信息,这些数据就和拉普拉斯金字塔有关系了。
      '''
      
    • 拉普拉斯金字塔(Laplacian pyramid): 用来从金字塔低层图像重建上层未采样图像,在数字图像处理中也即是预测残差,可以对图像进行最大程度的还原,配合高斯金字塔一起使用
    • 代码实现(详解)
      import cv2 as cv
      #高斯金字塔
      def pyramid_demo(image):
      	level = 3      #设置金字塔的层数为3
      	temp = image.copy()  #拷贝图像
          pyramid_images = []  #建立一个空列表
          for i in range(level):
              dst = cv.pyrDown(temp)   #先对图像进行高斯平滑,然后再进行降采样(将图像尺寸行和列方向缩减一半)
              pyramid_images.append(dst)  #在列表末尾添加新的对象
              cv.imshow("pyramid"+str(i+1), dst)
              temp = dst.copy()
          return pyramid_images
      #拉普拉斯金字塔
      def lapalian_demo(image):
          pyramid_images = pyramid_demo(image)    #做拉普拉斯金字塔必须用到高斯金字塔的结果
          level = len(pyramid_images)
          for i in range(level-1, -1, -1):
              if (i-1) < 0:
                  expand = cv.pyrUp(pyramid_images[i], dstsize = image.shape[:2])
                  lpls = cv.subtract(image, expand)
                  cv.imshow("lapalian_down_"+str(i+1), lpls)
              else:
                  expand = cv.pyrUp(pyramid_images[i], dstsize = pyramid_images[i-1].shape[:2])
                  lpls = cv.subtract(pyramid_images[i-1], expand)
                  cv.imshow("lapalian_down_"+str(i+1), lpls)
      src = cv.imread('F:/test.jpg')
      cv.namedWindow('input_image') #设置为WINDOW_NORMAL可以任意缩放
      cv.imshow('input_image', src)
      lapalian_demo(src)
      cv.waitKey(0)
      cv.destroyAllWindows()
      
  • 图像轮廓
    在这里插入图片描述

'''
cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。
'''
ret,thresh = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
countours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
draw_img = img.copy()
res = cv2.drawContours(draw_img, countours,-1, (142, 95, 43),2)
# 取出轮廓
cnt = countours[100]
# 计算面积
cv2.contourArea(cnt)
# 计算周长
# True 表示闭合
cv2.arcLength(cnt, True)
  • 轮廓近似
'''
drawContours,第二个参数是轮廓本身,在Python中是一个list;所以使用[cnt]
'''
# 将图片转变为灰度
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()
#  绘制出轮廓,2为线条粗细
res = cv2.drawContours(draw_img, [cnt], -1, (0,0,255),2)
  • 绘制边界矩形
	# 第一步图像转为灰度,找出轮廓
	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[4]
	# 第二步,绘制矩形
	x, y, w, h = cv2.boundingRect(cnt)
	img = cv2.rectangle(img,(x,y), (x+w,y+h), (0,255,0),2)
	area = cv2.contourArea(cnt)
	rect_area = w*h
	extent  = float(area) / rect_area
	# 轮廓面积与边界矩形比
  • 模板匹配
    在这里插入图片描述

    # 导入图片
    img = cv2.imread('./notebook/2.7/lena.jpg',0)
    # 导入模板
    template = cv2.imread('./notebook/2.7/face.jpg',0)
    h,w = template.shape[:2]
    

    原图:							![在这里插入图片描述](https://img-blog.csdnimg.cn/a25c28bb4d13459d9d27e7a1edaa8d40.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAeGlodWFuYWZlbmd4eA==,size_8,color_FFFFFF,t_70,g_se,x_16)模板图:![在这里插入图片描述](https://img-blog.csdnimg.cn/a2e1d37b8f724708850d123a9edc88cb.png)

    在这里插入图片描述

# cv2.matchTemplate()模板匹配函数,参数分别为,原图、模板图、损失函数
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
# 获取最大值,最小值,和他们的索引,方便于后面绘制矩形
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
methods = ['cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED',
           'cv2.TM_CCORR','cv2.TM_CCORR_NORMED',
           'cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
for meth in methods:
    img2 = img.copy()
    
    # 匹配方法的真值
    # eval() 函数用来执行一个字符串表达式,并返回表达式的值。
    method = eval(meth)
    res = cv2.matchTemplate(img2, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    
    # 如果是平方差匹配TM_SQDIFF或归一化平方擦汗匹配TM_SQDIFF_NORMAL,取最小值
    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()

在这里插入图片描述

  • 匹配多个对象:
img_rgb = cv2.imread('notebook/8/mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('notebook/8/mario_coin.jpg', 0)
h,w = template.shape[:2]

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于80%的坐标
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_show(img_rgb, 'img')

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xihuanafengxx

好累好累好累!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值