OpenCV

0

OpenCV介绍

  OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效,由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

OpenCV特点

  OpenCV是开源的计算机视觉库,采用C / C++编写,处理速度很快。
  OpenCV可以提供主流语言的接口,方便开发者调用。
  OpenCV具有通用的图像/视频载,保存和获取模块,具有底层和高层的应用开发包。

OpenCV应用

OpenCV读取,显示与保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import cv2 as cv

# cv.imread(filename, code) 以code格式读取一张图片,code可以为cv.IMREAD_GRAYSCALE读取一张灰度图像
img = cv.imread('lena.jpg')

# cv.namedWindow(windowname) 创建一个名为windowname的窗口
cv.namedWindow('lena')

# cv.imshow(window_name, img) 将img图片显示在窗口处
cv.imshow('lena', img)

# cv.waitkey(n) 等待用户按键n毫秒,0代表永远等待
cv.waitkey(0)

# cv.destroyAllWindows() 关闭所有窗口
cv.destroyAllWindows()

# cv.VideoCapture(n) 获取第n个摄像头,从0开始编号
cv.VideoCapture(0)

# cv.imwrite(filename, img) 将img图片保存在filename文件中
cv.imwrite('lena1.png', img)

1

OpenCV图像格式转换

cvtColor方法

1
2
3
4
5
6
7
8
9
10
11
import cv2 as cv

img = cv.imread('lena.jpg')

# cv.cvtColor(img, code) 将img转换为code格式,code可以为cv.COLOR_BGR2GRAY将RGB三通道彩色图像转换为灰度图像,cv.COLOR_BGR2HSV将RGB颜色通道转换为HSV颜色通道
img_gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)

cv.namedWindow('gray')
cv.imshow('gray', img_gray)
cv.waitKey(0)
cv.destroyAllWindows()

2

OpenCV图像形态学变换

morphologyEx方法

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2 as cv
import numpy as np

kernel = np.ones((3, 3), np.uint8)
img = cv.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)

# cv.morphologyEx(img, op, kernel) 将img进行模板为kernel的op操作,其中op可以为cv.MORPH_DILATE膨胀操作,cv.MORPH_ERODE腐蚀操作,cv.MORPH_OPEN开操作,cv.MORPH_CLOSE闭操作,cv.MORPH_GRADIENT梯度操作(膨胀+腐蚀)找出边缘
img_gradient = cv.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)

cv.namedWindow('gradient')
cv.imshow('gradient', img_gradient)
cv.waitKey(0)
cv.destroyAllWindows()

3

OpenCV图像形状变换

resize方法

1
2
3
4
5
6
7
8
9
10
11
12
13
import cv2 as cv

img = cv.imread('lena.jpg')
cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.resize(img, shape) 将img的大小调整为shape
img_resize = cv.resize(img, (500, 500))
cv.namedWindow('resize')
cv.imshow('resize',img_resize)

cv.waitKey(0)
cv.destroyAllWindows()

7

flip方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import cv2 as cv

img = cv.imread('lena.jpg')
cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.flip(img, n) 将img翻转,n>0沿y轴对称翻转,n=0沿x轴对称翻转,n<0沿x轴y轴同时对称翻转
img_flip_x = cv.flip(img, 0)
cv.namedWindow('flip_x')
cv.imshow('flip_x',img_flip_x)

img_flip_y = cv.flip(img, 1)
cv.namedWindow('flip_y')
cv.imshow('flip_y',img_flip_y)

img_flip_xy = cv.flip(img, -1)
cv.namedWindow('flip_xy')
cv.imshow('flip_xy',img_flip_xy)

cv.waitKey(0)
cv.destroyAllWindows()

4

warpAffine方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import cv2 as cv 
import numpy as np

np.random.seed(5)

m = np.random.rand(2,3)
img = cv.imread('lena.jpg')
cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.warpAffine(img, m, dsize) 将img进行仿射变换,变换矩阵为m,变换后的大小为dsize
img_affine = cv.warpAffine(img, m, (img.shape[0], img.shape[1]))
cv.namedWindow('affine')
cv.imshow('affine',img_affine)

