机器人视觉仿真软件:OpenCV_(12).机器人视觉系统设计与实现

机器人视觉系统设计与实现

在上一节中,我们已经介绍了如何使用OpenCV进行基本的图像处理和特征提取。本节将深入探讨机器人视觉系统的设计与实现,包括摄像头校准、目标检测、图像分割、深度学习模型的集成以及实时处理等方面的内容。通过本节的学习,你将能够设计并实现一个完整的机器人视觉系统,为机器人提供可靠的视觉感知能力。

摄像头校准

摄像头校准是机器人视觉系统中非常重要的一环,它能够消除相机的畸变,确保图像数据的准确性。OpenCV提供了一套完整的摄像头校准工具,可以帮助我们实现这一目标。

原理

摄像头校准的主要目的是确定相机的内参和外参。内参包括焦距、主点偏移等参数,外参包括相机相对于世界坐标系的位置和方向。通过校准,我们可以获取这些参数,从而在后续的图像处理中进行畸变校正和坐标变换。

内容

  1. 准备校准图像

  2. 检测角点

  3. 计算内参和外参

  4. 应用校正

1. 准备校准图像

为了进行摄像头校准,我们需要准备一系列校准图像。这些图像通常包含一个已知的棋盘格图案,因为棋盘格的角点位置是已知的,可以用来计算相机参数。


import cv2

import numpy as np

import glob



# 定义棋盘格的尺寸

chessboard_size = (9, 6)



# 准备角点的3D坐标

objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)

objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)



# 存储3D和2D点的向量

objpoints = []  # 3D点

imgpoints = []  # 2D点



# 加载校准图像

images = glob.glob('calibration_images/*.jpg')



for fname in images:

    img = cv2.imread(fname)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)



    # 寻找棋盘格角点

    ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)



    if ret:

        objpoints.append(objp)

        imgpoints.append(corners)



        # 绘制并显示角点

        cv2.drawChessboardCorners(img, chessboard_size, corners, ret)

        cv2.imshow('Chessboard', img)

        cv2.waitKey(500)



cv2.destroyAllWindows()

2. 检测角点

使用cv2.findChessboardCorners函数可以检测图像中的棋盘格角点。该函数返回一个布尔值ret,表示是否成功找到角点。如果找到角点,我们会将这些角点的3D坐标和2D坐标分别存储在objpointsimgpoints中。

3. 计算内参和外参

使用cv2.calibrateCamera函数可以计算相机的内参和外参。该函数需要输入3D和2D点的坐标,以及图像的尺寸。


# 计算内参和外参

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)



# 打印内参矩阵和畸变系数

print("内参矩阵:\n", mtx)

print("畸变系数:\n", dist)

4. 应用校正

使用cv2.undistort函数可以对图像进行畸变校正。该函数需要输入畸变校正后的内参矩阵和畸变系数。


# 应用畸变校正

for fname in images:

    img = cv2.imread(fname)

    h, w = img.shape[:2]

    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))



    dst = cv2.undistort(img, mtx, dist, None, newcameramtx)



    # 裁剪图像

    x, y, w, h = roi

    dst = dst[y:y+h, x:x+w]

    cv2.imwrite('calibrated_' + fname, dst)



    # 显示校正后的图像

    cv2.imshow('Calibrated', dst)

    cv2.waitKey(500)



cv2.destroyAllWindows()

代码解释

  1. 准备校准图像

    • chessboard_size定义了棋盘格的尺寸。

    • objp是棋盘格角点的3D坐标。

    • objpointsimgpoints分别存储3D和2D点的坐标。

    • glob模块用于加载校准图像。

  2. 检测角点

    • cv2.findChessboardCorners函数用于检测图像中的棋盘格角点。

    • cv2.drawChessboardCorners函数用于在图像中标记找到的角点。

  3. 计算内参和外参

    • cv2.calibrateCamera函数用于计算相机的内参和外参。

    • mtx是内参矩阵,dist是畸变系数。

  4. 应用校正

    • cv2.getOptimalNewCameraMatrix函数用于获取新的相机矩阵,以便在消除畸变时保持图像的分辨率。

    • cv2.undistort函数用于对图像进行畸变校正。

    • roi是校正后的图像的感兴趣区域,用于裁剪图像。

目标检测

