opencv-python入门

目录

本文主要针对opencv的python版本进行记录

一、opencv的安装

由于opencv比较大,并且anaconda方便管理库,采用清华的镜像安装(好像清华镜像又能够使用了)
1.安装anaconda
2.打开anaconda prompt,添加清华镜像

onda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes

添加完成之后就开始安装opencv,我们可以通过下面的命令让环境自动选择opencv版本

conda install -c menpo opencv

之后就可以使用了

二、读取显示一张图片

读取一张图片并显示出来,代码如下:

import cv2 as cv
src = cv.imread('d:/shili.jpg',1)
cv.imshow("chuangkou", src)
cv.waitKey(0)
cv.destroyAllWindows()

1、参数说明,imread(),传入两个参数,第一个参数文件的路径,要是文件和图片在同一个路径,可以只用给出图片的名称就可以。第二个参数,图片的读取方式,0,灰度图像,1,彩色图像。
2、imshow(),同样两个参数,第一个参数,显示窗口的名称,第二个参数,要显示的图片。
3、cv2.nameWindows(‘image’, cv2.WINDOWS_NORMAL/WINDOW_AUTOSIZE)函数作用就是可以调整显示图片窗口的大小,里面可传入两个参数,一个是窗口的名称,另一个是正常或者自动调整的窗口
4、waitKey()与waitKey(0),都代表无限等待,waitKey函数的默认参数就是int delay = 0,故这俩形式本质是一样的,按下键盘的任意键就会关闭窗口。当里面的数字大于零时,会等待若干毫秒执行下面的步骤,用在视频中就会选择截取每一帧的图片,在imshow(),后面加上这个函数,表示图像一直显示,不然无法显示图片,同时他会返回按键的ascii码,他的使用我们可以通过代码来理解。

import cv2
img = cv2.imread('shili.jpg',1)
cv2.imshow('image',img)
k = cv2.waitKey(0)
if k == 27: # wait for ESC key to exit
    cv2.destroyAllWindows()
elif k == ord('s'): # wait for 's' key to save and exit
    cv2.imwrite('messigray.png',img)
    cv2.destroyAllWindows()

这个程序的表示的是在按下esc时候,直接关闭窗口,当按下esc时候,这个waitkey()函数返回的是27给k,执行退出。

三、打印图片的属性、另存为图片

代码如下

#coding:utf-8
import cv2
import numpy as np

#输出图片的属性
def get_image_info(image):
    print(type(image))  # 显示图片的类型,numpy数据类型
    """
    shape属性表示图像的大小,shape会返回tuple元组,
    第一个元素是矩阵行数,第二个列数,第三个通道数
    """
    print(image.shape)
    print(image.size)  # 图像大小
    print(image.dtype)  # 图像类型
    pixel_data = np.array(image)
    print(pixel_data)  # 图片矩阵

src = cv2.imread('shili.jpg', 1)
cv2.namedWindow('1', cv2.WINDOW_NORMAL)
cv2.imshow('1', src)
get_image_info(src)
cv2.imwrite('baocun2.png',src)
cv2.waitKey(0)
cv2.destroyAllWindows()

这个函数的输出如下图所示:

<class 'numpy.ndarray'>
(363, 552, 3)
601128
uint8
[[[ 87 125 129]
  [ 97 138 141]
  [ 90 131 134]
  ...
  [228 176 135]
  [ 14   5   0]
  [  0   2   2]]

 [[ 80 117 121]
  [ 96 134 138]
  [ 87 128 131]
  ...
  [228 176 135]
  [ 14   5   0]
  [  0   2   2]]

 [[108 143 147]
  [117 154 158]
  [100 138 142]
  ...
  [228 176 135]
  [ 14   5   0]
  [  0   2   2]]

 ...

 [[216 220 225]
  [216 220 225]
  [216 220 225]
  ...
  [196 209 217]
  [  0   0   4]
  [  0   0   3]]

 [[212 216 221]
  [213 217 222]
  [213 217 222]
  ...
  [198 211 219]
  [  0   3   7]
  [  0   0   3]]

 [[212 216 221]
  [212 216 221]
  [212 216 221]
  ...
  [194 207 215]
  [  0   0   4]
  [  0   0   3]]]

Process finished with exit code 0

看完这个记过知道啥意思了吧,最后图片的输出是三通道,每一列向量是一个通道,一共363行,552列。

四、调用摄像头或者打开视频文件

代码如下:

#coding:utf-8
# 打开摄像头,获取图片
import cv2
def video_demo():
    captuer = cv2.VideoCapture(0)  #打开摄像头,0代表的是设备id,如通有多个摄像头,可以设置其他数值
    while True:
        ret, frame = captuer.read()  #读取摄像头,他能返回两个参数
        frame = cv2.flip(frame, 1)  #0,上下翻转,1左右翻转
        cv2.imshow("video", frame)
        if cv2.waitKey(10) &0xFF == ord('q'):  #按q关闭摄像头
            break

video_demo()
cv2.destroyAllWindows()

其中ret, frame是读取视频返回的两个值,其中ret是布尔值,如果读取帧是正确的则返回True,如果文件读取到结尾,它的返回值就为False。frame就是每一帧的图像,是个三维矩阵。
cv2.flip(frame, 1),第二个参数主要有1,0,-1,代表水平翻转,垂直翻转,水平垂直翻转。

五、numpy操作数组输出图片

5.1读取一张图片,修改颜色通道,后输出
可以得到图像的行数,列数,通道数举证,对矩阵进行操作可改变图像像素。

# -*- coding=utf-8 -*-
import numpy as np
import cv2

#numpy数字操作
def access_pixles(image):
    print(image.shape)
    height = image.shape[0]
    width = image.shape[1]
    channel = image.shape[2]
    print("width : %s, height : %s, channel : %s" % (width, height, channel))
    for row in range(height):
        for col in range(width):
            for c in range(channel):
                pv = image[row, col, c]
                image[row, col, c] = 255 - pv
    cv2.imshow("修改后的照片", image)


src = cv2.imread("shili.jpg", 1)
cv2.imshow("原来", src)
t1 = cv2.getTickCount()
access_pixles(src)
t2 = cv2.getTickCount()

time = (t2-t1)*1000/cv2.getTickFrequency()
print("time: %s" % time)
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果

(363, 552, 3)
width : 552, height : 363, channel : 3
time: 1183.3025

输出结果可以看到要是改为英文就不会乱码,先这么凑合着看
我们一起来理解下代码
image[row, col, c],获取像素点值,image[row, col, c] = 255 - pv,像素取反

计算时间的有两个模块,一个是time,另一个是opencv自带的cv2.getTickCount(), getTickCount():用于返回从操作系统启动到当前所经的计时周期数,看名字也很好理解,get Tick Count(s)。
getTickFrequency():用于返回CPU的频率。get Tick Frequency。这里的单位是秒,也就是一秒内重复的次数,多少个周期每秒。

所以剩下的就很清晰了:
总次数/一秒内重复的次数 = 时间(s)
1000 *总次数/一秒内重复的次数= 时间(ms)

这个逻辑很清晰,没什么问题,但是这里有一个小坑,那就是C版本的cvGetTickFrequency()函数和C++版本的getTickFrequency()的单位不一样,前者以ms计算频率,后者以s为单位计算频率,所以如果使用C版本的cvGetTickFrequency()计算时间的话,应该是:
总次数/一秒内重复的次数1000 = 时间(ms)
总次数/一秒内重复的次数
1000000

5.2自定义一张多通道的图片

用到函数zeros和ones,代码如下

# coding :utf-8
import cv2
import numpy as np

def creat_image():
    img = np.zeros([400, 400, 3],np.uint8)  # zeros: double类零矩阵,创建400*400,3通道的矩阵图像,像素格式为nint8
    img[:, :, 0] = np.ones([400, 400])*255  # ones([400, 400])是创建一个400*400的全一矩阵,后面*255变为全部255的矩阵,并将这个矩阵的值赋值给img的第一维
    img[:, :, 1] = np.ones([400, 400])*255  #第二维全是255
    img[:, :, 2] = np.ones([400, 400])*255
    cv2.imshow('zizhipictuer', img)

creat_image()
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果是输出一张白色的图片,也可以单独使用ones函数,代码如下;

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
def create_image():
    img = np.ones([400, 400, 3], np.uint8)
    img[:, :, 0] = img[:, :, 0]*255
    img[:, :, 1] = img[:, :, 1]*255
    img[:, :, 2] = img[:, :, 2]*255
    cv.imshow("自制图片", img)
 
create_image()
cv.waitKey(0)
cv.destroyAllWindows()

5.3定义一张单通道图片

# coding = utf-8
import cv2
import numpy as np
def creat_image():
    img = np.ones([400, 400, 1], np.uint8)
    img = img*127
    cv2.imshow("dipicture", img)

creat_image()
cv2.waitKey(0)
cv2.destroyAllWindows()

5.4调用库函数来实现像素取反

# coding = utf-8
import cv2
import numpy as np

def inverse(image):
    dst = cv2.bitwise_not(image)
    cv2.imshow("qufan", dst)