cv.waitKey(0)
cv.destroyAllWindows()

5

OpenCV图像操作

bitwise方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import cv2 as cv
import numpy as np

np.random.seed(1)

img = cv.imread('lena.jpg')
img_random = np.random.randint(0, 256, img.shape, dtype=np.uint8)


# cv.bitwise_not(img) 按位取反,等价于~img
img_not = cv.bitwise_not(img)
cv.namedWindow('not')
cv.imshow('not', img_not)

# cv.bitwise_and(img1, img2) 按位与,等价于img1 & img2
img_and = cv.bitwise_and(img, img_random)
cv.namedWindow('and')
cv.imshow('and', img_and)

# cv.bitwise_or(img1, img2) 按位或,等价于img1 | img2
img_or = cv.bitwise_or(img, img_random)
cv.namedWindow('or')
cv.imshow('or', img_or)

# cv.bitwise_xor(img1, img2) 按位异或,等价于img1 ^ img2
img_xor = cv.bitwise_xor(img, img_random)
cv.namedWindow('xor')
cv.imshow('xor', img_xor)

cv.waitKey(0)
cv.destroyAllWindows()

6

add,subtract,multiply,divide,addweight方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import cv2 as cv
import numpy as np

np.random.seed(1)

img = cv.imread('lena.jpg')
img_random = np.random.randint(0, 256, img.shape, dtype=np.uint8)

# cv.add(img1, img2) 将两张图片相加,如果加和大于上限则赋值为上限(200+200=255),和img1+img2不同,img1+img2如果大于上限则从下限开始计算(200+200=400-256=144)
img_add = cv.add(img, img_random)
cv.namedWindow('add')
cv.imshow('add', img_add)

img_plus = img + img_random
cv.namedWindow('plus')
cv.imshow('plus', img_plus)

# cv.subtract(img1, img2) 将两张图片相减,用法同add

# cv.multiply(img1, img2) 将两张图片相乘,用法同add

# cv.divide(img1, img2) 将两张图片相除,用法同add

# cv.addweight(img1, x, img2, y, z) 将两张图片相加,结果为img1 * x + img2 * y + z
cv.waitKey(0)
cv.destroyAllWindows()

8

blur,medianBlur,GaussianBlur,filter2D方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import cv2 as cv
import numpy as np

img = cv.imread('lena.jpg')

cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.blur(img, ksize) 将img做均值模糊操作,核大小为ksize
img_blur = cv.blur(img, (5, 5))

cv.namedWindow('blur')
cv.imshow('blur', img_blur)

# cv.medianBlur(img, ksize) 将img做中值模糊操作,核大小为ksize
img_median_blur = cv.medianBlur(img, 5)

cv.namedWindow('median_blur')
cv.imshow('median_blur', img_median_blur)

# cv.GaussianBlur(img, ksize, sigmaX) 将img做高斯模糊操作,核大小为ksize,σ为sigmaX
img_gauss_blur = cv.GaussianBlur(img, (5, 5), sigmaX=1)

cv.namedWindow('gauss_blur')
cv.imshow('gauss_blur', img_gauss_blur)

# cv.filter2D(img, ddepth, kernel) 将img做二位卷积操作,卷积核为kernel,如果要保持大小则ddepth为-1
img_edge = cv.filter2D(img, -1, np.array([[0, -1, 0], [-1, 4, -1], [0, -1, 0]]))

cv.namedWindow('edge')
cv.imshow('edge', img_edge)
cv.waitKey(0)
cv.destroyAllWindows()

9

OpenCV统计

getTickCount,getTickFrequency方法

1
2
3
4
5
6
7
8
9
10
import cv2 as cv

# cv.getTickCount() 计算从开机到当前时间的时钟周期数
t1 = cv.getTickCount()
t2 = cv.getTickCount()

