OpenCV项目实战

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

跟着YouTube大佬学了几个实战项目。

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
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
# project1 virtual paint
import cv2 as cv
import numpy as np

frameWidth = 640
frameHeight = 480

ipCameraUrl = 'http://zhao:raspberrypi@192.168.156.93:8081/'
cap = cv.VideoCapture(ipCameraUrl)
cap.set(3,frameWidth)
cap.set(4,frameHeight)
cap.set(10,50)

myColors = [[10,122,159,43,255,255],
[0,137,146,10,255,255],
[131,102,88,165,255,255]]
myColorValues = [[0,200,255],[60,0,255],[255,150,255]] # BGR

myPoints = [] # [x,y,colorID]

def findColor(img,myColors,myColorValues):
imgHSV = cv.cvtColor(img,cv.COLOR_BGR2HSV)
count = 0
newPoints = []
for color in myColors:
lower = np.array(color[0:3])
upper = np.array(color[3:6])
mask = cv.inRange(imgHSV,lower,upper)
x,y = getContours(mask)
cv.circle(imgResult,(x,y),10,myColorValues[count],cv.FILLED)
# cv.imshow(str(color[0]),mask)
if x!= 0 and y != 0:
newPoints.append([x,y,count])
count += 1
return newPoints

def getContours(img):
contours,hierarchy = cv.findContours(img,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_NONE)
x,y,w,h = 0,0,0,0
for cnt in contours:
area = cv.contourArea(cnt) # 计算contour面积
if area > 500:
# cv.drawContours(imgResult,cnt,-1,(255,0,0),9) # -1是画出所有contour
peri = cv.arcLength(cnt,True) # 计算曲线长度
approx = cv.approxPolyDP(cnt,0.02*peri,True) # 拐点,中间值是分辨率
x,y,w,h = cv.boundingRect(approx) # 边界框
return x+w//2,y

def drawOnCanvas(myPoints,myColorValues):
for point in myPoints:
cv.circle(imgResult,(point[0],point[1]),10,myColorValues[point[2]],cv.FILLED)

while True:
success,img = cap.read()
imgResult = img.copy()
newPoints = findColor(img,myColors,myColorValues)
if len(newPoints) != 0:
for newP in newPoints:
myPoints.append(newP)
if len(myPoints) != 0:
drawOnCanvas(myPoints,myColorValues)

cv.imshow("Original",imgResult)
if cv.waitKey(1) & 0xFF == ord('q'):
break

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
77
78
79
# project1 color picker
import cv2 as cv
import numpy as np

frameWidth = 640
frameHeight = 480
ipCameraUrl = 'http://zhao:raspberrypi@192.168.156.93:8081/'
cap = cv.VideoCapture(ipCameraUrl)
cap.set(3,frameWidth)
cap.set(4,frameHeight)

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

[0,84,180,15,255,255]
cv.namedWindow('TrackBars')
cv.resizeWindow('TrackBars', 640, 240)
cv.createTrackbar('Hue Min', 'TrackBars', 0, 179, empty)
cv.createTrackbar('Hue Max', 'TrackBars', 15, 179, empty)
cv.createTrackbar('Sat Min', 'TrackBars', 84, 255, empty)
cv.createTrackbar('Sat Max', 'TrackBars', 255, 255, empty)
cv.createTrackbar('Val Min', 'TrackBars', 180, 255, empty)
cv.createTrackbar('Val Max', 'TrackBars', 255, 255, empty)

while True:
success,img = cap.read()
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)
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
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# project2 document scanner
import cv2 as cv
import numpy as np

widthImg = 640
heightImg = 480

ipCameraUrl = 'http://zhao:raspberrypi@192.168.156.93:8081/'
cap = cv.VideoCapture(ipCameraUrl)
cap.set(3,widthImg)
cap.set(4,heightImg)
cap.set(10,50)

def preProcessing(img):
imgGray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
imgBlur = cv.GaussianBlur(imgGray,(5,5),1)
imgCanny = cv.Canny(imgBlur,200,200)
kernel = np.ones((5,5))
imgDial = cv.dilate(imgCanny,kernel,iterations=2)
imgThres = cv.erode(imgDial,kernel,iterations=1)
return imgThres