src = cv2.imread('shili.jpg', 1)
cv2.namedWindow("yuanlai", cv2.WINDOW_NORMAL)
cv2.imshow('yuanlai', src)
t1 = cv2.getTickCount()
inverse(src)
t2 = cv2.getTickCount()
time = (t2-t1)*1000/cv2.getTickFrequency()
print("time: %s" % time)
cv2.waitKey(0)

调用库函数bitwise_not 速度非常快

六 色彩空间转换

6.1调用转换函数实现图像色彩空间的转换,代码如下

# coding = utf-8
import cv2

#色彩空间的转换
def color_space_demo(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    cv2.imshow("gray", gray)
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    cv2.imshow('hsv', hsv)
    yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV)
    cv2.imshow("yuv", yuv)

src = cv2.imread('shili.jpg')
cv2.namedWindow('yuanlai', cv2.WINDOW_NORMAL)
cv2.imshow('yuanllai', src)
color_space_demo(src)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果如下
在这里插入图片描述HSV色彩空间说明
H:0-180
S:0-255
V:0-255

6.2 色彩空间转换,利用inrange函数过滤视频中的颜色,实现跟踪某一颜色

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
def nextrace_object_demo():
    capture = cv.VideoCapture("G:/1.mp4")#导入视频
    while True:
        ret, frame = capture.read()
        if ret == False:
            break
        hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)#转换色彩空间为hsv
        #设置白色的范围,跟踪视频中的白色
        lower_hsv = np.array([0, 0, 221])#设置过滤的颜色的低值
        upper_hsv = np.array([180, 30, 255])#设置过滤的颜色的高值
        mask = cv.inRange(hsv, lower_hsv, upper_hsv)#调节图像颜色信息(H)、饱和度(S)、亮度(V)区间,选择白色区域
        cv.imshow("video", frame)
        cv.imshow("mask", mask)
        if cv.waitKey(50) & 0xFF == ord('q'):
            break
 
nextrace_object_demo()
cv.waitKey(0)
cv.destroyAllWindows()

可以通过下表对应的颜色的数值过滤其他颜色
HSV对应RGB的分量范围;

在这里插入图片描述

6.3 通道分离,合并,修改某一通道

涉及函数:
split()将彩色图像分割成3个通道
merge()通道合并

#coding = utf-8
import cv2
import numpy as np

src = cv2.imread('shili.jpg')
cv2.namedWindow('yuanlai', cv2.WINDOW_NORMAL)
cv2.imshow('yuanlai',src)

#通道分离,输出三个单通道图片
b, g, r = cv2.split(src)  #将彩色图像分割成3个通道
cv2.imshow('blue', b)
cv2.imshow('green', g)
cv2.imshow('red', r)

#通道合并
src = cv2.merge([b, g, r])
cv2.imshow('hebing', src)
#修改某个通道的值
src[:, :, 2] = 100
cv2.imshow('dantngdao', src)
cv2.waitKey(0)
cv2.destroyAllWindows()

七 图片色素的数值运算

7.1opencv自带图片色素的处理函数:

相加: add()
相减: subtract()
相乘: divide()
相除: multiply()
原理就是通过获取两张(一次只能获取两张图片)图片的同一位置的色素值来实现运算。
运算要求:两张图片的shape要求一致

# coding = utf-8
import cv2
import numpy as np

#数值的运算
def shu_image(src11, src22):
    src = cv2.add(src11, src22)
    cv2.imshow('add', src)
    src = cv2.subtract(src11, src22)
    cv2.imshow('sub', src)
    src = cv2.divide(src11, src22)
    cv2.imshow('div', src)
    src = cv2.multiply(src11, src22)
    cv2.imshow('mul',src)

src1 = cv2.imread('1.jpg')
src2 = cv2.imread('2.jpg')
cv2.imshow('yuanlai1', src1)
cv2.imshow('yuanlai2', src2)
shu_image(src1, src2)
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如图
在这里插入图片描述

7.2 逻辑运算

opencv自带图片色素的处理函数
与: bitwise_add()
或: bitwise_or()
非: bitwise_not()
异或: bitwise_xor()
代码如下:

# coding = utf-8
import cv2
def luo_image(src11, src22):
    src = cv2.bitwise_not(src11)  # 对一张图片取反操作
    cv2.imshow('not', src)
    src = cv2.bitwise_and(src11, src22)  #两张图片同一位置的像素都不为0时才有输出
    cv2.imshow('and', src)
    src = cv2.bitwise_or(src11, src22)  # 两张图片同一位置的像素不同时为0时有输出
    cv2.imshow('or', src)
    src = cv2.bitwise_xor(src11, src22)  # 两张图片同一位置的像素一个为0,另一个不为0时才有输出
    cv2.imshow('xor', src)

