OpenCV基础学习

本文最后更新于:2022年7月8日下午5点08分

人脸识别、物体检测太有趣了,搭配小小的树莓派可以做很多事情呀

0 安装与引言

安装参见这篇文章这个视频

图像介绍

VGA=640×480(weight×height, pixels, 左上(0,0), 右下(640,480))

HD=1280×720

FHD=1920×1080

4K=3840×2160

灰度值\(0-2^8\),0为黑,\(2^8\)为纯白,中间有256个levels(8bits)。比如2levels就是非黑即白(Binary Image),而256levels的图片理论上会包含有0-256个值,即除了黑(0)白(256),中间还有254种颜色(灰色)(灰度值254),也就是说有黑白2种颜色加上254种灰色一共256种颜色。

对于一张彩色图片,由三张具有R、G、B色彩的图片构成,即3通道。所以一张彩色VGA图片:RGB VGA=640×480×3

1 读取图片、视频和网络摄像头

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
# chapter1 read images, videos and webcam
import cv2 as cv
print("Package Imported")

# 读取图片
# img = cv.imread('friends.jpg')
# cv.imshow('img',img)
# cv.waitKey(1000)

# 读取视频
# cap = cv.VideoCapture("friends.mp4")
# while True:
# success, img = cap.read()
# cv.imshow("Video",img)
# if cv.waitKey(1) & 0xFF == ord('q'):
# break
# cv.waitKey(1)相当于粗水管(输出值可能大于8bit),
# 0xFF相当于细水管(输出值是0b11111111)
# 两个'与'起来的意思是只要cv.waitKey(1)的对应0xFF的部分
# 所以这条语句就是判断键盘输入的前8bit是否是'q'

# 读取摄像头(webcam)
cap = cv.VideoCapture(0)
cap.set(3,640) # 宽,3是id,640是像素
cap.set(4,480) # 高
cap.set(10,100) # 调节亮度,10是id

while True:
success, img = cap.read()
cv.imshow("Video",img)
if cv.waitKey(1) & 0xFF == ord('q'):
break

2 基本函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# chapter2 basic functions
import cv2 as cv
import numpy as np

img = cv.imread("friends.jpg")
kernel = np.ones((5,5),np.uint8)
imgGray = cv.cvtColor(img,cv.COLOR_RGB2GRAY)
imgBlur = cv.GaussianBlur(imgGray,(7,7),0)
imgCanny = cv.Canny(img,50,500) # 值越大,轮廓越少
imgDialation = cv.dilate(imgCanny,kernel,iterations=1)
imgEroded = cv.erode(imgDialation,kernel,iterations=1)

cv.imshow("Image",img)
cv.imshow("Gray Image",imgGray)
cv.imshow("Blur Image",imgBlur)
cv.imshow("Canny Image",imgCanny)
cv.imshow("Dialation Image",imgDialation)
cv.imshow("Eroded Image",imgEroded)
cv.waitKey(0)

3 调整并裁剪图片大小

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

img = cv.imread('friends.jpg')
print(img.shape) # 输出结果(1000,680,3) (高,宽,通道)

imgResize = cv.resize(img,(300,200))
print(imgResize.shape) # (200,300,3)

imgCropped = img[50:235,165:305] # Joey's face
print(imgCropped.shape) # (185, 140, 3)

cv.imshow('Image',img)
cv.imshow('Image Resize',imgResize)
cv.imshow('Image Cropped',imgCropped)
cv.waitKey(0)

4 形状及文本

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

img = np.zeros((512,512,3),np.uint8)
print(img.shape) # 大小
# print(img) # 矩阵
# img[:] = 255,0,0 # :意思是整张图一个颜色
# img[100:300,200:300] = 255,0,0 # 指定区域

cv.line(img,(0,0),(img.shape[1],img.shape[0]),(0,255,0),1) # 起点坐标,终点坐标(矩阵),颜色,线宽
cv.rectangle(img,(0,0),(200,300),(0,0,255),2) # 最后是线宽,替换为cv.FILLED是填充
cv.circle(img,(400,50),30,(255,255,0),5) # 圆心,半径,颜色,线宽
cv.putText(img,"OpenCV",(300,200),cv.FONT_HERSHEY_COMPLEX,0.5,(255,0,0),2) # 坐标,字体,字体比例大小,颜色,线宽

