OpenCV_python编程


demo代码:https://github.com/2012Netsky/opencv


前言

和Python一样,当前的OpenCV也有两个大版本,OpenCV2和OpenCV3。相比OpenCV2,OpenCV3提供了更强的功能和更多方便的特性。
根据功能和需求的不同,OpenCV中的函数接口大体可以分为如下部分:

  • core:核心模块,主要包含了OpenCV中最基本的结构(矩阵,点线和形状等),以及相关的基础运算/操作。

  • imgproc:图像处理模块,包含和图像相关的基础功能(滤波,梯度,改变大小等),以及一些衍生的高级功能(图像分割,直方图,形态分析和边缘/直线提取等)。

  • highgui:提供了用户界面和文件读取的基本函数,比如图像显示窗口的生成和控制,图像/视频文件的IO等。

  • 如果不考虑视频应用,以上三个就是最核心和常用的模块了。针对视频和一些特别的视觉应用,OpenCV也提供了强劲的支持:

  • video:用于视频分析的常用功能,比如光流法(Optical Flow)和目标跟踪等。

  • calib3d:三维重建,立体视觉和相机标定等的相关功能。

  • features2d:二维特征相关的功能,主要是一些不受专利保护的,商业友好的特征点检测和匹配等功能,比如ORB特征。

  • object:目标检测模块,包含级联分类和Latent SVM

  • ml:机器学习算法模块,包含一些视觉中最常用的传统机器学习算法。

  • flann:最近邻算法库,Fast Library for Approximate

  • Nearest Neighbors,用于在多维空间进行聚类和检索,经常和关键点匹配搭配使用。

  • gpu:包含了一些gpu加速的接口,底层的加速是CUDA实现。

  • photo:计算摄像学(Computational Photography)相关的接口,当然这只是个名字,其实只有图像修复和降噪而已。

  • stitching:图像拼接模块,有了它可以自己生成全景照片。

  • nonfree:受到专利保护的一些算法,其实就是SIFT和SURF。

  • contrib:一些实验性质的算法,考虑在未来版本中加入的。

  • legacy:字面是遗产,意思就是废弃的一些接口,保留是考虑到向下兼容。

  • ocl:利用OpenCL并行加速的一些接口。

  • superres:超分辨率模块,其实就是BTV-L1(Biliteral Total Variation – L1regularization)算法

  • viz:基础的3D渲染模块,其实底层就是著名的3D工具包VTK(Visualization Toolkit)。

从使用的角度来看,和OpenCV2相比,OpenCV3的主要变化是更多的功能和更细化的模块划分。


python——opencv基础
图像的表示
已知单通道的灰度图像在计算机中的表示是一个8位无符号整形的矩阵,在oncv的C++代码中,表示图像有专门的结构cv::Mat,但python中有numpy这种强大的基础工具,所以该矩阵就用numpy的array表示,多通道就是红绿蓝(RGB)三通道。

在这里插入图片描述


1、OpenCV读图及显示

import cv2

img = cv2.imread("psc.jpg")
cv2.namedWindow("Image")
cv2.imshow("Image", img)
cv2.waitKey(-1)
cv2.destroyAllWindows()

2、自定义函数读图及显示



def show_picture(picture):
    import cv2
    img = cv2.imread(picture)
    print(type(img), img.size, img.shape, img.dtype)

    # print(img.shape)
    # print(img)
    #
    # cv2.namedWindow("Image"+picture)
    # cv2.imshow("Image"+picture, img)
    # cv2.waitKey(-1)
    # cv2.destroyAllWindows()


show_picture('psc.jpg')

3、读取摄像头图片

import cv2 as cv


def video_demo():
    # 0是代表摄像头编号,只有一个的话默认为0
    capture = cv.VideoCapture(0)
    while (True):
        ref, frame = capture.read()

        cv.imshow("1", frame)
        # 等待30ms显示图像,若过程中按“Esc”退出
        c = cv.waitKey(10)
        if c == 27:
            capture.release()
            break


video_demo()
cv.waitKey()
cv.destroyAllWindows()

4、裁剪

import cv2


def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


img = cv2.imread('psc.jpg')
cat = img[0:50, 0:200]
cv_show('cat', cat)

5、通道分离及通道融合

import cv2

img = cv2.imread('psc.jpg')  # 读取方式cv2.IMREAD_REDUCED_GRAYSCALE_2