src1 = cv2.imread('1.jpg')
src2 = cv2.imread('2.jpg')
cv2.imshow('yuanlai1', src1)
cv2.imshow('yuanlai2', src2)
luo_image(src1, src2)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

八 粗略调整图片对比度和亮度

基本原理:两张图片合成
先按照原来的图片的格式新建一个色素全为零的图片,然后按照两张图的比例不同合成一张新图片,用到的有addWeighted函数,代码如下:

# coding = utf-8
import cv2
import numpy as np

#粗略的调节对比度和亮度
def contrast_brightness_image(src1, a, g):
    h, w, ch = src1.shape  # 获取shape的数值

    #新建全零的图片数组,h,w,ch和原来图片一样(色素全为0,输出为0)
    src2 = np.zeros([h, w, ch], src1.dtype)
    dst = cv2.addWeighted(src1, a, src2, 1-a, g)
    cv2.imshow('con_demo', dst)

src = cv2.imread('shili.jpg')
cv2.imshow('yuanlai', src)
contrast_brightness_image(src, 1.2, 10)  # 第一个1.2为对比度, 第二个为亮度,数值越大越亮
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
addWeighted函数:官方:计算两个图像阵列的加权和 我的理解是按照所占比例合成两张图片。

addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);

一共有七个参数:前4个是两张要合成的图片及它们所占比例,第5个double gamma起微调作用,第6个OutputArray dst是合成后的图片,第七个输出的图片的类型(可选参数,默认-1)

有公式得出两个图片加成输出的图片为:dst=src1alpha+src2beta+gamma

九 图片的切割、合并、填充

图片的切割与合并
原理通过操作图像矩阵来获取或合并指定图像的位置
代码如下:

# coding = utf-8
import cv2
import numpy as np

#截取图片中的指定区域或在指定区域添加某一张图片
def cut_image(src1):
    src2 = src1[5:89, 300:430]  #截取第5行到89行和500列到630列
    cv2.imshow('cut', src2)
    src1[105:189, 200:330] = src2  #指定位置填充,要大小一致才能填充
    cv2.imshow('tianchong', src1)

src = cv2.imread('shili.jpg')
cv2.imshow('yuanlai', src)
cut_image(src)

输出结果如下:
在这里插入图片描述

十 floodFill填充函数

指定颜色填充,代码如下

# coding = utf-8
import cv2
import numpy as np
#指定颜色替换
def fill_image(image):
    copyImage = image.copy()  #复制原图像
    h, w = image.shape[:2]
    mask = np.zeros([h+2, w+2], np.uint8)  #新建图像矩阵,+2是官方函数要求
    cv2.floodFill(copyImage, mask, (0, 80), (0, 100, 255), (100, 100, 50), (50, 50, 50), cv2.FLOODFILL_FIXED_RANGE)
    cv2.imshow('tianchong', copyImage)

src = cv2.imread('shili.jpg')
cv2.imshow('yuanlai', src)
fill_image(src)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
说明如下:

floodFill函数:漫水填充算法:我觉得叫颜色替换好一些

官方定义为:floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )

不知道为啥,python中调用这个函数,Rect* rect=0这个参数没有,剩下7个参数

通俗解释:floodFill( 1.操作的图像, 2.掩模, 3.起始像素值,4.填充的颜色, 5.填充颜色的低值, 6.填充颜色的高值 ,7.填充的方法)

视频讲解如下:

参数5.填充颜色的低值就是:参数3 处像数值减去 参数5

参数6.填充颜色的高值就是:参数3处的像素值 加上 参数6

即是这两个数值之间的色素替换为参数4的颜色

7.填充的方法

彩色图像一般是FLOODFILL_FIXED_RANGE 指定颜色填充

还有一种是FLOODFILL_MASK_ONLY,mask的指定的位置为零时才填充,不为零不填充
函数的另一种理解:漫水填充说明

十一 利用卷积对图像模糊处理

看了许多资料,在图像上个人觉得卷积就是:对于某一位置的像素,通过算法来把它附近的所有像素点的值联合起来,重新设置这个像素的大小。(大概就是这样)

这个算法类似有:均值,中值,就是取周围所有像素的均值、中值来设置这个像素的大小。

(关于边界问题:有几种填充方法:补零、边界复制、块复制、镜像复制等方法)

一、调用函数实现模糊

代码如下:


# -*- coding=GBK -*-
# -*- coding=utf-8 -*-
import cv2 as cv


def mo_image(src1):
    src2 = cv.blur(src1, (5, 5))
    cv.imshow("junzhi", src2)


    src2 = cv.medianBlur(src1, 5)
    cv.imshow("zhongzhi", src2)


    src2 = cv.GaussianBlur(src1, (5, 5), 2)
    cv.imshow("gaosi", src2)


    src2 = cv.bilateralFilter(src1, 5, 5, 2)
    cv.imshow("shuangbianlvbo", src2)