cv.imshow('Image',img)
cv.waitKey(0)

5 透视变换

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

img = cv.imread("poker.jpg")

width,height = 250,350
pts1 = np.float32([[1100,402],[1387,730],[596,868],[905,1209]])
pts2 = np.float32([[0,0],[width,0],[0,height],[width,height]])
matrix = cv.getPerspectiveTransform(pts1,pts2)
imgOutput = cv.warpPerspective(img,matrix,(width,height))

cv.imshow('Image',img)
cv.imshow('Image Output',imgOutput)
cv.waitKey(0)

6 合并图片

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# chapter6 Joining images
import cv2 as cv
import numpy as np

# img = cv.imread("poker.jpg")
# imgHor = np.hstack((img,img))
# imgVer = np.vstack((img,img))
# # 两个问题:1不能调整合并图的大小;
# # 2该函数属于numpy库,是两个矩阵的拼接,所以如果两个图片通道不同,不能合并

# cv.imshow('Horizontal',imgHor)
# cv.imshow('Vertical',imgVer)
# cv.waitKey(0)

def stackImages(scale,imgArray):
rows = len(imgArray)
cols = len(imgArray[0])
rowsAvailable = isinstance(imgArray[0], list)
width = imgArray[0][0].shape[1]
height = imgArray[0][0].shape[0]
if rowsAvailable:
for x in range ( 0, rows):
for y in range(0, cols):
if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
imgArray[x][y] = cv.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv.cvtColor( imgArray[x][y], cv.COLOR_GRAY2BGR)
imageBlank = np.zeros((height, width, 3), np.uint8)
hor = [imageBlank]*rows
hor_con = [imageBlank]*rows
for x in range(0, rows):
hor[x] = np.hstack(imgArray[x])
ver = np.vstack(hor)
else:
for x in range(0, rows):
if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
imgArray[x] = cv.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
if len(imgArray[x].shape) == 2: imgArray[x] = cv.cvtColor(imgArray[x], cv.COLOR_GRAY2BGR)
hor= np.hstack(imgArray)
ver = hor
return ver

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

imgStack = stackImages(0.5,([img,imgGray,img],[img,img,img]))

cv.imshow("ImageStack",imgStack)

cv.waitKey(0)

7 颜色检测

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# chapter7 color detection
import cv2 as cv
import numpy as np


def empty(a):
pass

# 组图程序
def stackImages(scale,imgArray):
rows = len(imgArray)
cols = len(imgArray[0])
rowsAvailable = isinstance(imgArray[0], list)
width = imgArray[0][0].shape[1]
height = imgArray[0][0].shape[0]
if rowsAvailable:
for x in range ( 0, rows):
for y in range(0, cols):
if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
imgArray[x][y] = cv.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv.cvtColor( imgArray[x][y], cv.COLOR_GRAY2BGR)
imageBlank = np.zeros((height, width, 3), np.uint8)
hor = [imageBlank]*rows
hor_con = [imageBlank]*rows
for x in range(0, rows):
hor[x] = np.hstack(imgArray[x])
ver = np.vstack(hor)
else:
for x in range(0, rows):
if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
imgArray[x] = cv.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
if len(imgArray[x].shape) == 2: imgArray[x] = cv.cvtColor(imgArray[x], cv.COLOR_GRAY2BGR)
hor= np.hstack(imgArray)
ver = hor
return ver

path = 'friends.jpg'
cv.namedWindow('TrackBars')
cv.resizeWindow('TrackBars', 640, 240)
cv.createTrackbar('Hue Min', 'TrackBars', 0, 179, empty)
cv.createTrackbar('Hue Max', 'TrackBars', 28, 179, empty)
cv.createTrackbar('Sat Min', 'TrackBars', 3, 355, empty)
cv.createTrackbar('Sat Max', 'TrackBars', 255, 255, empty)
cv.createTrackbar('Val Min', 'TrackBars', 143, 255, empty)
cv.createTrackbar('Val Max', 'TrackBars', 255, 255, empty)

img = cv.imread(path)