目标检测是机器人视觉中的一项基本任务,用于识别和定位图像中的特定对象。OpenCV提供了多种目标检测算法,如HOG、SIFT、SURF等。本节将介绍如何使用这些算法进行目标检测。

原理

目标检测的基本原理是通过特征提取和匹配,识别图像中的特定对象。常见的特征提取方法包括HOG(方向梯度直方图)、SIFT(尺度不变特征变换)和SURF(加速稳健特征)等。这些特征提取方法可以帮助我们识别不同尺度和旋转下的目标。

内容

  1. 使用HOG进行目标检测

  2. 使用SIFT进行目标检测

  3. 使用SURF进行目标检测

1. 使用HOG进行目标检测

HOG(方向梯度直方图)是一种广泛用于目标检测的特征描述子。它通过计算图像中每个小区域的梯度方向直方图来描述对象的形状。


import cv2

import numpy as np



# 加载图像

img = cv2.imread('test_image.jpg')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)



# 初始化HOG描述子

hog = cv2.HOGDescriptor()

hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())



# 检测行人

found, w = hog.detectMultiScale(gray, winStride=(8, 8), padding=(32, 32), scale=1.05)



# 绘制检测结果

for (x, y, w, h) in found:

    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)



cv2.imshow('HOG Detection', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载图像

    • cv2.imread函数用于读取图像。

    • cv2.cvtColor函数用于将图像转换为灰度图像。

  2. 初始化HOG描述子

    • cv2.HOGDescriptor类用于创建HOG描述子。

    • cv2.HOGDescriptor_getDefaultPeopleDetector函数用于获取预训练的SVM检测器,用于检测行人。

  3. 检测行人

    • hog.detectMultiScale函数用于在图像中检测行人。

    • winStride参数表示滑动窗口的步长。

    • padding参数表示滑动窗口的填充。

    • scale参数表示图像金字塔的缩放比例。

  4. 绘制检测结果

    • cv2.rectangle函数用于在图像中标记检测到的行人。
2. 使用SIFT进行目标检测

SIFT(尺度不变特征变换)是一种用于图像特征提取和匹配的算法。它可以在不同的尺度和旋转下识别目标。


import cv2

import numpy as np



# 加载图像

img1 = cv2.imread('object_image.jpg', cv2.IMREAD_GRAYSCALE)

img2 = cv2.imread('scene_image.jpg', cv2.IMREAD_GRAYSCALE)



# 初始化SIFT检测器

sift = cv2.SIFT_create()



# 检测关键点和计算描述子

kp1, des1 = sift.detectAndCompute(img1, None)

kp2, des2 = sift.detectAndCompute(img2, None)



# 初始化FLANN匹配器

FLANN_INDEX_KDTREE = 1

index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)

search_params = dict(checks=50)

flann = cv2.FlannBasedMatcher(index_params, search_params)



# 进行特征匹配

matches = flann.knnMatch(des1, des2, k=2)



# 筛选匹配点

good_matches = []

for m, n in matches:

    if m.distance < 0.7 * n.distance:

        good_matches.append(m)



# 获取匹配点的坐标

src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)

dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)



# 计算单应性矩阵

M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)



# 获取目标边界

h, w = img1.shape

pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)

dst = cv2.perspectiveTransform(pts, M)



# 绘制匹配结果

img2 = cv2.polylines(img2, [np.int32(dst)], True, 255, 3, cv2.LINE_AA)

draw_params = dict(matchColor=(0, 255, 0), singlePointColor=None, matchesMask=mask.ravel().tolist(), flags=2)

img3 = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, **draw_params)



cv2.imshow('SIFT Detection', img3)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载图像

    • cv2.imread函数用于读取图像。

    • cv2.IMREAD_GRAYSCALE参数表示读取灰度图像。

  2. 初始化SIFT检测器

    • cv2.SIFT_create函数用于创建SIFT检测器。
  3. 检测关键点和计算描述子

    • sift.detectAndCompute函数用于检测关键点并计算描述子。
  4. 初始化FLANN匹配器

    • FLANN_INDEX_KDTREE表示使用KD树算法。

    • index_paramssearch_params分别用于配置FLANN匹配器的索引和搜索参数。

    • cv2.FlannBasedMatcher类用于创建FLANN匹配器。

  5. 进行特征匹配

    • flann.knnMatch函数用于进行特征匹配。

    • good_matches用于存储筛选后的匹配点。

  6. 获取匹配点的坐标

    • src_ptsdst_pts分别存储源图像和目标图像的匹配点坐标。
  7. 计算单应性矩阵

    • cv2.findHomography函数用于计算单应性矩阵。

    • cv2.RANSAC参数表示使用RANSAC算法进行鲁棒估计。

  8. 获取目标边界

    • cv2.perspectiveTransform函数用于计算目标的边界。
  9. 绘制匹配结果

    • cv2.polylines函数用于在图像中绘制目标边界。

    • cv2.drawMatches函数用于绘制匹配点。