src = cv.imread("shili.jpg")
cv.namedWindow("yuanlai", cv.WINDOW_NORMAL)
cv.imshow("yuanlai", src)
mo_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

输出
1.均值模糊函数blur():定义:blur(src,ksize,dst=None, anchor=None, borderType=None)

定义是有5个参数,但最后三个均为none,所以也就2个参数

src:要处理的原图像

ksize: 周围关联的像素的范围:代码中(5,5)就是5*5的大小,就是计算这些范围内的均值来确定中心位置的大小

2.中值模糊函数medianBlur(): 定义:medianBlur(src, ksize, dst=None)

ksize与blur()函数不同,不是矩阵,而是一个数字,例如为5,就表示了5*5的方阵

3.高斯平滑函数GaussianBlur():定义:GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)

sigmaX:标准差

4.双边滤波函数bilateralFilter():定义:bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
d:邻域直径
sigmaColor:颜色标准差
sigmaSpace:空间标准差

十二、图像直方图

# -*- coding=GBK -*-
import cv2 as cv
from matplotlib import pyplot as plt


# 画出图像的直方图
def hist_image(image):
    color = ("blue", "green", "red")
    for i, color in enumerate(color):
        hist = cv.calcHist([image], [i], None, [256], [0, 256])
        plt.plot(hist, color=color)
        plt.xlim([0, 256])
    plt.show()


src = cv.imread("shili.jpg")
cv.namedWindow("原来", cv.WINDOW_NORMAL)
cv.imshow("yuanlai", src)
hist_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

输出结果 直方图
1.numpy的ravel函数功能是将多维数组降为一维数组。参考博客:https://blog.csdn.net/lanchunhui/article/details/50354978

2.matplotlib.pyplot.hist函数主要是计算直方图。

hist函数原型:hist(x, bins=None, range=None, density=None, weights=None, cumulative=False, bottom=None, histtype=‘bar’, align=‘mid’, orientation=‘vertical’, rwidth=None, log=False, color=None, label=None, stacked=False, normed=None, hold=None, data=None, **kwargs)

x参数表示是一个数组或一个序列,是指定每个bin(箱子)分布的数据

bins参数表示指定bin(箱子)的个数,也就是总共有几条条状图

range参数表示箱子的下限和上限。即横坐标显示的范围,范围之外的将被舍弃。

参考博客:https://blog.csdn.net/u013571243/article/details/48998619

3.enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据下标和数据,一般用在 for 循环当中。

4.cv2.calcHist的原型为:calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist

images参数表示输入图像,传入时应该用中括号[ ]括起来

channels参数表示传入图像的通道,如果是灰度图像,那就不用说了,只有一个通道,值为0,如果是彩色图像(有3个通道),那么值为0,1,2,中选择一个,对应着BGR各个通道。这个值也得用[ ]传入。

mask参数表示掩膜图像。如果统计整幅图,那么为None。主要是如果要统计部分图的直方图,就得构造相应的掩膜来计算。

histSize参数表示灰度级的个数,需要中括号,比如[256]

ranges参数表示像素值的范围,通常[0,256]。此外,假如channels为[0,1],ranges为[0,256,0,180],则代表0通道范围是0-256,1通道范围0-180。

hist参数表示计算出来的直方图。

参考:https://blog.csdn.net/YZXnuaa/article/details/79231817

5.关于pyplot模块里plot()函数、xlim()函数等的用法参考:

https://blog.csdn.net/cymy001/article/details/78344316

https://blog.csdn.net/chinwuforwork/article/details/51786967

二、直方图应用

直方图均衡化:提升对比度的两种方法:默认、自定义

# -*- coding=GBK -*-
import cv2 as cv
from matplotlib import pyplot as plt
 
 
#提升对比度(默认提升),只能是灰度图像
def equalHist_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    cv.imshow("原来", gray)#因为只能处理灰度图像,所以输出原图的灰度图像用于对比
    dst = cv.equalizeHist(gray)
    cv.imshow("默认处理", dst)
 
 
#对比度限制(自定义提示参数)
def clahe_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(4, 4))#clipLimit是对比度的大小,tileGridSize是每次处理块的大小
    dst = clahe.apply(gray)
    cv.imshow("自定义处理", dst)
 
src = cv.imread("C://1.jpg")
equalHist_image(src)
clahe_image(src)
cv.waitKey(0)
cv.destroyAllWindows() 

在这里插入图片描述

十三 模板匹配