while True:
imgHSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
h_min = cv.getTrackbarPos('Hue Min', 'TrackBars')
h_max = cv.getTrackbarPos('Hue Max', 'TrackBars')
s_min = cv.getTrackbarPos('Sat Min', 'TrackBars')
s_max = cv.getTrackbarPos('Sat Max', 'TrackBars')
v_min = cv.getTrackbarPos('Val Min', 'TrackBars')
v_max = cv.getTrackbarPos('Val Max', 'TrackBars')
print(h_min, h_max, s_min, s_max, v_min, v_max)
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
mask = cv.inRange(imgHSV, lower, upper)
imgResult = cv.bitwise_and(img,img,mask=mask)

cv.imshow('Original', img)
cv.imshow('ImageHSV', imgHSV)
cv.imshow('Mask', mask)
cv.imshow('Result', imgResult)
imgStack = stackImages(0.5,([img,imgHSV],[mask,imgResult]))
cv.imshow('Stacked Images',imgStack)
cv.waitKey(1)

8 轮廓、形状检测

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# chapter8 contours / shape detection
import cv2 as cv
import numpy as np

def stackImages(scale,imgArray):
rows = len(imgArray)
cols = len(imgArray[0])
rowsAvailable = isinstance(imgArray[0], list)
width = imgArray[0][0].shape[1]
height = imgArray[0][0].shape[0]
if rowsAvailable:
for x in range ( 0, rows):
for y in range(0, cols):
if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
imgArray[x][y] = cv.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv.cvtColor( imgArray[x][y], cv.COLOR_GRAY2BGR)
imageBlank = np.zeros((height, width, 3), np.uint8)
hor = [imageBlank]*rows
hor_con = [imageBlank]*rows
for x in range(0, rows):
hor[x] = np.hstack(imgArray[x])
ver = np.vstack(hor)
else:
for x in range(0, rows):
if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
imgArray[x] = cv.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
if len(imgArray[x].shape) == 2: imgArray[x] = cv.cvtColor(imgArray[x], cv.COLOR_GRAY2BGR)
hor= np.hstack(imgArray)
ver = hor
return ver

def getContours(img):
contours,hierarchy = cv.findContours(img,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_NONE)
for cnt in contours:
area = cv.contourArea(cnt) # 计算contour面积
# print(area)
if area > 500:
cv.drawContours(imgContour,cnt,-1,(255,0,0),9) # -1是画出所有contour
peri = cv.arcLength(cnt,True) # 计算曲线长度
# print(peri)
approx = cv.approxPolyDP(cnt,0.02*peri,True) # 拐点,中间值是分辨率
print(len(approx)) # 3是三角形,4是矩形,超过4的应该认为是圆形
objCor = len(approx) # object corners
x,y,w,h = cv.boundingRect(approx) # 边界框

if objCor == 3: objectType = "Tri"
elif objCor == 4:
aspRatio = w/float(h)
if aspRatio > 0.95 and aspRatio < 1.05: objectType = "Square"
else: objectType = "Rectangle"
elif objCor > 4: objectType = "Circle"
else: objectType = "None"
cv.rectangle(imgContour,(x,y),(x+w,y+h),(0,255,0),2)
cv.putText(imgContour,objectType,
(x+(w//2)-10,y+(h//2)-10),cv.FONT_HERSHEY_COMPLEX,
0.5,(0,0,0),2)

path = 'shapes2.png'
img = cv.imread(path)
imgContour = img.copy()

imgGray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
imgBlur = cv.GaussianBlur(imgGray,(7,7),1)
imgCanny = cv.Canny(imgBlur,50,50)

getContours(imgCanny)

imgBlank = np.zeros_like(img)
imgStack = stackImages(0.8,([img,imgGray,imgBlur],
[imgCanny,imgContour,imgBlank]))
cv.imshow('Stacked Image',imgStack)
cv.waitKey(0)

9 面部检测

Viola&Jones——第一个实时物体检测算法(2001)

一般内置数据集有这几个

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

faceCascade = cv.CascadeClassifier("/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_default.xml")
path = 'friends.jpg'
img = cv.imread(path)
imgGray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)

faces = faceCascade.detectMultiScale(imgGray,1.3,4)
for (x,y,w,h) in faces:
cv.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

cv.imshow('Original',img)
cv.waitKey(0)

Rachel的脸没有检测出来,应该是斜脸的原因,调了几次还是不行,看来要换数据集才行。


本文作者: Shixin
本文链接: https://physxz.github.io/posts/10014/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!