3. 使用SURF进行目标检测

SURF(加速稳健特征)是SIFT的加速版本,适用于实时目标检测。它通过使用积分图像和快速近似算法来提高检测速度。


import cv2

import numpy as np



# 加载图像

img1 = cv2.imread('object_image.jpg', cv2.IMREAD_GRAYSCALE)

img2 = cv2.imread('scene_image.jpg', cv2.IMREAD_GRAYSCALE)



# 初始化SURF检测器

surf = cv2.xfeatures2d.SURF_create(400)



# 检测关键点和计算描述子

kp1, des1 = surf.detectAndCompute(img1, None)

kp2, des2 = surf.detectAndCompute(img2, None)



# 初始化FLANN匹配器

FLANN_INDEX_KDTREE = 1

index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)

search_params = dict(checks=50)

flann = cv2.FlannBasedMatcher(index_params, search_params)



# 进行特征匹配

matches = flann.knnMatch(des1, des2, k=2)



# 筛选匹配点

good_matches = []

for m, n in matches:

    if m.distance < 0.7 * n.distance:

        good_matches.append(m)



# 获取匹配点的坐标

src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)

dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)



# 计算单应性矩阵

M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)



# 获取目标边界

h, w = img1.shape

pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)

dst = cv2.perspectiveTransform(pts, M)



# 绘制匹配结果

img2 = cv2.polylines(img2, [np.int32(dst)], True, 255, 3, cv2.LINE_AA)

draw_params = dict(matchColor=(0, 255, 0), singlePointColor=None, matchesMask=mask.ravel().tolist(), flags=2)

img3 = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, **draw_params)



cv2.imshow('SURF Detection', img3)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载图像

    • cv2.imread函数用于读取图像。

    • cv2.IMREAD_GRAYSCALE参数表示读取灰度图像。

  2. 初始化SURF检测器

    • cv2.xfeatures2d.SURF_create函数用于创建SURF检测器。

    • 400参数表示检测器的阈值。

  3. 检测关键点和计算描述子

    • surf.detectAndCompute函数用于检测关键点并计算描述子。
  4. 初始化FLANN匹配器

    • FLANN_INDEX_KDTREE表示使用KD树算法。

    • index_paramssearch_params分别用于配置FLANN匹配器的索引和搜索参数。

    • cv2.FlannBasedMatcher类用于创建FLANN匹配器。

  5. 进行特征匹配

    • flann.knnMatch函数用于进行特征匹配。

    • good_matches用于存储筛选后的匹配点。

  6. 获取匹配点的坐标

    • src_ptsdst_pts分别存储源图像和目标图像的匹配点坐标。
  7. 计算单应性矩阵

    • cv2.findHomography函数用于计算单应性矩阵。

    • cv2.RANSAC参数表示使用RANSAC算法进行鲁棒估计。

  8. 获取目标边界

    • cv2.perspectiveTransform函数用于计算目标的边界。
  9. 绘制匹配结果

    • cv2.polylines函数用于在图像中绘制目标边界。

    • cv2.drawMatches函数用于绘制匹配点。

图像分割

图像分割是将图像划分为多个区域或对象的过程。在机器人视觉中,图像分割可以帮助我们更好地理解场景,识别不同的对象。OpenCV提供了多种图像分割算法,如阈值分割、区域生长、GrabCut等。本节将介绍如何使用这些算法进行图像分割。

原理

图像分割的基本原理是通过不同的特征(如颜色、纹理、边缘等)将图像划分为多个区域。每个区域代表一个特定的对象或背景。常见的图像分割方法包括阈值分割、区域生长、GrabCut等。

内容

  1. 阈值分割

  2. 区域生长

  3. GrabCut

1. 阈值分割