模板匹配:通俗讲就是以图找图,通过图中的一部分来找它在图中的位置

通过三种方式来匹配:cv.TM_SQDIFF_NORMED, cv.TM_CCORR_NORMED, cv.TM_CCOEFF_NORMED

代码如下:

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
#模版匹配
def template_image():
    tpl = cv.imread("C://2.jpg")
    target = cv.imread("C://1.jpg")
    cv.imshow("模板", tpl)
    cv.imshow("原图", target)
    methods = [cv.TM_SQDIFF_NORMED, cv.TM_CCORR_NORMED, cv.TM_CCOEFF_NORMED]
    th, tw = tpl.shape[:2]
    for md in methods:
        print(md)
        result = cv.matchTemplate(target, tpl, md)
        min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
        if md == cv.TM_SQDIFF_NORMED:
            tl = min_loc
        else:
            tl = max_loc
        br = (tl[0]+tw, tl[1]+th)
        cv.rectangle(target, tl, br, (0, 0, 255), 2)
        cv.imshow("匹配"+np.str(md), target)
 
 
template_image()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述
在这里插入图片描述

十四 图像二值化

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
#图像二值化 0白色 1黑色
#全局阈值
def threshold_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    cv.imshow("原来", gray)
 
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)#大律法,全局自适应阈值 参数0可改为任意数字但不起作用
    print("阈值:%s" % ret)
    cv.imshow("OTSU", binary)
 
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)#TRIANGLE法,,全局自适应阈值, 参数0可改为任意数字但不起作用,适用于单个波峰
    print("阈值:%s" % ret)
    cv.imshow("TRIANGLE", binary)
 
    ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY)# 自定义阈值为150,大于150的是白色 小于的是黑色
    print("阈值:%s" % ret)
    cv.imshow("自定义", binary)
 
    ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_BINARY_INV)# 自定义阈值为150,大于150的是黑色 小于的是白色
    print("阈值:%s" % ret)
    cv.imshow("自定义反色", binary)
 
    ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_TRUNC)# 截断 大于150的是改为150  小于150的保留
    print("阈值:%s" % ret)
    cv.imshow("截断1", binary)
 
    ret, binary = cv.threshold(gray, 150, 255, cv.THRESH_TOZERO)# 截断 小于150的是改为150  大于150的保留
    print("阈值:%s" % ret)
    cv.imshow("截断2", binary)
 
src = cv.imread("C://1.jpg")
threshold_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

函数threshold()的参数说明:

cv.THRESH_BINARY | cv.THRESH_OTSU)#大律法,全局自适应阈值 参数0可改为任意数字但不起作用
cv.THRESH_BINARY | cv.THRESH_TRIANGLE)#TRIANGLE法,,全局自适应阈值, 参数0可改为任意数字但不起作用,适用于单个波峰
cv.THRESH_BINARY)# 自定义阈值为150,大于150的是白色 小于的是黑色
cv.THRESH_BINARY_INV)# 自定义阈值为150,大于150的是黑色 小于的是白色
cv.THRESH_TRUNC)# 截断 大于150的是改为150  小于150的保留

cv.THRESH_TOZERO)# 截断 小于150的是改为150  大于150的保留

14.2局部阈值

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
#求出图像均值作为阈值来二值化
def custom_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    cv.imshow("原来", gray)
    h, w = gray.shape[:2]
    m = np.reshape(gray, [1, w*h])#化为一维数组
    mean = m.sum() / (w*h)
    print("mean: ", mean)
    ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
    cv.imshow("二值", binary)
 
 
src = cv.imread("C://1.jpg")
custom_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

14.3自己求图像平均阈值

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
#求出图像均值作为阈值来二值化
def custom_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    cv.imshow("原来", gray)
    h, w = gray.shape[:2]
    m = np.reshape(gray, [1, w*h])#化为一维数组
    mean = m.sum() / (w*h)
    print("mean: ", mean)
    ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
    cv.imshow("二值", binary)
 
 
src = cv.imread("C://1.jpg")
custom_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

十五 高斯金字塔和拉普拉斯金字塔

要求:拉普拉斯金字塔时,图像大小必须是2的n次方*2的n次方,不然会报错

# -*- coding=GBK -*-
import cv2 as cv
 
 
#高斯金字塔
def pyramid_image(image):
    level = 3#金字塔的层数
    temp = image.copy()#拷贝图像
    pyramid_images = []
    for i in range(level):
        dst = cv.pyrDown(temp)
        pyramid_images.append(dst)
        cv.imshow("高斯金字塔"+str(i), dst)
        temp = dst.copy()
    return pyramid_images
 
 
