资讯动态

(附代码)使用OpenCV和关键点检测计算瓶子角度

发布时间:2026/10/15 18:27:47 来源:尧图企业网站定制
计算机视觉中的关键点检测是一种用于识别图像中独特点或位置的技术可用作进一步分析的参考例如对象识别、姿态估计或运动跟踪等。本文中我们将介绍如何使用关键点标记来训练计算机视觉模型来识别水瓶的兴趣点。然后我们将使用此信息来估计水瓶的方向。水瓶的方向是指其相对于参考系或轴的旋转对齐或定位。简单来说它是水瓶相对于某个方向倾斜或转动的角度。例如如果您将一个水瓶放在桌子上并且它完全直立其底座与桌子表面平行则其方向将被视为 90 度。如果随后将瓶子稍微向左或向右倾斜其方向会相应地改变。在计算机视觉或机器人环境中确定水瓶的方向可能涉及测量水瓶从预定义的参考方向倾斜或旋转的角度。此信息可用于各种应用例如自动化系统中的对象检测、操作或跟踪。确定物体的方向例如水瓶或任何其他物体在各个领域都有许多实际应用例如在机器人技术中工业机器人需要精确抓取物体以执行组装、分拣、包装或将物体放置在指定位置等任务。在运输和物流中将物品装入集装箱、卡车或货机时了解包裹的方向有助于最大限度地提高空间利用率。估计瓶子方向的方法首先我们需要训练一个关键点检测模型来识别水瓶的顶部和底部关键点。我们将在下一步中介绍如何训练模型。此模型将为我们提供这些关键点的 x 和 y 坐标。然后使用三角函数计算由两个点 x1 y1 和 x2 y2 形成的线段的角度以估计水瓶的方向如下所示首先找出 x 坐标 Δx 和 y 坐标 Δy 的差值然后使用 arctangent 函数求角度此信息用于估计对象的方向在我们的示例中一个具有顶部和底部关键点的水瓶。如果瓶子的底部是直立的呈 90 度角则表明方向正确;否则它被视为不正确。如果正确识别了对象的关键点则此概念可用于估计任何物理对象的方向。详细实现步骤具体步骤如下收集和标记水瓶数据集训练关键点检测模型构建应用程序以检测关键点并估计水瓶的方向步骤 #1收集并标记水瓶数据集手动采集水瓶的数据集。该数据集包含以三个不同方向放置的水瓶如下图所示收集数据集后将其上传到 Roboflow 项目进行标记和训练。要标记数据集首先需要创建一个关键点骨架。有关如何使用 Roboflow 创建和标记关键点项目的更多详细信息您可以参考下方链接https://blog.roboflow.com/keypoint-detection-on-roboflow/对于此项目我定义了一个关键点骨架用于描述顶部点和底部点如下图所示。定义关键点骨架类后它用于通过拖动边界框并将 “top” 和 “bottom” 关键点定位到其所需位置来标记每个图像如下图所示。所有图像都使用 keypoint 类进行标记并生成数据集。步骤 #2训练关键点检测模型完成标记过程后将生成数据集版本并使用 Roboflow 自动训练功能对模型进行训练。实现的训练准确率为 99.5%。该模型会自动部署到云 API。Roboflow 提供了一系列用于测试和部署模型的选项例如在 Web 浏览器中进行实时测试和部署到边缘设备。随附的图片说明了通过 Roboflow 的 Web 界面进行测试的模型。步骤 #3构建应用程序以检测关键点并估计水瓶的方向此步骤涉及构建应用程序以检测实时摄像头源中水瓶的关键点。最初我们将开发一个基本的 Python 脚本该脚本能够检测水瓶的关键点并在图像上用边界框显示它们。为此我们将使用提供的测试映像。首先安装 Roboflow Python 包和 Inference SDK 包我们将使用它们在我们的模型上运行推理pip install roboflow inference-sdk inference然后我们可以编写一个脚本来运行推理。创建新文件并添加以下代码json_string json.dumps(json_data) data json.loads(json_string ) image cv2.imread(bottle.jpg) for prediction in data[predictions]: x int(prediction[x]) y int(prediction[y]) width int(prediction[width]) height int(prediction[height]) x1 int(x - (width / 2)) y1 int(y - (height / 2)) x2 int(x (width / 2)) y2 int(y (height / 2)) # Draw bounding box cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) # Draw keypoints for keypoint in prediction[keypoints]: keypoint_x int(keypoint[x]) keypoint_y int(keypoint[y]) class_name keypoint[class_name] if class_name top: color (0, 0, 255) # Red color for top keypoints elif class_name bottom: color (255, 0, 0) # Blue color for bottom keypoints else: color (0, 255, 0) # Green color for other keypoints cv2.circle(image, (keypoint_x, keypoint_y), 5, color, -1) cv2.imshow(Image with Bounding Boxes and Keypoints, image) cv2.waitKey(0) cv2.destroyAllWindows()上面的代码以 JSON 格式给出输出如下所示。此预测结果存储在 json_data 变量中。{time: 0.09515731000010419, image: {width: 800, height: 360}, predictions: [{x: 341.5, y: 196.5, width: 309.0, height: 85.0, confidence: 0.9074831008911133, class: bottle, class_id: 0, detection_id: bff695c1-df86-4576-83ad-8c802e08774e, keypoints: [{x: 186.0, y: 198.0, confidence: 0.9994387626647949, class_id: 0, class_name: top}, {x: 496.0, y: 202.0, confidence: 0.9994300007820129, class_id: 1, class_name: bottom}]}]}我们会将其转换为 JSON 字符串在以下代码中然后使用该字符串在测试图像输出上绘制边界框和关键点。要显示带有关键点检测模型返回的边界框和关键点的图像我们需要加载图像。然后我们需要遍历存储在 JSON 字符串中的预测结果并绘制边界框和关键点如以下代码所示from inference_sdk import InferenceHTTPClient import cv2 import json CLIENT InferenceHTTPClient( api_urlhttps://detect.roboflow.com, api_keyYOUR_API_KEY ) # infer on a local image json_data CLIENT.infer(bottle.jpg, model_idbottle-keypoints/1) print(json_data)效果如下接下来我们将更新此代码以对视频流执行推理。我们将利用网络摄像头来捕获视频并对视频的每一帧执行推理。创建新文件并添加以下代码from inference_sdk import InferenceHTTPClient import cv2 import json CLIENT InferenceHTTPClient( api_urlhttps://detect.roboflow.com, api_keyYOUR_API_KEY ) defcalculate_angle(x1, y1, x2, y2): # Calculate the differences in coordinates delta_x x1 - x2 delta_y y1 - y2 # Calculate the angle using arctan2 and convert it to degrees angle_rad math.atan2(delta_y, delta_x) angle_deg math.degrees(angle_rad) # Ensure the angle is between 0 and 360 degrees mapped_angle angle_deg % 360 if mapped_angle 0: mapped_angle 360# Ensure angle is positive return mapped_angle cap cv2.VideoCapture(0) ret, frame cap.read() ifnot ret: break # Perform inference on the current frame json_data CLIENT.infer(frame, model_idbottle-keypoints/1) # Convert JSON data to dictionary data json.loads(json.dumps(json_data)) # Variables to store bottom and top keypoint coordinates bottom_x, bottom_y None, None top_x, top_y None, None # Iterate through predictions for prediction in data[predictions]: x int(prediction[x]) y int(prediction[y]) width int(prediction[width]) height int(prediction[height]) x1 int(x - (width / 2)) y1 int(y - (height / 2)) x2 int(x (width / 2)) y2 int(y (height / 2)) # Draw bounding box cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) # Draw keypoints for keypoint in prediction[keypoints]: keypoint_x int(keypoint[x]) keypoint_y int(keypoint[y]) class_name keypoint[class_name] if class_name top: color (0, 0, 255) # Red color for top keypoints top_x, top_y keypoint_x, keypoint_y elif class_name bottom: color (255, 0, 0) # Blue color for bottom keypoints bottom_x, bottom_y keypoint_x, keypoint_y else: color (0, 255, 0) # Green color for other keypoints cv2.circle(frame, (keypoint_x, keypoint_y), 5, color, -1) if bottom_x isnotNoneand bottom_y isnotNoneand top_x isnotNoneand top_y isnotNone: angle calculate_angle(bottom_x, bottom_y, top_x, top_y) # Display the angle on the frame cv2.putText(frame, Angle: {:.2f} degrees.format(angle), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, ( 251, 241, 25), 2) # Check for orientation if0 angle 85or95 angle 185: # Angle close to 0 or 180 degrees cv2.putText(frame, Wrong orientation, (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) elif85 angle 95or265 angle 275: # Angle close to 90 degrees cv2.putText(frame, Correct orientation, (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # Display the frame with predictions and angle cv2.imshow(Webcam, frame) # Check for q key press to exit if cv2.waitKey(1) 0xFF ord(q): break # Release the webcam and close OpenCV windows cap.release() cv2.destroyAllWindows()在我们的代码中我们使用一个函数来计算模型关键点之间的角度。使用这个角度我们将确定水瓶的正确方向。我们可以打开视频流并从网络摄像头捕获帧对每个帧执行推理并保存预测结果。然后我们在捕获的视频的每一帧上绘制边界框和关键点。在此之后我们将计算角度并将其显示在视频帧上。然后我们可以评估方向如果瓶子的角度为 90 度则认为它的位置正确;但是如果它倾斜接近 0 度或 180 度则认为它的位置不正确。这是我们系统的最终输出

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