引言
一名视觉入门选手,在校生大一,了解OpenCV的皮毛。撰写此文,一是为了分享内容,帮助后来人;二更是为了能吸引大佬能给我提出我在学习上的建议和问题。
说明
环境:树莓派5 官方操作系统Raspberry Pi OS OpenCV Python语言 CSI500万摄像头
内容:树莓派5安装OpenCV,调用CSI摄像头,OpenCV简单图像处理
安装OpenCV
python3-opencv安装
终端下尝试:
sudo apt install libopencv-dev python3-opencv
若出现安装到98%左右出现问题,终端尝试尝试:
sudo apt-get update
sudo apt-get upgrade
此也可以尝试,但如果树莓派OS装了chrome浏览器可能会非常非常慢
安装解压完成后(自动),LX终端输入python
进入python命令页面后,输入
import cv2 cv2.__version__ # 打印出版本号
若无报错即安装完成
查看当前opencv版本
终端输入:
pkg-config --modversion opencv4
pkg-config opencv4 --libs
树莓派5摄像头调用
参考资料
!!重要说明:树莓派5在摄像头调用方面与4差异很大,CSI摄像头在pi4的python代码下无法在pi5上正常运行,本人在此方面浪费了好久,查询资料,找到了这几篇文章分享的非常好,尤其是DIY相机(二),对于picamera2库讲的挺详细的。
DIY相机(一)libcamera库 - 知乎 (zhihu.com)
DIY相机(二)picamera2库 - 知乎 (zhihu.com)
DIY相机(三)picamera2库手册解读 - 知乎 (zhihu.com)
CSI摄像头调用
完整代码:
import cv2
import numpy as np
import libcamera
from time import sleep
from picamera2 import Picamera2
picam2 = Picamera2()
config=picam2.create_preview_configuration(main={"format":'RGB888',"size":(640,480)},
raw={"format":'SRGGB12',"size":(1920,1080)})
config["transform"] = libcamera.Transform(hflip = 0, vflip = 1)
picam2.configure(config)
picam2.start()
while True:
frame = picam2.capture_array()
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q')
break
sleep(0.01)
cv2.destroyAllWindows()
这里偷懒了,time是可以不调用的,包括结尾的sleep。
摄像头的main流{“format”:‘RGB888’},勿看错,size可有可无,只是对摄像头的视野有影响,raw流本人了解不深,但尝试过了,没有它也没关系。
config["transform"]行是修改摄像头的水平 or 垂直是否反转,0 or 1,可以自己尝试修改值,默认是hflip 和 vflip均为0,可以根据项目需要修改。
摄像头帧图像不再是VideoCapture(),采用的是capture_array()。
程序效果
运行后会有名叫frame的窗口,会实时显示frame变量,键盘上的“q”键按下,程序结束,清除所有窗口。具体的opencv代码后面会讲。
OpenCV
基于BSD许可开源发行得跨平台计算机视觉和机器学习软件库,可以运行在Linux,Windows,Android,Mac操作系统上。
应用领域
人机互动,物体识别,图像分割,人脸识别,动作识别,动作跟踪
机器人,运动分析,机器视觉,结构分析,汽车安全驾驶等
入门
读入图像
使用函数 cv2.imread()
读入图像。这幅图像应该在此程序的工作路径,或 者给函数提供完整路径。 第二个参数是要告诉函数应该如何读取这幅图片。
cv.IMREAD_COLOR |
加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。 |
cv.IMREAD_GRAYSCALE |
以灰度模式加载图像。 |
cv.IMREAD_UNCHANGED |
加载图像,包括 alpha 通道。 |
注意:除了这三个标志,你可以分别简单地传递整数 1、0 或-1。
警告:就算图像的路径是错的,OpenCV 也不会提醒你的,但是当你使用命令 print img 时得到的结果是 None
显示图像
使用函数cv2.imshow()
显示图像。窗口会自动调整为图像大小。
第一个参数是窗口的名字。
第二个其次才是我们的图像。
你可以创建多个窗口,但是必须给他们不同的名字。
cv2.waitKey()
是一个键盘绑定函数。
需要指出的是它的时间尺度是毫秒级。 函数等待特定的几毫秒,看是否有键盘输入。
特定的几毫秒之内,如果按下任意键,这个函数会返回按键的 ASCII 码值,程序将会继续运行。
如果没有键盘输 入,返回值为 -1。
如果我们设置这个函数的参数为 0,那它将会无限期的等待键盘输入。
它也可以被用来检测特定键是否被按下,例如按键 q 是否被按下,
cv2.destroyAllWindows()
可以轻易删除任何我们建立的窗口。
如果你想删除特定的窗口可以使用cv2.destroyWindow()
,在括号内输入你想删除的窗口名。
保存图像
使用函数 cv2.imwrite() 来保存一个图像。首先需要一个文件名,之后才是 你要保存的图像。
用的少,我也不详细说了,具体的可以自行搜索。
图像操作
RGB三原色 0~255
OpenCV中反过来,BGR,注意顺序!
特征点的提取
import cv2
image = cv2.imread("cd../opencv_logo.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转化为灰度图
corners = cv2.goodFeaturesToTrack(gray, 500, 0.1, 10)
# 获取特征点,最多返回500个,点的质量优于0.1,特征点距离大于10像素
for corner in corners:
x, y = corner.ravel()
cv2.circle(image, (int(x), int(y)), 3, (255, 0, 255), -1)
# 遍历特征点,标记颜色
cv2.imshow("corners", image)
cv2.waitKey()
模板匹配
import cv2
import numpy as np
image = cv2.imread("cd../poker.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
template = gray[75:105, 235:265] # 选取图片的某个区域作为模板,此索引范围是一个菱形
match = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)# 标准相关匹配算法
locations = np.where(match >= 0.9)# 找出匹配度大于0.9的点集
w, h = template.shape[0:2]
for p in zip(*locations[::-1]):
x1, y1 = p[0], p[1]
x2, y2 = x1 + w, y1 + h
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)# 框选
cv2.imshow("image", image)
cv2.waitKey()
图像梯度算法
Canny边缘检测算法
在灰度图下进行的一种图像操作
cv2.Canny(gray, 100, 200)
像素亮度(0~255 : 黑 ~ 白)。梯度的方向与边缘的方向是垂直的。,边缘检测算子返回水平方向的Gx和垂直方向的Gy。
cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
-
image 为 8 位输入图像
-
threshold1 表示处理过程中的第一个阈值。
-
threshold2 表示处理过程中的第二个阈值。
-
apertureSize 表示 Sobel 算子的孔径大小。
-
L2gradient 为计算图像梯度幅度(gradient magnitude)的标识。其默认值为 False。如果为 True,则使用更精确的 L2 范数进行计算(即两个方向的导数的平方和再开方),否则使用 L1 范数(直接将两个方向导数的绝对值相加)。
当函数 cv2.Canny()的参数 threshold1 和 threshold2 的值较小时,能够捕获更多的边缘信息。
Laplacian
拉普拉斯算子是图像邻域内像素灰度差分计算的基础,通过二阶微分推导出的一种图像邻域增强算法。它的基本思想是当邻域的中心像素灰度低于它所在邻域内的其他像素的平均灰度时,此中心像素的灰度应该进一步降低;当高于时进一步提高中心像素的灰度,从而实现图像锐化处理。 在算法实现过程中,通过对邻域中心像素的四方向或八方向求梯度,并将梯度和相加来判断中心像素灰度与邻域内其他像素灰度的关系,并用梯度运算的结果对像素灰度进行调整。
cv2.Laplacian(src,ddepth[,ksize[,scale[,delta[,borderType]]]])
-
src代表原始图像。
-
ddepth代表目标图像的深度。
-
ksize代表用于计算二阶导数的核尺寸大小。值必须是正的奇数。当ksize的值为1时,Laplacian算子计算时采用的3×3计算方法。
-
scale代表计算Laplacian值的缩放比例因子,该参数是可选的。默认情况下,该值为 1,表示不进行缩放。
-
delta代表加到目标图像上的可选值,默认为0。
-
borderType代表边界样式。
通常情况下,在使用Laplacian算子时,对于参数ksize、scale、delta和borderType,直接采用其默认值即可。
因此,函数的常用形式为:
dst=cv2.Laplacian(src,ddepth)
【数字图像处理】图像锐化【数字图像处理】图像锐化:拉普拉斯算子(Laplacian)、高通滤波、Sobel算子、Isotropic算子、Prewitt算子_拉普拉斯算子锐化-CSDN博客
图像梯度算法实例
Canny和Laplacian:
import cv2
gray = cv2.imread("cd../opencv_logo.jpg", cv2.IMREAD_GRAYSCALE)
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
canny = cv2.Canny(gray, 100, 200)
cv2.imshow("gray", gray)
cv2.imshow("laplacian", laplacian)
cv2.imshow("canny", canny)
cv2.waitKey()
阈值算法(二值化)
import cv2
gray = cv2.imread("cd../bookpage.jpg", cv2.IMREAD_GRAYSCALE)
ret, binary = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
# 10作为阈值,大于10的统一为白色,小于10的统一为黑色,整体亮度会变大
# 下面介绍另外两种相似算法:
# 1.对于光照不均匀的图片,很难选择一个固定的阈值,于是opencv提供了自适应阈值算法:将图像分为多个区域
# 每个区域都有自己合适的阈值
binary_adaptive = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)
# 2.otsu算法,自动计算合适的阈值,使得分离出的两个灰度分布差异最大
ret1, binary_otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imshow("gray", gray)
cv2.imshow("binary", binary)
cv2.imshow("adaptive", binary_adaptive)
cv2.imshow("otsu", binary_otsu)
cv2.waitKey()
巡线原理之一!
腐蚀与膨胀
形态学算法之腐蚀与膨胀操作
本节操作基于二值化后的图像
import cv2
import numpy as np
gray = cv2.imread("cd../opencv_logo.jpg", cv2.IMREAD_GRAYSCALE)
_, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
# 反向阈值,因为logo图中的背景为白色
kernel = np.ones((5, 5), np.uint8)# 5*5 像素方形
erosion = cv2.erode(binary, kernel)# 腐蚀
dilation = cv2.dilate(binary, kernel)# 膨胀
cv2.imshow("binary", binary)
cv2.imshow("erosion", erosion)
cv2.imshow("dilation", dilation)
cv2.waitKey()
#交替使用腐蚀和膨胀操作,可以获得更多形态学变化,比如打开/封闭图案中的空腔等
结尾
第一篇文章,可能对于CSDN的规矩还有些不懂,如果有版权侵犯私信可删除本贴,本人承诺所有应用的文章都仅用于个人学习了,本文也只是出于分享目的。
如果能帮到你记得点收藏哦,关注也是可以的。
如果有想提出问题或建议的,也欢迎评论区,万分感谢。