#拉普拉斯金字塔
def laplian_image(image):
    pyramid_images = pyramid_image(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("拉普拉斯"+str(i), 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("拉普拉斯"+str(i), lpls)
 
src = cv.imread("C://01.jpg")
cv.imshow("原来", src)
laplian_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

十六 图像梯度

一、索贝尔算子

# -*- coding=GBK -*-
import cv2 as cv
 
 
#图像梯度:索贝尔算子
def sobel_image(image):
    grad_x = cv.Sobel(image, cv.CV_32F, 1, 0)#x方向导数
    grad_y = cv.Sobel(image, cv.CV_32F, 0, 1)#y方向导数
    gradx = cv.convertScaleAbs(grad_x)
    grady = cv.convertScaleAbs(grad_y)
    cv.imshow("X方向", gradx)#颜色变化在水平分层
    cv.imshow("Y方向", grady)#颜色变化在垂直分层
    gradxy = cv.addWeighted(gradx, 0.5, grady, 0.5, 0)
    cv.imshow("合成", gradxy)
 
src = cv.imread("C://1.jpg")
cv.imshow("原来", src)
sobel_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

scharr算子

#图像梯度:scharr算子:增强边缘
def scharr_image(image):
    grad_x = cv.Scharr(image, cv.CV_32F, 1, 0)#x方向导数
    grad_y = cv.Scharr(image, cv.CV_32F, 0, 1)#y方向导数
    gradx = cv.convertScaleAbs(grad_x)
    grady = cv.convertScaleAbs(grad_y)
    cv.imshow("X方向", gradx)#颜色变化在水平分层
    cv.imshow("Y方向", grady)#颜色变化在垂直分层
    gradxy = cv.addWeighted(gradx, 0.5, grady, 0.5, 0)
    cv.imshow("合成", gradxy)

在这里插入图片描述

拉普拉斯算子

#拉普拉斯算子
def lapalian_image(image):
    dst = cv.Laplacian(image, cv.CV_32F)
    lpls = cv.convertScaleAbs(dst)
    cv.imshow("拉普拉斯", lpls)

在这里插入图片描述

十七 Canny边缘检测算法

# -*- coding=GBK -*-
import cv2 as cv
 
 
#边缘检测述算法
def edge_image(image):
    blurred = cv.GaussianBlur(image, (3, 3), 0)
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    xgrad = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
    ygrad = cv.Sobel(gray, cv.CV_16SC1, 0, 1)
    edge_output = cv.Canny(xgrad, ygrad, 50, 150)
    cv.imshow("canny边缘", edge_output)
    dst = cv.bitwise_and(image, image, mask=edge_output)
    cv.imshow("color边缘", dst)
 
src = cv.imread("C://1.jpg")
cv.imshow("原来", src)
edge_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

十八 直线检测

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
#霍夫直线检测
def line_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 50, 150, apertureSize=3)
    lines = cv.HoughLines(edges, 1, np.pi/180, 200)
    for line in lines:
        rho, theta = line[0]
        a = np.cos(theta)
        b = np.sin(theta)
        x0 = a * rho
        y0 = b * rho
        x1 = int(x0+1000*(-b))
        y1 = int(y0+1000*(a))
        x2 = int(x0-1000*(-b))
        y2 = int(y0-1000*(a))
        cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
    cv.imshow("直线", image)
 
 
src = cv.imread("C://01.png")
cv.imshow("原来", src)
line_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

十九 圆检测

-- coding=GBK --

import cv2 as cv
import numpy as np

#圆检测
def circles_image(image):
dst = cv.pyrMeanShiftFiltering(image, 10, 100)
cimage = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
circles = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)
cv.circle(image, (i[0], i[1]), 2, (255, 0, 255), 2)
cv.imshow(“圆形”, image)

src = cv.imread(“C://04.jpg”)
cv.imshow(“原来”, src)
circles_image(src)
cv.waitKey(0)
cv.destroyAllWindows()
在这里插入图片描述

二十 轮廓发现

# -*- coding=GBK -*-
import cv2 as cv
import numpy as np
 
 
#轮廓发现
def contous_image(image):
    dst = cv.GaussianBlur(image, (3, 3), 0)
    gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow("二值化", binary)
    cloneImage, contous, heriachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    for i,contou in enumerate(contous):
        cv.drawContours(image, contous, i, (0, 0, 255), 1)
    cv.imshow("轮廓", image)
    for i,contou in enumerate(contous):
        cv.drawContours(image, contous, i, (0, 0, 255), -1)
    cv.imshow("轮廓覆盖", image)
 
 
src = cv.imread("D://1.jpg")
cv.imshow("原来", src)
contous_image(src)
cv.waitKey(0)
cv.destroyAllWindows() 

在这里插入图片描述

二十一 图像的开闭操作

作用:删除图像的小的干扰项

# -*- coding=GBK -*-
import cv2 as cv
 
 
#图像的开闭操作
def open_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow("二值化", binary)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
    binary = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)
    cv.imshow("开操作", binary)
 
 