print(img.shape)
b, g, r = cv2.split(img)  # 
print(r.shape, g.shape, b.shape)
img = cv2.merge((r, g, b))  # 
print(img.shape)
cv2.imwrite('mycat.png', img)  # 写图片

# 只保留R
cur_img = img.copy()
cur_img[:, :, 0] = 0
cur_img[:, :, 1] = 0
cv_show('R', cur_img)

# 只保留G
cur_img = img.copy()
cur_img[:, :, 0] = 0
cur_img[:, :, 2] = 0
cv_show('G', cur_img)

# 只保留B
cur_img = img.copy()
cur_img[:, :, 1] = 0
cur_img[:, :, 2] = 0
cv_show('B', cur_img)

6、边界填充


'''
BORDER_REPLICATE:复制法,也就是复制最边缘像素。
BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT:常量法,常数值填充。
'''

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

7、数值计算


import cv2


# 第一种显示图片方式
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


img_cat = cv2.imread('cat.jpg')
img_dog = cv2.imread('dog.jpg')
rows, cols = img_cat.shape[:2]  # 得到 img_cat尺寸 的大小
img_dog = cv2.resize(img_dog, (cols, rows), interpolation=cv2.INTER_CUBIC)  # 调整图片大小

8、第二种显示图片方式


import matplotlib.pyplot as plt

plt.subplot(121), plt.imshow(img_cat), plt.title('ORIGINAL')  # 图片显示信息设置
plt.subplot(122), plt.imshow(img_dog), plt.title('ORIGINAL')  # 图片显示信息设置
plt.show()  # 图片显示

# 第三种显示图片方式
cv2.imshow('cat', img_cat)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imshow('dog', img_dog)
cv2.waitKey(0)
cv2.destroyAllWindows()

img_cat2 = img_cat + 10
print(img_cat[:5, :, 0], img_cat2[:5, :, 0], (img_cat + img_cat2)[:5, :, 0], cv2.add(img_cat, img_cat2)[:5, :, 0])

9、图像融合(高级)


import cv2  # opencv读取的格式是BGR

#
img_cat = cv2.imread('cat.jpg')
img_dog = cv2.imread('dog.jpg')

rows, cols = img_cat.shape[:2]  # 获取img_cat的高度、宽度
img_dog = cv2.resize(img_dog, (cols, rows))

print(img_cat.shape, img_dog.shape)
print(img_cat + img_dog)  # 直接融合

res = cv2.addWeighted(img_cat, 0.4, img_dog, 0.6, 0)  # 带有权重的融合

print(res.shape)

import matplotlib.pyplot as plt  # 显示图片

plt.subplot(131), plt.imshow(img_cat), plt.title('ORIGINAL1')  # 图片显示信息设置
plt.subplot(132), plt.imshow(img_dog), plt.title('ORIGINAL2')
plt.subplot(133), plt.imshow(res), plt.title('ORIGINAL3')
plt.imshow(res)  # 显示图片

10、调整大小


import cv2
import matplotlib.pyplot as plt


def cv_show(name, img):
    #    img=cv2.imread(img)      # cv_show('pic',cv2.imread('psc.jpg'))
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# cv_show('pic','psc.jpg')
# cv_show('pic',cv2.imread('psc.jpg'))

img = cv2.imread('psc.jpg')
res = cv2.resize(img, (0, 0), fx=4, fy=4)
# cv_show('1',img)
# cv_show('2',res)
# plt.imshow(res)
print(img.shape, res.shape)

11、matplotlib 显示图像

#
from PIL import Image
import matplotlib.pyplot as plt

# 显示彩色
# img = Image.open(os.path.join('images', '2007_000648' + '.jpg'))  # images文件夹 2007_000648文件名 .jpg后缀名
img = Image.open('psc.jpg')
print('1', img)
# img = img.convert('L')  # 转变为灰度 L = R * 299/1000 + G * 587/1000+ B * 114/1000
print('2', img)
plt.figure("Image")  # 图像窗口名称
print('3')
plt.imshow(img)  # 图像信息
# plt.imshow(img,g)       # 图像信息,显示灰色
print('4')
plt.axis('on')  # 关掉坐标轴为 off
plt.title('image')  # 图像题目
print('5')
plt.show()

12、显示多张图片

# 
from PIL import Image
import matplotlib.pyplot as plt