阈值分割是一种简单的图像分割方法,通过设置一个或多个阈值将图像中的像素划分为不同的区域。


import cv2

import numpy as np



# 加载图像

img = cv2.imread('test_image.jpg', cv2.IMREAD_GRAYSCALE)



# 应用阈值分割

ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)



# 显示结果

cv2.imshow('Thresholded Image', thresh)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载图像

    • cv2.imread函数用于读取图像。

    • cv2.IMREAD_GRAYSCALE参数表示读取灰度图像。

  2. 应用阈值分割

    • cv2.threshold函数用于对图像进行阈值分割。该函数需要输入图像、阈值、最大值和阈值类型。

    • 127是阈值,表示将像素值小于127的像素设为0(黑色),大于或等于127的像素设为255(白色)。

    • cv2.THRESH_BINARY表示使用二值化阈值分割。

  3. 显示结果

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey函数用于等待用户按键,0表示无限等待。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

2. 区域生长

区域生长是一种基于像素相似性的图像分割方法。通过选择一个种子点,然后逐步将与种子点相似的像素添加到同一区域,最终形成一个完整的分割区域。


import cv2

import numpy as np



# 加载图像

img = cv2.imread('test_image.jpg', cv2.IMREAD_GRAYSCALE)



# 选择种子点

seed_point = (50, 50)



# 定义区域生长函数

def region_growing(image, seed, threshold=10):

    height, width = image.shape

    seed_value = image[seed[1], seed[0]]

    segmented = np.zeros_like(image)

    segmented[seed[1], seed[0]] = 255



    stack = [seed]

    while stack:

        x, y = stack.pop()

        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:

            nx, ny = x + dx, y + dy

            if 0 <= nx < width and 0 <= ny < height and segmented[ny, nx] == 0:

                if abs(int(image[ny, nx]) - int(seed_value)) < threshold:

                    segmented[ny, nx] = 255

                    stack.append((nx, ny))



    return segmented



# 应用区域生长

segmented = region_growing(img, seed_point)



# 显示结果

cv2.imshow('Region Growing', segmented)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载图像

    • cv2.imread函数用于读取图像。

    • cv2.IMREAD_GRAYSCALE参数表示读取灰度图像。

  2. 选择种子点

    • seed_point是一个元组,表示种子点的坐标。
  3. 定义区域生长函数

    • region_growing函数用于实现区域生长算法。

    • image是输入的灰度图像。

    • seed是种子点的坐标。

    • threshold是像素值相似性的阈值。

    • heightwidth分别表示图像的高度和宽度。

    • seed_value是种子点的像素值。

    • segmented是一个与输入图像相同大小的二维数组,用于存储分割后的图像。

    • stack是一个栈,用于存储待处理的像素点。

    • 通过遍历种子点周围的像素,如果像素值与种子点的像素值差小于阈值,则将其标记为同一区域,并将其添加到栈中,继续处理。

  4. 应用区域生长

    • region_growing函数被调用,传入图像和种子点,返回分割后的图像。
  5. 显示结果

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey函数用于等待用户按键,0表示无限等待。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

3. GrabCut

GrabCut是一种基于图割理论的交互式图像分割方法。它通过用户提供的矩形区域或种子点,自动分割出感兴趣的对象。


import cv2

import numpy as np



# 加载图像

img = cv2.imread('test_image.jpg')

mask = np.zeros(img.shape[:2], np.uint8)



# 定义前景和背景模型

bgd_model = np.zeros((1, 65), np.float64)

fgd_model = np.zeros((1, 65), np.float64)



# 选择感兴趣区域

rect = (50, 50, 300, 400)



# 应用GrabCut

cv2.grabCut(img, mask, rect, bgd_model, fgd_model, 5, cv2.GC_INIT_WITH_RECT)



# 提取前景

mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')

img = img * mask2[:, :, np.newaxis]



# 显示结果