# cv.getTickFrequency() 获得一秒的时钟周期数,常常用时钟周期数除以该数获得所用时间
f = cv.getTickFrequency()

print('所用时间为:', (t2-t1) / f)

10

mean,meanStdDev方法

1
2
3
4
5
6
7
8
import cv2 as cv
img = cv.imread('lena.jpg')

# cv.mean(img) 计算img每个通道的均值
mean = cv.mean(img)

# cv.meanStdDev(img) 计算img每个通道的均值和方差
mean1, std1 = cv.meanStdDev(img)

11

calcHist方法

1
2
3
4
5
6
7
8
9
10
11
import cv2 as cv
import matplotlib.pyplot as plt

img = cv.imread('lena.jpg')
color=['blue','green','red']

# cv.calcHist(img, channels, mask, histSize, ranges) 绘制img中channels通道的直方图,histSize为直方图大小,ranges为直方图的范围
for i,color_i in enumerate(color):
hist = cv.calcHist([img],[i],None,[256],[0,255])
plt.plot(hist,color_i)
plt.show()

12

OpenCV常用图像操作

inRange方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import cv2 as cv
import numpy as np

img = cv.imread('lena.jpg')
cv.namedWindow('origin')
cv.imshow('origin', img)

img_hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)

# cv.inRange(img, lowerb, upperb) 将HSV色彩空间中的颜色过滤,img颜色通道先转换为HSV,然后再进行颜色过滤
res = cv.inRange(img_hsv, np.array([125, 43, 46]), np.array([155, 255, 255]))

cv.namedWindow('purple')
cv.imshow('purple', res)
cv.waitKey(0)
cv.destroyAllWindows()

HSV空间颜色分布表:

$$\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|} 颜色 & 黑 & 灰 & 白 & 红 & 橙 & 黄 & 绿 & 青 & 蓝 & 紫 \\ \hline h_{min} & 0 & 0 & 0 & 0 & 11 & 26 & 35 & 78 & 100 & 125\\ h_{max} & 180 & 180 & 180 & 10 & 25 & 34 & 77 & 99 & 124 & 155\\ s_{min} & 0 & 0 & 0 & 43 & 43 & 43 & 43 & 43 & 43 & 43\\ s_{max} & 255 & 43 & 30 & 255 & 255 & 255 & 255 & 255 & 255 & 255\\ v_{min} & 0 & 46 & 221 & 46 & 46 & 46 & 46 & 46 & 46 & 46\\ v_{max} & 46 & 220 & 255 & 255 & 255 & 255 & 255 & 255 & 255 & 255\\ \end{array}$$
13

equalizeHist方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import cv2 as cv

