计算机视觉 | 人工智能 自己总结 (下)
目录
- 立体视觉
- 立体视觉的概念
- 视差信息的概念
- 立体匹配
- 目标检测和跟踪
- 三维重建
- 立体图像拼接
立体视觉
立体视觉的概念
立体视觉是指人类双眼所产生的深度感觉,也称为立体感或深度感。它是由于两只眼睛分别观察到同一物体的微小差异而产生的。
当两只眼睛看到同一物体时,它们分别从不同的角度观察该物体。这些微小的视角差异导致我们的大脑能够计算出物体的深度和距离,从而产生立体感。
立体视觉
也是一种计算机视觉技术,其目的是从两幅或两幅以上的图像中推理出图像中每个像素的深度信息
。
视差信息的概念
在立体视觉中,视差
是指两个视点(即左右摄像机)观察同一场景时,同一个空间点在两个图像上对应像素的水平位置之间的差值。视差信息
就是通过比较两个图像中对应像素之间的水平位置差异,计算出每个像素点的视差值。
视差信息
是立体视觉的重要信息,因为它可以用来计算像素点的深度或距离
,从而实现三维场景的重建、物体的检测与跟踪等。在立体视觉中,一般会将左右两个视点的图像分别称为左图和右图,通过匹配左右图像中对应像素的位置,得到每个像素点的视差信息
。
视差值越大,表示该像素点距离摄像机越近;
视差值越小,表示该像素点距离摄像机越远。
视差信息
的获取需要对左右两个视点的图像进行配准和匹配,通常会使用立体匹配算法
来实现。
立体匹配算法
的目标就是找到左右两个视点中对应像素之间的匹配关系,从而计算出视差信息。
立体匹配
概念:OpenCV提供了一些立体匹配算法,例如Semi-Global Block Matching(SGBM)和StereoSGBM算法,可以计算两张图片之间的视差,从而计算出物体的深度信息。
使用opencv实现立体视觉的示例代码:
import cv2
# 读入左右两张图像
img_left = cv2.imread('left.png')
img_right = cv2.imread('right.png')
# 转为灰度图像
gray_left = cv2.cvtColor(img_left, cv2.COLOR_BGR2GRAY)
gray_right = cv2.cvtColor(img_right, cv2.COLOR_BGR2GRAY)
# 定义SGBM算法参数
stereo = cv2.StereoSGBM_create(numDisparities=16, blockSize=15)
# 计算视差图
disparity = stereo.compute(gray_left, gray_right)
# 显示视差图
cv2.imshow('Disparity Map', disparity)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述示例代码中,我们使用OpenCV的StereoSGBM_create函数
创建了一个SGBM算法对象,并传入了numDisparities和blockSize
两个参数。然后,我们使用该算法对象计算了左右两张灰度图像的视差图
,并使用cv2.imshow函数显示了结果。需要注意的是,在实际使用中,我们通常会对算法参数进行调整以获取更好的匹配结果
。
目标检测和跟踪
目标检测和跟踪是计算机视觉领域中的重要研究方向,它们可以帮助计算机理解并处理图像或视频中的目标物体信息。
目标检测可以被视为一种分类问题,它的任务是在图像或视频中检测出特定类别的物体,并用边框框定它们的位置。常用的目标检测算法包括 Haar 级联分类器、基于深度学习的 Faster R-CNN、YOLO等。
跟踪算法则是基于目标检测结果的基础上,追踪物体在图像或视频中的位置,使得在物体移动或者遮挡的情况下,依然能够准确地追踪物体。常用的跟踪算法包括卡尔曼滤波、mean-shift 算法、correlation filters 算法等。
在 OpenCV 中,目标检测和跟踪都可以很方便地实现。下面是一个简单的示例代码,演示如何使用 OpenCV 中的 Haar 级联分类器来实现人脸检测,并使用追踪算法跟踪人脸运动轨迹:
import cv2
# 加载 Haar 级联分类器
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 初始化追踪器
tracker = cv2.TrackerCSRT_create()
# 打开视频
cap = cv2.VideoCapture(0)
# 读取第一帧图像
ret, frame = cap.read()
# 进行人脸检测
faces = face_cascade.detectMultiScale(frame, scaleFactor=1.3, minNeighbors=5)
# 对第一个人脸进行跟踪
if len(faces) > 0:
x, y, w, h = faces[0]
bbox = (x, y, w, h)
tracker.init(frame, bbox)
while True:
# 读取一帧图像
ret, frame = cap.read()
# 进行跟踪
success, bbox = tracker.update(frame)
# 根据跟踪结果绘制矩形框
if success:
x, y, w, h = [int(i) for i in bbox]
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2, 1)
else:
cv2.putText(frame, "Lost", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
# 显示结果
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
在该示例代码中,我们首先加载 Haar 级联分类器目标检测和跟踪是计算机视觉中的重要应用,其可以识别图像或视频中的目标,并对其进行跟踪和定位。其中,目标检测通常被定义为在图像或视频中检测出特定类别的目标,而目标跟踪则是在一个视频序列中跟踪一个物体的位置。
在OpenCV中,目标检测和跟踪通常是通过使用预训练的深度学习模型实现的。常见的模型包括基于单阶段的目标检测算法(例如YOLO和SSD)和基于两阶段的目标检测算法(例如Faster R-CNN和Mask R-CNN)。
以下是一个基于OpenCV和YOLOv3的目标检测示例代码:
import cv2
# 加载YOLOv3模型
net = cv2.dnn.readNetFromDarknet('yolov3.cfg', 'yolov3.weights')
classes = []
with open('coco.names', 'r') as f:
classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# 读取图像
img = cv2.imread('test.jpg')
# 获取图像宽高和通道数
height, width, channels = img.shape
# 对图像进行预处理
blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
# 输入预处理后的图像到网络中进行前向传播
net.setInput(blob)
outs = net.forward(output_layers)
# 解析网络输出,筛选出置信度高于0.5的检测结果
class_ids = []
confidences = []
boxes = []
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
# 使用非极大值抑制去除重叠框
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
# 在图像上绘制检测结果
font = cv2.FONT_HERSHEY_SIMPLEX
for i in range(len(boxes)):
if i in indexes:
x, y, w, h = boxes[i]
label = classes[class_ids[i]]
confidence = confidences[i]
color = (0, 255, 0)
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
cv2.putText(img, '{} {:.2f}'.format(label, confidence), (x, y - 5), font, 0.5, color, 1)
# 显示图像
cv2.imshow('Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
三维重建
三维重建是指将二维图像或点云数据转化为三维模型的过程。在计算机视觉领域,三维重建有着广泛的应用,如建筑、地图制作、文物修复等。
三维重建可以通过多种方式实现,如利用三角测量法,使用相机标定和立体匹配技术获取深度信息,利用光线投射法和点云数据生成三维模型等。其中,利用相机标定和立体匹配技术进行三维重建的方法被广泛应用。
opencv中的代码实现:
import cv2
import numpy as np
# 读入左右两张图像
img_left = cv2.imread('left.png')
img_right = cv2.imread('right.png')
# 转为灰度图像
gray_left = cv2.cvtColor(img_left, cv2.COLOR_BGR2GRAY)
gray_right = cv2.cvtColor(img_right, cv2.COLOR_BGR2GRAY)
# 定义SGBM算法参数
stereo = cv2.StereoSGBM_create(numDisparities=16, blockSize=15)
# 计算视差图
disparity = stereo.compute(gray_left, gray_right)
# 计算深度图
depth = cv2.convertScaleAbs(disparity, alpha=0.1)
# 根据内参和外参计算投影矩阵
K = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]])
R = np.array([[r11, r12, r13], [r21, r22, r23], [r31, r32, r33]])
t = np.array([[tx], [ty], [tz]])
P_left = np.dot(K, np.hstack((R, t)))
# 构建点云
points = []
for v in range(height):
for u in range(width):
# 计算点的三维坐标
x = (u - cx) * depth[v, u] / fx
y = (v - cy) * depth[v, u] / fy
z = depth[v, u]
# 投影到左相机坐标系
p = np.dot(R.T, np.array([[x], [y], [z]] - t))
points.append(p)
# 将点云转为numpy数组并保存为ply文件
points = np.array(points)
ply_header = 'ply\nformat ascii 1.0\nelement vertex %d\nproperty float x\nproperty float y\nproperty float z\nend_header\n' % len(points)
np.savetxt('point_cloud.ply', points, header=ply_header, comments='')
立体图像拼接
立体图像拼接是将两个或多个不同视角拍摄的图像拼接成一幅立体图像的过程。立体图像拼接可以用于创建更加逼真的三维场景,同时也可以用于医学影像处理和机器人视觉等领域。
立体图像拼接的主要步骤包括相机标定、立体匹配和图像融合。相机标定用于确定相机内外参数,立体匹配用于计算两个相机之间的视差信息,而图像融合则是将两个图像融合为一幅立体图像。
opencv中的代码实现:
import cv2
import numpy as np
# 读入左右两张图像
img_left = cv2.imread('left.png')
img_right = cv2.imread('right.png')
# 转为灰度图像
gray_left = cv2.cvtColor(img_left, cv2.COLOR_BGR2GRAY)
gray_right = cv2.cvtColor(img_right, cv2.COLOR_BGR2GRAY)
# 定义SGBM算法参数
stereo = cv2.StereoSGBM_create(numDisparities=16, blockSize=15)
# 计算视差图
disparity = stereo.compute(gray_left, gray_right)
# 计算视差映射
map_left, map_right = cv2.initUndistortRectifyMap(K_left, D_left, R_left, P_left, (width, height), cv2.CV_16SC2)
disparity_map = cv2.remap(disparity, map_left, map_right, cv2.INTER_LINEAR)
# 根据视差映射拼接图像
img_out = np.zeros_like(img_left)
for v in range(height):
for u in range(width):
# 计算右图像素坐标
x = u - disparity_map[v, u]
y = v
# 判断像素坐标是否在右图像范围内
if x >= 0 and x < width:
# 将左右像素拼接到输出图像中
img_out[y, u] = img_left[y, u]
img_out[y, x] = img_right[y, x]
# 显示结果图像
cv2.imshow('Stereo Image', img_out)
cv2.waitKey(0)
在上述示例代码中,我们首先使用OpenCV的StereoSGBM_create函数计算了左右两张灰度图像的视差图,并使用相机的内参和外参计算了视差映射。然后,我们根据视差映射将左右图像拼接到一起,得到了立体图像。