def getContours(img):
biggest = np.array([])
maxArea = 0
contours,hierarchy = cv.findContours(img,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_NONE)
for cnt in contours:
area = cv.contourArea(cnt) # 计算contour面积
if area > 5000:
# cv.drawContours(imgContour,cnt,-1,(255,0,0),9) # -1是画出所有contour
peri = cv.arcLength(cnt,True) # 计算曲线长度
approx = cv.approxPolyDP(cnt,0.02*peri,True) # 拐点,中间值是分辨率
if area > maxArea and len(approx) == 4:
biggest = approx
maxArea = area
cv.drawContours(imgContour,biggest,-1,(255,0,0),20) # -1是画出所有contour
return biggest

def reorder(myPoints):
myPoints = myPoints.reshape((4,2))
myPointsNew = np.zeros((4,1,2),np.int32)
add = myPoints.sum(1)
# print("add",add)

myPointsNew[0] = myPoints[np.argmin(add)]
myPointsNew[3] = myPoints[np.argmax(add)]
diff = np.diff(myPoints,axis=1)
myPointsNew[1] = myPoints[np.argmin(diff)]
myPointsNew[2] = myPoints[np.argmax(diff)]
# print("NewPoints",myPointsNew)
return myPointsNew

def getWarp(img,biggest):
biggest = reorder(biggest)
# print(biggest)
pts1 = np.float32(biggest)
pts2 = np.float32([[0,0],[widthImg,0],[0,heightImg],[widthImg,heightImg]])
matrix = cv.getPerspectiveTransform(pts1,pts2)
imgOutput = cv.warpPerspective(img,matrix,(widthImg,heightImg))
imgCropped = imgOutput[15:imgOutput.shape[0]-15,15:imgOutput.shape[1]-15]
imgCropped = cv.resize(imgCropped,(widthImg,heightImg))
return imgCropped

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

while True:
success,img = cap.read()
img = cv.resize(img,(widthImg,heightImg))
imgContour = img.copy()
imgThres = preProcessing(img)
biggest = getContours(imgThres)
if biggest.size != 0:
# print(biggest)
imgWarped = getWarp(img,biggest)
else:
imgArray = ([img,imgThres],[img,img])

imgArray = ([img,imgThres],[imgContour,imgWarped])
stackedImages = stackImages(0.6,imgArray)

cv.imshow("WorkFlow",stackedImages)
cv.imshow("Warped Image",imgWarped)
if cv.waitKey(1) & 0xFF == ord('q'):
break

3 车牌检测

图片来源网络,侵删。

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
# project3 number plate detection
import cv2 as cv
import numpy as np

##########################################
widthImg = 640
heightImg = 480
path = "/usr/local/share/opencv4/haarcascades/haarcascade_russian_plate_number.xml"
nplateCascade = cv.CascadeClassifier(path)
miniArea = 500
color = (255,0,255)
##############################################

ipCameraUrl = 'http://zhao:raspberrypi@192.168.156.93:8081/'
cap = cv.VideoCapture(ipCameraUrl)
cap.set(3,widthImg)
cap.set(4,heightImg)
cap.set(10,50)
count = 0

while True:
success,img = cap.read()

imgGray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
nymberPlates = nplateCascade.detectMultiScale(imgGray,1.3,4)
for (x,y,w,h) in nymberPlates:
area = w*h
if area > miniArea:
cv.rectangle(img,(x,y),(x+w,y+h),(255,0,255),2)
cv.putText(img,"Number Plate",(x,y-5),cv.FONT_HERSHEY_COMPLEX_SMALL,1,color,2)
imgRoi = img[y:y+h,x:x+w] # region of interest
cv.imshow("Roi",imgRoi)

cv.imshow("Original",img)
if cv.waitKey(1) & 0xFF == ord('s'):
cv.imwrite("./Scanned/NoPlate_"+str(count)+".jpg",imgRoi)
cv.rectangle(img,(0,200),(640,300),(0,255,0),cv.FILLED)
cv.putText(img,"Sacn Saved",(150,265),cv.FONT_HERSHEY_DUPLEX,2,(0,0,255),2)
cv.imshow("Result",img)
cv.waitKey(500)
count += 1

4 手部跟踪

使用框架是Google开发的MediaPipe。以Python包使用mediapipe只需要运行

1
pip install mediapipe

手部跟踪需要完成两部分动作:

  • 手掌检测

  • 关键点标识

    给出的手部关键点有21个,为了给出这21个关键点,团队手动标记了30000张不同的手部图片用于训练。

1

5 机械手臂

很好的一个融合Arduino和OpenCV的项目。


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