img = cv.imread('lena.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.equalizeHist(img) 对img图像进行直方图均衡化
img_equal = cv.equalizeHist(img)

cv.namedWindow('euqal')
cv.imshow('equal', img_equal)
cv.waitKey(0)
cv.destoryAllWindows()

14

compareHist,calcBackProject,matchTemplate方法

1
2
3
4
5
# cv.compareHist(hist1, hist2, method) 对两个直方图进行比较,method可以为cv.HISTCMP_BHATTACHARYYA,cv.HISTCMP_CORREL等等

# cv.calcBackProject(target, channel, hsv_hist, range) 从target中寻找处与模板相似的区域,其中模板为HSV图像的直方图,channel为通道数,range为直方图的长和宽

# cv.matchTemplate(target, mask, method) 计算图片之间的匹配程度,method可以为cv.TM_SQDIFF_NORMED,cv.TM_CCOERR_NORMED,cv.TM_CCOEFF_NORMED等等

line,rectangle,circle方法

1
2
3
4
5
# cv.line(img, pt1, pt2, color, thickness) 在img图像上画一条直线,起点坐标为pt1,终点坐标为pt2,颜色为color,线宽为thickness

# cv.rectangle(img, pt1, pt2, color, thickness) 在img图像上画一个矩形,左上点坐标为pt1,右下点坐标为pt2,颜色为color,线宽为thickness

# cv.circle(img, center, radius, color, thickness) 在img图像上画一个圆,圆心坐标为center,半径为radius,颜色为color,线宽为thickness

threshold方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import cv2 as cv

img = cv.imread('lena.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.threshold(img, thresh, maxval, type) 对灰度图像img进行阈值分割,thresh为指定按照阈值大小分割,最大的灰度值为maxval,分割方法为type,可以为cv.THRESH_OTSU等等,如果指定type则thresh失效
thresh, img_thresh = cv.threshold(img, 0, 255, cv.THRESH_OTSU)

cv.namedWindow('thresh')
cv.imshow('thresh', img_thresh)
cv.waitKey(0)
cv.destoryAllWindows()

15

pyrDown,pyrUp方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import cv2 as cv

img = cv.imread('lena.jpg')
cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.pyrDown(img) 对img进行下采样
img_down = cv.pyrDown(img)

cv.namedWindow('down')
cv.imshow('down', img_down)

# cv.pyrUp(img) 对img进行上采样
img_up = cv.pyrUp(img)

cv.namedWindow('up')
cv.imshow('up', img_up)
cv.waitKey(0)
cv.destoryAllWindows()

16

OpenCV算子

Sobel,Laplacian,Canny方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import cv2 as cv

img = cv.imread('lena.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

cv.namedWindow('origin')
cv.imshow('origin', img)

# cv.Sobel(img, ddepth, dx, dy) 对img进行Sobel算子滤波,dx=1,dy=0代表水平方向,dx=0,dy=1代表垂直方向
img_sobel = cv.Sobel(img, -1, dx=0, dy=1)

cv.namedWindow('sobel')
cv.imshow('sobel', img_sobel)

# cv.Laplacian(img, ddepth) 将img进行Laplacian算子滤波
img_laplacian = cv.Laplacian(img, -1)

cv.namedWindow('laplacian')
cv.imshow('laplacian', img_laplacian)

# cv.Canny(img, threshold1, threshold2) 将img进行Canny算子滤波,低阈值为threshold1,高阈值为threshold2
img_canny = cv.Canny(img, 50, 150)

cv.namedWindow('canny')
cv.imshow('canny', img_canny)
cv.waitKey(0)
cv.destroyAllWindows()

17

OpenCV霍夫变换

HoughLines,HoughCircles方法

1
2
3
# cv.HoughLines(img, rho, theta, threshold) 霍夫直线检测,边缘提取后的图像为img,步长为rho,角度步长为theta,阈值为threshold,返回所有直线信息

# cv.HoughCircles(img, method, dp, minDist, param1, param2, minRadius, maxRadius) 霍夫圆检测,检测方法method,可以为cv.HOUGH_GRADIENT等等,dp为累加器分辨率与图像分辨率的反比,dp越大,累加器数组越小,minDist为检测到原中心的最小距离,如果太靠近则检测不出,param1用于边缘检测的阈值,param2为累加器阈值,越高则越精确,但是圆越少,minRadius为圆的最小半径,maxRadius为圆的最大半径

OpenCV轮廓处理

findContour,drawContour,contourArea方法

1
2
3
4
5
# cv.findContour(img, mode, method) 寻找轮廓,mode表示轮廓的检索模式,可以为cv2.RETR_EXTERNAL,cv2.RETR_TREE等等,method表示轮廓的近似办法,可以为cv2.CHAIN_APPROX_NONE,cv2.CHAIN_APPROX_SIMPLE等等

# cv.drawContour(img, contours, contourIdx, color, thickness) 根据寻找到的轮廓,画出第contourIdx个轮廓,颜色为color,线宽为thickness

# cv.contourArea(contour) 计算轮廓的面积

OpenCV小结

  通过OpenCV,使用者可以仅需要几行代码,便可以完成一系列图像处理任务,在这里介绍的只是小部分常见的功能,因此在图像处理的研究应用中,OpenCV是必不可少的帮手。

-------------本文结束感谢您的阅读-------------
0%