def close_image(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
    binary = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel)
    cv.imshow("闭操作", binary)
 
 
src = cv.imread("C://1.jpg")
cv.imshow("原来", src)
open_image(src)
close_image(src)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

二十二 分水岭分割算法

分水岭分割流程:图像->灰度->二值->距离变换->寻找种子->生成Marker->分水岭变换->输出

# -*- coding=GBK -*-
import cv2 as cv
import  numpy as np
 
 
# 分水岭算法
def water_image():
    print(src.shape)
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)    # 去除噪点
 
    # gray\binary image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow("二值图像", binary)
 
    # morphology operation
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
    mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)
    sure_bg = cv.dilate(mb, kernel, iterations=3)
    cv.imshow("形态操作", sure_bg)
 
    # distance transform
    dist = cv.distanceTransform(mb, cv.DIST_L2, 3)
    dist_output = cv.normalize(dist, 0, 1.0, cv.NORM_MINMAX)
    cv.imshow("距离变换", dist_output*70)
 
    ret, surface = cv.threshold(dist, dist.max()*0.6, 255, cv.THRESH_BINARY)
    cv.imshow("寻找种子", surface)
 
    surface_fg = np.uint8(surface)
    unknown = cv.subtract(sure_bg, surface_fg)
    ret, markers = cv.connectedComponents(surface_fg)
    print(ret)
 
    # watershed transfrom
    markers += 1
    markers[unknown == 255] = 0
    markers = cv.watershed(src, markers=markers)
    src[markers == -1] = [0, 0, 255]
    cv.imshow("分水岭结果", src)
 
src = cv.imread("C://02.png")
cv.imshow("原来", src)
water_image()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

二十三 人脸检测

这里需要使用haarcascade_frontalface_alt_tree.xml,可以自行百度

# -*- coding=GBK -*-
import cv2 as cv
 
 
# 人脸检测
def face_image():
  gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
  face_detector = cv.CascadeClassifier("haarcascade_frontalface_alt_tree.xml")
  faces = face_detector.detectMultiScale(gray, 1.02, 5)   # 第二个参数是移动距离,第三个参数是识别度,越大识别读越高
  for x, y, w, h in faces:
    cv.rectangle(src, (x, y), (x+w, y+h), (0, 0, 255), 2)   # 后两个参数,一个是颜色,一个是边框宽度
  cv.imshow("结果", src)
 
 
src = cv.imread("C://4.jpg")
cv.imshow("原来", src)
face_image()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

视频中人脸检测

# -*- coding=GBK -*-
import cv2 as cv
 
 
# 摄像头人脸检测
def face_image(src):
  gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
  face_detector = cv.CascadeClassifier("haarcascade_frontalface_alt_tree.xml")
  faces = face_detector.detectMultiScale(gray, 1.02, 5)   # 第二个参数是移动距离,第三个参数是识别度,越大识别读越高
  for x, y, w, h in faces:
    cv.rectangle(src, (x, y), (x+w, y+h), (0, 0, 255), 2)   # 后两个参数,一个是颜色,一个是边框宽度
  cv.imshow("结果", src)
 
 
capture = cv.VideoCapture(0)
while(True):
    ret, frame = capture.read()
    frame = cv.flip(frame, 1)
    face_image(frame)
    if cv.waitKey(10) & 0xFF == ord('q'):    # 键盘输入q退出窗口,不按q点击关闭会一直关不掉 也可以设置成其他键。
            break
face_image()
cv.waitKey(0)
cv.destroyAllWindows() 

视频中人脸检测还可以

二十四 识别验证码

验证码识别前期准备:

1.安装:tesseract-oc,直接安装就行,要配环境,下载地址点这里

参考资料:点这里,再说一下,实测一定要配环境!!!

2.安装pytesseract:pip install pytesseract

# -*- coding=GBK -*-
import cv2 as cv
import Image
import pytesseract
 
 
def recognize_text():
    gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 6))
    binl = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 1))
    open_out = cv.morphologyEx(binl, cv.MORPH_OPEN, kernel)
    cv.bitwise_not(open_out, open_out)  # 背景变为白色
    cv.imshow("转换", open_out)
    textImage = Image.fromarray(open_out)
    text = pytesseract.image_to_string(textImage)
    print("This OK:%s"%text)
 
 
src = cv.imread("C://yzm.jpg")
cv.imshow("原来", src)
recognize_text()
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述
在此学习告一段落

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值