cv2.imshow('GrabCut', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载图像

    • cv2.imread函数用于读取图像。

    • mask是一个与输入图像相同大小的二维数组,用于存储分割结果。

  2. 定义前景和背景模型

    • bgd_modelfgd_model分别用于存储背景和前景模型的初始值。
  3. 选择感兴趣区域

    • rect是一个元组,表示用户提供的矩形区域的坐标和尺寸。
  4. 应用GrabCut

    • cv2.grabCut函数用于进行图像分割。该函数需要输入图像、掩码、矩形区域、背景模型、前景模型、迭代次数和初始化方法。

    • 5表示迭代次数。

    • cv2.GC_INIT_WITH_RECT表示使用矩形区域进行初始化。

  5. 提取前景

    • mask2是一个二值掩码,用于提取前景区域。

    • img * mask2[:, :, np.newaxis]将前景区域与原图像相乘,得到分割后的前景图像。

  6. 显示结果

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey函数用于等待用户按键,0表示无限等待。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

深度学习模型的集成

深度学习模型在目标检测和图像分割等任务中表现出色。本节将介绍如何将深度学习模型集成到机器人视觉系统中,以提高系统的准确性和鲁棒性。

原理

深度学习模型通过学习大量的标注数据,可以自动提取图像中的特征并进行分类或分割。常见的深度学习模型包括卷积神经网络(CNN)、YOLO、Mask R-CNN等。这些模型可以用于检测和识别图像中的目标,以及分割图像中的不同区域。

内容

  1. 使用YOLO进行目标检测

  2. 使用Mask R-CNN进行实例分割

1. 使用YOLO进行目标检测

YOLO(You Only Look Once)是一种实时目标检测算法,通过一个单一的神经网络同时进行目标的分类和定位。


import cv2

import numpy as np



# 加载YOLO模型

net = cv2.dnn.readNet('yolov3.weights', 'yolov3.cfg')

layer_names = net.getLayerNames()

output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]



# 加载类别名称

with open('coco.names', 'r') as f:

    classes = [line.strip() for line in f.readlines()]



# 加载图像

img = cv2.imread('test_image.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)



# 解析输出

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_PLAIN

colors = np.random.uniform(0, 255, size=(len(classes), 3))



for i in range(len(boxes)):

    if i in indexes:

        x, y, w, h = boxes[i]

        label = str(classes[class_ids[i]])

        color = colors[class_ids[i]]

        cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)

        cv2.putText(img, label, (x, y - 10), font, 1, color, 2)



# 显示结果

cv2.imshow('YOLO Detection', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载YOLO模型

    • cv2.dnn.readNet函数用于加载YOLO模型的权重文件和配置文件。

    • net.getLayerNamesnet.getUnconnectedOutLayers用于获取模型的输出层名称。

  2. 加载类别名称

    • coco.names文件包含COCO数据集中的类别名称。
  3. 加载图像

    • cv2.imread函数用于读取图像。

    • heightwidthchannels分别表示图像的高度、宽度和通道数。

  4. 进行图像预处理

    • cv2.dnn.blobFromImage函数用于将图像转换为模型输入所需的格式。

    • 0.00392是图像归一化系数。

    • (416, 416)是输入图像的尺寸。

    • (0, 0, 0)是均值减去值。

    • True表示交换图像的R和B通道。

    • crop=False表示不裁剪图像。

  5. 解析输出

    • outs是模型的输出,包含检测结果。

    • class_idsconfidencesboxes分别存储检测到的目标的类别、置信度和边界框。

  6. 应用非最大抑制

    • cv2.dnn.NMSBoxes函数用于去除冗余的检测框,保留置信度最高的框。
  7. 绘制检测结果

    • cv2.rectangle函数用于在图像中标记检测到的目标。

    • cv2.putText函数用于在图像中显示目标的类别名称。

  8. 显示结果

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey函数用于等待用户按键,0表示无限等待。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

2. 使用Mask R-CNN进行实例分割

Mask R-CNN是一种扩展了Faster R-CNN的目标检测和实例分割算法。它不仅能够检测目标,还能生成目标的分割掩码。


import cv2

import numpy as np

import torch

import torchvision



# 加载Mask R-CNN模型

model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)

model.eval()



# 加载类别名称

with open('coco.names', 'r') as f:

    classes = [line.strip() for line in f.readlines()]



# 加载图像

img = cv2.imread('test_image.jpg')

img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

img_tensor = torch.from_numpy(img / 255.0).permute(2, 0, 1).float().unsqueeze(0)



# 进行图像预处理

with torch.no_grad():

    predictions = model(img_tensor)



# 解析输出

boxes = predictions[0]['boxes'].cpu().numpy()

masks = predictions[0]['masks'].cpu().numpy()