img = Image.open('psc.jpg')
gray = img.convert('L')
r, g, b = img.split()
img_merged = Image.merge('RGB', (r, g, b))

plt.figure(figsize=(10, 5))  # 设置窗口大小
plt.suptitle('Multi_Image')  # 图片名称

plt.subplot(2, 3, 1), plt.title('image')  # 2行3列第一个
plt.imshow(img), plt.axis('off')

plt.subplot(2, 3, 2), plt.title('gray')  # 2行3列第二个
plt.imshow(gray, cmap='gray'), plt.axis('off')  # 这里显示灰度图要加cmap

plt.subplot(2, 3, 3), plt.title('img_merged')  # 2行3列第三个
plt.imshow(img_merged), plt.axis('off')

plt.subplot(2, 3, 4), plt.title('r')  # 2行3列第四个
plt.imshow(r, cmap='gray'), plt.axis('off')

plt.subplot(2, 3, 5), plt.title('g')  # 2行3列第五个
plt.imshow(g, cmap='gray'), plt.axis('off')

plt.subplot(2, 3, 6), plt.title('b')  # 2行3列第六个
plt.imshow(b, cmap='gray'), plt.axis('off')

plt.show()

13、灰度图


import cv2  # opencv 读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt  # Matplotlib 是RGB

img = cv2.imread('psc.jpg')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(img_gray.shape)

