OpenCV(未完结)📷️🩻
还差几个小项目,以及还要解决屏幕录制转gif问题
编程环境配置
- pycharm
- 在终端中使用安装opencv
shell
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple
OpenCV基础内容学习
chapter1
test1 读取png等图片文件
python
import cv2
import numpy as np
# test1 读取png等图片文件
img = cv2.imread("Resources/lena.png")
cv2.imshow("Lena", img)
cv2.waitKey(0)
test2 读取mp4等视频文件
python
import cv2
import numpy as np
# test2 读取mp4等视频文件
cap = cv2.VideoCapture("Resources/test_video.mp4")
while True:
success, img = cap.read()
cv2.imshow("Video", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
test3 捕获摄像头图像
python
import cv2
import numpy as np
# test3 捕获摄像头图像
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
cap.set(3, 640) # 3参数设置捕获图像的宽
cap.set(4, 480) # 4参数设置捕获图像的高
cap.set(10, 100) # 10参数设置图像亮度
while True:
success, img = cap.read() # read返回两个参数
cv2.imshow("Video", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
chapter2
test1 灰度转换、高斯模糊、边缘检测、扩张、腐蚀
python
import cv2
import numpy as np
from Stack import stackImages
# test4 灰度转换、高斯模糊、边缘检测、扩张、腐蚀
img = cv2.imread("Resources/lena.png")
# 5×5内核,
kernel = np.ones((5, 5), np.uint8)
# 由RGB三通道变为灰度单通道灰度图像
imgGray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY)
# 高斯模糊
imgBlur = cv2.GaussianBlur(imgGray, (7, 7), 0)
# Canny边缘检测
imgCanny = cv2.Canny(img, 100, 100)
# 扩张。算法:内核下的至少一个像素为1,则像素元素为1。iteration:迭代次数
imgDilation = cv2.dilate(imgCanny, kernel, iterations=1)
# 腐蚀。算法:内核中所有像素为1,则像素元素为1
imgEroded = cv2.erode(imgDilation, kernel, iterations=1)
Stack = stackImages(0.5, ([img, imgGray, imgBlur],
[imgCanny, imgDilation, imgEroded]))
cv2.imshow("Stack Image", Stack)
# cv2.imshow("Gray Image", imgGray)
# cv2.imshow("Blur Image", imgBlur)
# cv2.imshow("Canny Image", imgCanny)
# cv2.imshow("Dilation Image", imgDilation)
# cv2.imshow("Eroded Image", imgEroded)
cv2.waitKey(0)
chapter3
test1 对图像做拉伸、裁剪处理
python
import cv2
import numpy as np
# test1 对图像做拉伸、裁剪处理
img = cv2.imread("Resources/lambo.PNG")
imgResize = cv2.resize(img, (300, 200))
imgCropped = img[0:200, 200:500]
cv2.imshow("Image", img)
cv2.imshow("Image Resize", imgResize)
cv2.imshow("Image Cropped", imgCropped)
print(img.shape)
print(imgResize.shape)
print(imgCropped.shape)
cv2.waitKey(0)
chapter4
test1 在图像上绘制简单图形
python
import cv2
import numpy as np
# test1 在图像上绘制简单图形
img = np.zeros((512, 512, 3), np.uint8)
print(img.shape)
# 根据img数组绘制矩形
# img[200:300, 100:300] = 255, 0, 0
# 绘制线line(img, (x1,y1), (x2,y2), (B,G,R), channel)
cv2.line(img, (0, 0), (300, 300), (0, 255, 0), 3)
# 绘制矩形rectangle(img, (x1,y1), (x2,y2), (R,G,B), width(填充:cv2.FILLED))
cv2.rectangle(img, (0, 0), (250, 350), (0, 0, 255), 2)
# 绘制圆形circle(img, (x0,y0), R, (B,G,R), width)
cv2.circle(img, (400, 400), 40, (255, 255, 0), 2)
# 绘制文本putText(img, "your_string", (x0,y0), cv2.FONT, scale, (B,G,R), width)
# (x0, y0)是字体的左下角坐标
cv2.putText(img, "OPEN CV", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 150, 0), 5)
cv2.imshow("Image", img)
cv2.waitKey(0)
chapter5
test 将图片做拉伸变换,透视变换
python
import cv2
import numpy as np
# test 将图片做拉伸变换,透视变换
img = cv2.imread("Resources/cards.jpg")
width, height = 250, 350
# src_points (x, y) 中,x 表示从左到右的水平位置,y 表示从上到下的垂直位置。
pts1 = np.float32([[111, 219], [297, 188], [154, 482], [352, 440]])
# dst_points (x, y) 中,x 表示从左到右的水平位置,y 表示从上到下的垂直位置。
pts2 = np.float32([[0, 0], [width, 0], [0, height], [width, height]])
# 计算得到透视变换矩阵
matrix = cv2.getPerspectiveTransform(pts1, pts2)
# 将源图像应用透视变换矩阵M,并生成新的图像,它根据目标图像的尺寸来输出。
imgOutput = cv2.warpPerspective(img, matrix, (width, height))
print(matrix)
cv2.imshow("Image", img)
cv2.imshow("Output", imgOutput)
cv2.waitKey(0)
chapter6
test 将图片进行排列分布
python
import cv2
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] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv2.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] = cv2.cvtColor(imgArray[x][y], cv2.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] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)
if len(imgArray[x].shape) == 2:
imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
hor = np.hstack(imgArray)
ver = hor
return ver
python
import cv2
import numpy as np
from Stack import stackImages
# test 将图片进行排列分布
img = cv2.imread("Resources/lena.png")
imgHor = np.hstack((img, img))
imgVer = np.vstack((img, img))
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgStack = stackImages(0.5, ([img, imgGray, img], [img, img, img]))
cv2.imshow("Horizontal", imgHor)
cv2.imshow("Vertical", imgVer)
cv2.imshow("ImgStack", imgStack)
cv2.waitKey(0)
chapter7
test1
python
import cv2
import numpy as np
from Stack import stackImages
def empty(a):
pass
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 640, 240)
cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, empty)
cv2.createTrackbar("Hue Max", "TrackBars", 19, 179, empty)
cv2.createTrackbar("Sat Min", "TrackBars", 110, 255, empty)
cv2.createTrackbar("Sat Max", "TrackBars", 240, 255, empty)
cv2.createTrackbar("Val Min", "TrackBars", 153, 255, empty)
cv2.createTrackbar("Val Max", "TrackBars", 255, 255, empty)
path = "Resources/lambo.PNG"
while True:
img = cv2.imread(path)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
print(h_min, h_max, s_min, s_max, v_min, v_max)
mask = cv2.inRange(imgHSV, lower, upper)
imgResult = cv2.bitwise_and(img, img, mask=mask)
# cv2.imshow("Original", img)
# cv2.imshow("HSV", imgHSV)
# cv2.imshow("Mask", mask)
# cv2.imshow("Result", imgResult)
imgStack = stackImages(0.6, ([img, imgHSV], [mask, imgResult]))
cv2.imshow("Stacked Images", imgStack)
cv2.waitKey(1)
chapter8
test 寻找图像的轮廓, 并框住整个图像
python
import cv2
import numpy as np
from Stack import stackImages
# test 寻找图像的轮廓, 并框住整个图像
def getContours(img):
# contours:轮廓的列表,hierarchy:轮廓的层次结构
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
i = 1
for cnt in contours:
print("##############CONTOUR", i)
area = cv2.contourArea(cnt)
print("area:", area)
if area > 500:
cv2.drawContours(imgContour, cnt, -1, (255, 0, 0), 2)
peri = cv2.arcLength(cnt, True)
print("peri:", peri)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
print(len(approx))
objCor = len(approx)
x, y, w, h = cv2.boundingRect(approx)
if objCor == 3:
objectType = "Triangle"
elif objCor == 4:
aspRatio = w / float(h)
if aspRatio > 0.95 and aspRatio < 1.05:
objectType = "Square"
else:
objectType = "Rectangle"
elif objCor >= 8:
objectType = "Circle"
else:
objectType = "None"
cv2.rectangle(imgContour, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(imgContour, objectType,
(x + (w // 2) - 10, y + (h // 2) - 10),
cv2.FONT_HERSHEY_COMPLEX, 0.6,
(0, 0, 0), 1)
i += 1
path = "Resources/shapes.png"
img = cv2.imread(path)
imgContour = img.copy()
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgBlur = cv2.GaussianBlur(imgGray, (7, 7), 1)
imgCanny = cv2.Canny(imgBlur, 50, 50)
getContours(imgCanny)
imgBlank = np.zeros_like(img)
imgStack = stackImages(0.6, ([img, imgGray, imgBlur],
[imgCanny, imgContour, imgBlank]))
cv2.imshow("Stack Images", imgStack)
cv2.waitKey(0)
chapter9
test1 图像捕获人脸
python
faceCascade = cv2.CascadeClassifier("Resources/haarcascade_frontalface_default.xml")
img = cv2.imread("Resources/lena.png")
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(imgGray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.imshow("Result", img)
cv2.waitKey(0)
test2 摄像头捕获人脸
python
import cv2
import numpy as np
# test2 摄像头捕获人脸
faceCascade = cv2.CascadeClassifier("Resources/haarcascade_frontalface_default.xml")
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
cap.set(3, 640) # 3参数设置捕获图像的宽
cap.set(4, 480) # 4参数设置捕获图像的高
cap.set(10, 100) # 10参数设置图像亮度
while True:
success, img = cap.read() # read返回两个参数
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(imgGray, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.imshow("Result", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
主要函数介绍
cv2.waitKey()
函数原型
cv2.waitKey([delay])
是 OpenCV 中用于等待键盘事件的一个函数。它的主要作用是暂停程序的执行,等待指定时间内的按键输入,并返回按键的 ASCII 码。- delay: 这是一个可选参数,指定等待的时间(单位为毫秒)。如果设置为正值,函数会等待指定的时间。如果设置为 0,则表示函数会一直等待,直到按下某个键为止。
返回值
- 如果在指定的 delay 时间内按下了键,
waitKey()
返回按键的 ASCII 码(或者对于某些键,它返回特定的整数值)。 - 如果在 delay 时间内没有按下任何键,则返回 -1。
用途
- 控制窗口关闭:通常与
cv2.imshow()
配合使用,cv2.waitKey()
可以使窗口在一定时间内保持显示,或者等待用户按下某个键后关闭。 - 键盘事件:可以通过返回的 ASCII 码判断用户按下了哪个键,从而执行相应的操作。
cv2.VideoCapture()
函数原型
cv2.VideoCapture()
是 OpenCV 中用于从视频文件、摄像头或其他视频流源中读取视频帧的一个函数。它是 OpenCV 中视频处理的基础,可以帮助你从多种源(比如本地文件、摄像头、网络视频流等)读取视频。
基本用法
- 从视频文件中读取
cap = cv2.VideoCapture('video.mp4')
创建一个 VideoCapture 对象,传入视频文件的路径cap.read()
方法返回两个值:ret 和 frame。ret 是一个布尔值,表示帧是否读取成功;frame 是当前帧的图像(以 NumPy 数组的形式)。cap.isOpened()
可以检查 VideoCapture 是否成功打开。如果返回 False,说明打开失败。
- 从摄像头中读取
函数原型
cap = cv2.VideoCapture(index, apiPreference)
参数解析
index
:这是一个设备索引,用来指定你想打开的摄像头或视频设备。通常:0:表示默认的摄像头。如果你的计算机有多个摄像头,0 通常是第一个(内置摄像头或者外接的第一个摄像头)。如果你有多个摄像头,1, 2, 等可能是其他摄像头的索引。apiPreference
:这个参数是可选的,用来指定你想要使用的后端接口。OpenCV 支持多种视频捕获后端,常见的有:cv2.CAP_ANY
:自动选择合适的后端。cv2.CAP_DSHOW
:使用 Windows DirectShow 后端,这通常在 Windows 系统上对摄像头的支持较好。cv2.CAP_FFMPEG
:使用 FFmpeg 后端,支持各种格式的视频文件。cv2.CAP_GSTREAMER
:使用 GStreamer 后端,常用于 Linux 系统。cv2.CAP_V4L2
:在 Linux 系统上使用 Video4Linux2 后端。
cap设置
cap.set(propId, value)
- propId:这是一个属性标识符,指定你想要设置的属性。例如,分辨率、帧率、亮度等。OpenCV 中有一组常见的属性标识符,你可以用它们来配置捕获设备。
- value:这是你想要设置的属性值,具体值依赖于 propId。例如,如果你设置的是帧率,value 就是一个数值,表示帧率的大小。
属性 | propId 值 | 说明 |
---|---|---|
帧宽度 | cv2.CAP_PROP_FRAME_WIDTH | 设置视频帧的宽度。 |
帧高度 | cv2.CAP_PROP_FRAME_HEIGHT | 设置视频帧的高度。 |
帧率 | cv2.CAP_PROP_FPS | 设置视频的帧率(即每秒多少帧)。 |
曝光 | cv2.CAP_PROP_EXPOSURE | 设置摄像头的曝光值。 |
亮度 | cv2.CAP_PROP_BRIGHTNESS | 设置摄像头的亮度值。 |
对比度 | cv2.CAP_PROP_CONTRAST | 设置摄像头的对比度值。 |
饱和度 | cv2.CAP_PROP_SATURATION | 设置摄像头的饱和度值。 |
色调 | cv2.CAP_PROP_HUE | 设置摄像头的色调。 |
镜像翻转(左右翻转) | cv2.CAP_PROP_FLIP | 设置是否启用镜像翻转,值为0表示不翻转,1表示翻转。 |
OpenCV小项目学习
恭喜你🎉,你已经学会了OpenCV的基础知识和内置函数使用方法,让我们再来完成一点小项目吧!
Project1 颜色轨迹
项目概述
在视频画面或摄像头捕获画面中会出现一些特定的颜色,要求绘制出画面中特定颜色的运动轨迹
实现思路
实现代码
python
import cv2
import numpy as np
frameWidth = 640
frameHeight = 480
# 捕获摄像头
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
cap.set(3, frameWidth) # 3参数设置捕获图像的宽
cap.set(4, frameHeight) # 4参数设置捕获图像的高
cap.set(10, 150) # 10参数设置图像亮度
# [pink, blue, green] 使用chapter7的HSV模型,捕获粉,蓝,绿三个颜色的lower, upper
myColors = [[137, 121, 137, 168, 247, 255],
[59, 233, 105, 103, 255, 255],
[47, 106, 153, 97, 240, 247]]
# [pink, blue, green] 存储三种颜色的BGR,用于绘制圆圈
myColorValues = [[214, 112, 218],
[225, 105, 65],
[87, 201, 0]]
# 存储圆圈数组,实现轨迹效果
myPoints = [] # [x, y, colorId]
# 找出画面中myColors的轮廓,添加对应颜色的Points
def findColor(img, myColors, myColorValues):
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
count = 0
newPoints = []
for color in myColors:
lower = np.array(color[0:3])
upper = np.array(color[3:6])
mask = cv2.inRange(imgHSV, lower, upper) # 得到该颜色的蒙版
x, y = getContours(mask) # 得到蒙版的外部轮廓的中上方的点
# cv2.imshow(str(color[0]), mask)
# cv2.circle(imgResult, (x, y), 10, myColorValues[count], cv2.FILLED)
if x != 0 and y != 0:
newPoints.append([x, y, count])
count += 1
return newPoints
# 返回轮廓中上位置的点
def getContours(img):
# contours:轮廓的列表,hierarchy:轮廓的层次结构
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
x, y, w, h = 0, 0, 0, 0
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 500:
cv2.drawContours(imgResult, cnt, -1, (255, 0, 0), 2)
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
x, y, w, h = cv2.boundingRect(approx)
return x + w // 2, y
# 将myPoints数组的的所有点都绘制出来
def drawOnCanvas(myPoints, myColorValues):
for point in myPoints:
cv2.circle(imgResult, (point[0], point[1]), 10, myColorValues[point[2]], cv2.FILLED)
while True:
success, img = cap.read() # read返回两个参数
imgResult = img.copy()
newPoints = findColor(img, myColors, myColorValues)
# 键盘输入R,重置轨迹,方便测试
if cv2.waitKey(1) & 0xFF == ord('r'):
myPoints = []
if len(newPoints) != 0:
for newP in newPoints:
myPoints.append(newP)
if len(myPoints) != 0:
drawOnCanvas(myPoints, myColorValues)
cv2.imshow("Video", imgResult)
if cv2.waitKey(1) & 0xFF == ord('q'):
break