scores = predictions[0]['scores'].cpu().numpy()

labels = predictions[0]['labels'].cpu().numpy()



# 过滤置信度低的检测结果

min_confidence = 0.5

boxes = boxes[scores > min_confidence]

masks = masks[scores > min_confidence]

labels = labels[scores > min_confidence]



# 绘制检测结果

for i in range(len(boxes)):

    x1, y1, x2, y2 = boxes[i]

    label = str(classes[labels[i] - 1])

    mask = masks[i][0]

    mask = (mask > 0.5).astype(np.uint8)



    # 绘制边界框

    cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)



    # 绘制分割掩码

    colored_mask = np.zeros_like(img, dtype=np.uint8)

    colored_mask[:, :, 1] = mask * 255

    img = cv2.addWeighted(img, 1, colored_mask, 0.5, 0)



    # 显示类别名称

    cv2.putText(img, label, (x1, y1 - 10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 2)



# 显示结果

img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

cv2.imshow('Mask R-CNN Detection', img)

cv2.waitKey(0)

cv2.destroyAllWindows()

代码解释

  1. 加载Mask R-CNN模型

    • torchvision.models.detection.maskrcnn_resnet50_fpn函数用于加载预训练的Mask R-CNN模型。

    • model.eval将模型设置为评估模式。

  2. 加载类别名称

    • coco.names文件包含COCO数据集中的类别名称。
  3. 加载图像

    • cv2.imread函数用于读取图像。

    • cv2.cvtColor函数将图像从BGR格式转换为RGB格式。

    • torch.from_numpy函数将图像转换为PyTorch张量。

    • permute函数用于调整张量的维度顺序。

    • unsqueeze函数用于增加一个批次维度。

  4. 进行图像预处理

    • modeltorch.no_grad上下文中进行推理,以禁用梯度计算。
  5. 解析输出

    • predictions包含模型的输出,包括边界框、分割掩码、置信度和类别标签。

    • boxesmasksscoreslabels分别存储检测到的目标的边界框、分割掩码、置信度和类别标签。

  6. 过滤置信度低的检测结果

    • min_confidence表示置信度阈值。

    • 通过筛选,保留置信度大于阈值的检测结果。

  7. 绘制检测结果

    • cv2.rectangle函数用于在图像中标记检测到的目标。

    • cv2.addWeighted函数用于将分割掩码与原图像进行加权混合,生成带有掩码的图像。

    • cv2.putText函数用于在图像中显示目标的类别名称。

  8. 显示结果

    • cv2.cvtColor函数将图像从RGB格式转换回BGR格式。

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey函数用于等待用户按键,0表示无限等待。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

实时处理

在机器人视觉应用中,实时处理是非常重要的。本节将介绍如何使用OpenCV进行实时的图像处理,包括摄像头捕获、目标检测、图像分割等。

原理

实时处理的基本原理是通过摄像头连续捕获图像,并在每一帧图像上进行处理。处理速度需要足够快,以满足实时应用的要求。

内容

  1. 摄像头捕获

  2. 实时目标检测

  3. 实时图像分割

1. 摄像头捕获

使用OpenCV的VideoCapture类可以方便地从摄像头捕获图像。


import cv2



# 初始化摄像头

cap = cv2.VideoCapture(0)



while True:

    # 读取一帧图像

    ret, frame = cap.read()

    if not ret:

        break



    # 显示图像

    cv2.imshow('Camera Capture', frame)



    # 按'q'键退出

    if cv2.waitKey(1) & 0xFF == ord('q'):

        break



# 释放摄像头并关闭窗口

cap.release()

cv2.destroyAllWindows()

代码解释

  1. 初始化摄像头

    • cv2.VideoCapture(0)函数用于初始化摄像头,0表示第一个摄像头。
  2. 读取一帧图像

    • cap.read函数用于读取一帧图像,返回一个布尔值ret和图像帧frame

    • if not ret表示如果读取失败,退出循环。

  3. 显示图像

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey(1)函数用于等待1毫秒,0xFF表示按键的ASCII码。

    • ord('q')表示’q’键的ASCII码,用于检测用户是否按下了’q’键。

  4. 释放摄像头并关闭窗口

    • cap.release函数用于释放摄像头资源。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

2. 实时目标检测

在实时应用中,我们可以结合摄像头捕获和目标检测算法,实现实时的目标检测。


import cv2

import numpy as np



# 加载YOLO模型

net = cv2.dnn.readNet### 续写:实时目标检测



在实时应用中,我们可以结合摄像头捕获和目标检测算法,实现实时的目标检测。以下是一个使用YOLO模型进行实时目标检测的示例代码。



```python

import cv2

import numpy as np



# 加载YOLO模型

net = cv2.dnn.readNet('yolov3.weights', 'yolov3.cfg')

layer_names = net.getLayerNames()

output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]



# 加载类别名称

with open('coco.names', 'r') as f:

    classes = [line.strip() for line in f.readlines()]



# 初始化摄像头

cap = cv2.VideoCapture(0)



while True:

    # 读取一帧图像

    ret, frame = cap.read()

    if not ret:

        break



    # 获取图像的尺寸

    height, width, channels = frame.shape



    # 进行图像预处理

    blob = cv2.dnn.blobFromImage(frame, 0.00392, (416, 416), (0, 0, 0), True, crop=False)

    net.setInput(blob)

    outs = net.forward(output_layers)



    # 解析输出

    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_PLAIN

    colors = np.random.uniform(0, 255, size=(len(classes), 3))



    for i in range(len(boxes)):

        if i in indexes:

            x, y, w, h = boxes[i]

            label = str(classes[class_ids[i]])

            color = colors[class_ids[i]]

            cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)

            cv2.putText(frame, label, (x, y - 10), font, 1, color, 2)



    # 显示图像

    cv2.imshow('Real-time YOLO Detection', frame)



    # 按'q'键退出

    if cv2.waitKey(1) & 0xFF == ord('q'):

        break



# 释放摄像头并关闭窗口

cap.release()

cv2.destroyAllWindows()

代码解释

  1. 加载YOLO模型

    • cv2.dnn.readNet函数用于加载YOLO模型的权重文件和配置文件。

    • net.getLayerNamesnet.getUnconnectedOutLayers用于获取模型的输出层名称。

  2. 加载类别名称

    • coco.names文件包含COCO数据集中的类别名称。
  3. 初始化摄像头

    • cv2.VideoCapture(0)函数用于初始化摄像头,0表示第一个摄像头。
  4. 读取一帧图像

    • cap.read函数用于读取一帧图像,返回一个布尔值ret和图像帧frame

    • if not ret表示如果读取失败,退出循环。

  5. 获取图像的尺寸

    • heightwidthchannels分别表示图像的高度、宽度和通道数。
  6. 进行图像预处理

    • cv2.dnn.blobFromImage函数用于将图像转换为模型输入所需的格式。

    • 0.00392是图像归一化系数。

    • (416, 416)是输入图像的尺寸。

    • (0, 0, 0)是均值减去值。

    • True表示交换图像的R和B通道。

    • crop=False表示不裁剪图像。

    • net.setInput(blob)将预处理后的图像设置为模型的输入。

    • net.forward(output_layers)进行前向传播,获取模型的输出。

  7. 解析输出

    • outs是模型的输出,包含检测结果。

    • class_idsconfidencesboxes分别存储检测到的目标的类别、置信度和边界框。

  8. 应用非最大抑制

    • cv2.dnn.NMSBoxes函数用于去除冗余的检测框,保留置信度最高的框。
  9. 绘制检测结果

    • cv2.rectangle函数用于在图像中标记检测到的目标。

    • cv2.putText函数用于在图像中显示目标的类别名称。

  10. 显示图像

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey(1)函数用于等待1毫秒,0xFF表示按键的ASCII码。

    • ord('q')表示’q’键的ASCII码,用于检测用户是否按下了’q’键。

  11. 释放摄像头并关闭窗口

    • cap.release函数用于释放摄像头资源。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

3. 实时图像分割

在实时应用中,我们可以结合摄像头捕获和图像分割算法,实现实时的图像分割。以下是一个使用Mask R-CNN模型进行实时图像分割的示例代码。


import cv2

import numpy as np

import torch

import torchvision



# 加载Mask R-CNN模型

model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True)

model.eval()



# 加载类别名称

with open('coco.names', 'r') as f:

    classes = [line.strip() for line in f.readlines()]



# 初始化摄像头

cap = cv2.VideoCapture(0)



while True:

    # 读取一帧图像

    ret, frame = cap.read()

    if not ret:

        break



    # 将图像转换为RGB格式

    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

    frame_tensor = torch.from_numpy(frame / 255.0).permute(2, 0, 1).float().unsqueeze(0)



    # 进行图像预处理

    with torch.no_grad():

        predictions = model(frame_tensor)



    # 解析输出

    boxes = predictions[0]['boxes'].cpu().numpy()

    masks = predictions[0]['masks'].cpu().numpy()

    scores = predictions[0]['scores'].cpu().numpy()

    labels = predictions[0]['labels'].cpu().numpy()



    # 过滤置信度低的检测结果

    min_confidence = 0.5

    boxes = boxes[scores > min_confidence]

    masks = masks[scores > min_confidence]

    labels = labels[scores > min_confidence]



    # 绘制检测结果

    for i in range(len(boxes)):

        x1, y1, x2, y2 = boxes[i]

        label = str(classes[labels[i] - 1])

        mask = masks[i][0]

        mask = (mask > 0.5).astype(np.uint8)



        # 绘制边界框

        cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)



        # 绘制分割掩码

        colored_mask = np.zeros_like(frame, dtype=np.uint8)

        colored_mask[:, :, 1] = mask * 255

        frame = cv2.addWeighted(frame, 1, colored_mask, 0.5, 0)



        # 显示类别名称

        cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 2)



    # 将图像转换回BGR格式

    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)



    # 显示图像

    cv2.imshow('Real-time Mask R-CNN Segmentation', frame)



    # 按'q'键退出

    if cv2.waitKey(1) & 0xFF == ord('q'):

        break



# 释放摄像头并关闭窗口

cap.release()

cv2.destroyAllWindows()

代码解释

  1. 加载Mask R-CNN模型

    • torchvision.models.detection.maskrcnn_resnet50_fpn函数用于加载预训练的Mask R-CNN模型。

    • model.eval将模型设置为评估模式。

  2. 加载类别名称

    • coco.names文件包含COCO数据集中的类别名称。
  3. 初始化摄像头

    • cv2.VideoCapture(0)函数用于初始化摄像头,0表示第一个摄像头。
  4. 读取一帧图像

    • cap.read函数用于读取一帧图像,返回一个布尔值ret和图像帧frame

    • if not ret表示如果读取失败,退出循环。

  5. 将图像转换为RGB格式

    • cv2.cvtColor函数将图像从BGR格式转换为RGB格式。

    • torch.from_numpy函数将图像转换为PyTorch张量。

    • permute函数用于调整张量的维度顺序。

    • unsqueeze函数用于增加一个批次维度。

  6. 进行图像预处理

    • modeltorch.no_grad上下文中进行推理,以禁用梯度计算。
  7. 解析输出

    • predictions包含模型的输出,包括边界框、分割掩码、置信度和类别标签。

    • boxesmasksscoreslabels分别存储检测到的目标的边界框、分割掩码、置信度和类别标签。

  8. 过滤置信度低的检测结果

    • min_confidence表示置信度阈值。

    • 通过筛选,保留置信度大于阈值的检测结果。

  9. 绘制检测结果

    • cv2.rectangle函数用于在图像中标记检测到的目标。

    • cv2.addWeighted函数用于将分割掩码与原图像进行加权混合,生成带有掩码的图像。

    • cv2.putText函数用于在图像中显示目标的类别名称。

  10. 将图像转换回BGR格式

    • cv2.cvtColor函数将图像从RGB格式转换回BGR格式。
  11. 显示图像

    • cv2.imshow函数用于显示图像。

    • cv2.waitKey(1)函数用于等待1毫秒,0xFF表示按键的ASCII码。

    • ord('q')表示’q’键的ASCII码,用于检测用户是否按下了’q’键。

  12. 释放摄像头并关闭窗口

    • cap.release函数用于释放摄像头资源。

    • cv2.destroyAllWindows函数用于关闭所有图像窗口。

通过以上内容,你已经了解了如何设计和实现一个完整的机器人视觉系统,包括摄像头校准、目标检测、图像分割和实时处理。这些技术的结合可以为机器人提供强大的视觉感知能力,使其在各种应用场景中更加智能和可靠。希望这些内容对你有所帮助,祝你在机器人视觉领域取得更大的进展!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kkchenjj

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值