cv2.imshow("img_gray", img_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

# hsv通道分离
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.imshow("hsv", hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()

14、阈值分割

'''
ret, dst = cv2.threshold(src, thresh, maxval, type)

    src:    输入图,只能输入单通道图像,通常来说为灰度图
    dst:    输出图
    thresh: 阈值
    maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
    type:   二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV

    cv2.THRESH_BINARY 超过阈值部分取maxval(最大值),否则取0
    cv2.THRESH_BINARY_INV THRESH_BINARY的反转
    cv2.THRESH_TRUNC 大于阈值部分设为阈值,否则不变
    cv2.THRESH_TOZERO 大于阈值部分不改变,否则设为0
    cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
'''
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)

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

15、显示图片

# -------------------------- #
img = cv2.imread('cat.jpg')  #
cv2.namedWindow("Image")  #
cv2.imshow('Image', img)  #
cv2.waitKey(-1)  #
cv2.destroyAllWindows()  #
# -------------------------- #

16、显示

import cv2

img = cv2.imread("psc.jpg")
# cv2.namedWindow("Image")
cv2.imshow("Image", img)
cv2.waitKey(-1)
cv2.destroyAllWindows()

17、滤波

# 均值
# 简单的平均卷积操作
img = cv2.imread('cat.jpg')
blur = cv2.blur(img, (3, 3))
cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 方框滤波
# 基本和均值一样,可以选择归一化
img = cv2.imread('cat.jpg')
box = cv2.boxFilter(img, -1, (3, 3), normalize=True)

cv2.imshow('box', box)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 方框滤波
# 基本和均值一样,可以选择归一化,容易越界
img = cv2.imread('cat.jpg')
box = cv2.boxFilter(img, -1, (3, 3), normalize=False)

cv2.imshow('box', box)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
img = cv2.imread('cat.jpg')
aussian = cv2.GaussianBlur(img, (5, 5), 1)

cv2.imshow('aussian', aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 中值滤波
# 相当于用中值代替
img = cv2.imread('cat.jpg')
median = cv2.medianBlur(img, 5)  # 中值滤波

cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 展示所有的
res = np.hstack((blur, aussian, median))
# print (res)
cv2.imshow('median vs average', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

18、形态学-腐蚀操作


import numpy as np

img = cv2.imread('cat.jpg')

# cv2.imshow('img', img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

kernel = np.ones((3, 3), np.uint8)
print(kernel)
erosion = cv2.erode(img, kernel, iterations=1)

# cv2.imshow('erosion', erosion)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
import matplotlib.pyplot as plt  # 显示图片

plt.subplot(121), plt.imshow(img), plt.title('img')  # 图片显示信息设置
plt.subplot(122), plt.imshow(erosion), plt.title('erosion')
plt.show()  # 显示图片

pie = cv2.imread('pie.png')

cv2.imshow('pie', pie)
cv2.waitKey(0)
cv2.destroyAllWindows()

19、腐蚀

import numpy as np

img = cv2.imread('cat.jpg')
kernel = np.ones((3, 3), np.uint8)
erosion_1 = cv2.erode(img, kernel, iterations=1)
erosion_2 = cv2.erode(img, kernel, iterations=2)
erosion_3 = cv2.erode(img, kernel, iterations=3)

res = np.hstack((erosion_1, erosion_2, erosion_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

20、形态学-膨胀操作

# 
import numpy as np

img = cv2.imread('cat.jpg')

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

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

# cv2.imshow('erosion', erosion)
# cv2.waitKey(0)
# cv2.destroyAllWindows()


kernel = np.ones((3, 3), np.uint8)
dilate = cv2.dilate(erosion, kernel, iterations=1)

# cv2.imshow('dilate', dilate)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

res = np.hstack((img, erosion, dilate))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

21、腐蚀

import numpy as np

img = cv2.imread('cat.jpg')

kernel = np.ones((30, 30), np.uint8)
dilate_1 = cv2.dilate(img, kernel, iterations=1)
dilate_2 = cv2.dilate(img, kernel, iterations=2)
dilate_3 = cv2.dilate(img, kernel, iterations=3)
res = np.hstack((dilate_1, dilate_2, dilate_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

22、开运算与闭运算


# 开:先腐蚀,再膨胀
import numpy as np

img = cv2.imread('cat.jpg')

kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 闭:先膨胀,再腐蚀
img = cv2.imread('cat.jpg')

kernel = np.ones((5, 5), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

cv2.imshow('closing', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()

23、梯度运算

# 梯度=膨胀-腐蚀
import numpy as np

pie = cv2.imread('cat.jpg')
kernel = np.ones((3, 3), np.uint8)
dilate = cv2.dilate(pie, kernel, iterations=5)
erosion = cv2.erode(pie, kernel, iterations=5)

res = np.hstack((dilate, erosion))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)
cv2.imshow('gradient', gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()

24、礼帽与黑帽

'''

    礼帽 = 原始输入-开运算结果
    黑帽 = 闭运算-原始输入
'''
# 礼帽
import numpy as np

img = cv2.imread('cat.jpg')
kernel = np.ones((3, 3), np.uint8)
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)

cv2.imshow('tophat', tophat)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 黑帽
img = cv2.imread('cat.jpg')
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
cv2.imshow('blackhat ', blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()

25、图像梯度-Sobel算子

img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

'''
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
ddepth:图像的深度
   dx和dy分别表示水平和竖直方向
   ksize是Sobel算子的大小
'''


def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


# sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
# cv_show(sobelx,'sobelx')

# 白到黑是正数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
cv_show(sobelx, 'sobelx')

sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
sobely = cv2.convertScaleAbs(sobely)
cv_show(sobely, 'sobely')

# # 分别计算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')


def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)
cv_show(img, 'img')

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)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
cv_show(sobelxy, 'sobelxy')

26、图像梯度

'''
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3) sobelxy = cv2.convertScaleAbs(sobelxy) cv_show(sobelxy,'sobelxy')
'''

# 图像梯度-Scharr算子
# 图像梯度-laplacian算子
# 不同算子的差异

import numpy as np


def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


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)
scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1)
scharrx = cv2.convertScaleAbs(scharrx)
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((sobelxy, scharrxy, laplacian))
cv_show(res, 'res')

27、Canny边缘检测

'''
Canny边缘检测
    1) 使用高斯滤波器,以平滑图像,滤除噪声。
    2) 计算图像中每个像素点的梯度强度和方向。
    3) 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
    4) 应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
    5) 通过抑制孤立的弱边缘最终完成边缘检测。
'''

# 1:高斯滤波器
# 2:梯度和方向
# 3:非极大值抑制
# 4:双阈值检测

import numpy as np

img = cv2.imread("cat.jpg", cv2.IMREAD_GRAYSCALE)


def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 100)
res = np.hstack((v1, v2))
cv_show(res, 'res')

img = cv2.imread("car.png", cv2.IMREAD_GRAYSCALE)
v1 = cv2.Canny(img, 120, 250)
v2 = cv2.Canny(img, 50, 100)
res = np.hstack((v1, v2))
cv_show(res, 'res')

28、图像金字塔


'''
图像金字塔
   高斯金字塔
   拉普拉斯金字
'''
# 高斯金字塔:向下采样方法(缩小)
# 高斯金字塔:向上采样方法(放大)

import numpy as np


def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("cat.jpg")
cv_show(img, 'img')
print('1', img.shape)

up = cv2.pyrUp(img)
cv_show(up, 'up')  # 放大
print('2', up.shape)

down = cv2.pyrDown(img)
cv_show(down, 'down')  # 缩小
print('3', down.shape)

up2 = cv2.pyrUp(up)
cv_show(up2, 'up2')  # 超级放大
print('4', up2.shape)

up = cv2.pyrUp(img)
up_down = cv2.pyrDown(up)  # 放大再缩小
cv_show(up_down, 'up_down')

cv_show(np.hstack((img, up_down)), 'up_down')

up = cv2.pyrUp(img)
up_down = cv2.pyrDown(up)
cv_show(img - up_down, 'img-up_down')  # 梯度 边缘检测

29、拉普拉斯金字塔



# 拉普拉斯金字塔

def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread("cat.jpg")
down = cv2.pyrDown(img)
down_up = cv2.pyrUp(down)
l_1 = img - down_up
cv_show(l_1, 'l_1')

30、图像轮廓

'''
图像轮廓

   cv2.findContours(img,mode,method)
   mode:轮廓检索模式

       RETR_EXTERNAL :只检索最外面的轮廓;
       RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
       RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
       RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;

   method:轮廓逼近方法

       CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
       CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
'''


# 为了更高的准确率,使用二值图像。


def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread('cat.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv_show(thresh, 'thresh')

binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# 绘制轮廓
cv_show(img, 'img')

31、传入绘制图像



# 传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变

def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


img = cv2.imread('cat.jpg')
draw_img = img.copy()

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)

res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res, 'res')

draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
cv_show(res, 'res')

# 轮廓特征
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.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show(res, 'res')

epsilon = 0.15 * cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, epsilon, True)

draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res, 'res')

32、边界矩形

# 边界矩形

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[0]

x, y, w, h = cv2.boundingRect(cnt)
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
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')

33、傅里叶变换

'''
傅里叶变换
  我们生活在时间的世界中,早上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)。
'''

34、得到灰度图能表示的形式

import numpy as np
import cv2
from matplotlib import pyplot as plt

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

35、低通滤波

import numpy as np
import cv2
from matplotlib import pyplot as plt

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

36、高通滤波

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

37、直方图与模板匹配

# 直方图与模板匹配
import cv2  # opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt  # Matplotlib是RGB


# %matplotlib inline

def cv_show(img, name):
    cv2.imshow(name, img)
    cv2.waitKey()
    cv2.destroyAllWindows()


38、直方图

'''
v2.calcHist(images,channels,mask,histSize,ranges)

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

img = cv2.imread('cat.jpg', 0)  # 0表示灰度图
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
print(hist.shape)

plt.hist(img.ravel(), 256)
plt.show()

img = cv2.imread('cat.jpg')
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])

39、mask操作

# mask操作
# 创建mast

mask = np.zeros(img.shape[:2], np.uint8)
print(mask.shape)
mask[100:300, 100:400] = 255
cv_show(mask, 'mask')
img = cv2.imread('cat.jpg', 0)
cv_show(img, 'img')
masked_img = cv2.bitwise_and(img, img, mask=mask)  # 与操作
cv_show(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()

40、直方图均衡化

# 直方图均衡化
img = cv2.imread('clahe.jpg', 0)  # 0表示灰度图 #clahe
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')

# 自适应直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
res_clahe = clahe.apply(img)
res = np.hstack((img, equ, res_clahe))
cv_show(res, 'res')

41、模板匹配

# 模板匹配

'''
  模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,
  这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图
  形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)
'''

# 模板匹配
img = cv2.imread('lena.jpg', 0)
template = cv2.imread('face.jpg', 0)
h, w = template.shape[:2]
print(img.shape, template.shape)

'''
  TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
  TM_CCORR:计算相关性,计算出来的值越大,越相关
  TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
  TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
  TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
  TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
  公式:https://docs.opencv.org/3.3.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d
'''

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_SQDIFF)
print(res.shape)

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print(min_val, max_val, min_loc, 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()

42、匹配多个对象

# 匹配多个对象
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('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)

cv2.imshow('img_rgb', img_rgb)
cv2.waitKey(0)

猜你喜欢

转载自blog.csdn.net/weixin_42483745/article/details/123828763
今日推荐