基于OpenCV的RoboMaster装甲识别(Python,C++都有)
基于OpenCV的RoboMaster装甲识别(Python,C++都有)
概述
这篇文章简单的介绍了RoboMaster机器人的装甲识别。方法是通过边缘检测的方法将灯柱作为标识选中装甲板区域。在本篇博客中将提供坐标点,作为后续机甲调试使用。
所使用到的技术:颜通道分离,高斯滤波,lambda表达式,轮廓检测
训练素材&最终效果
训练素材放在以下的百度网盘链接中,有需要的朋友自提一下。
链接:
提取码:yvi6
最终效果
关键部分
b, g, r = cv2.split(image)
在OpenCV中图片颜通道顺序为BGR,而非大家熟悉的RBG,cv2.split(src)返回值为三个通道,与灰度图一样,用0~255表示颜的深度。
轮廓检测的前提条件为二值图,因此我们需要那单通道图片进行二值化。
ret, binary = (src, threshold, maxval, type)
二值化的四个参数分别为:输入的单通道图片src,二值化阈值threshold,超过阈值的赋值maxval,二值化类型type。
其中type的类型常用为:
- cv2.THRESH_BIARY(黑白二值)
- cv2.THRESH_BIARY_IV(黑白二值反转)
Gaussian = cv2.GaussianBlur(binary, ksize, 0)
高斯卷积操作的参数分别为:输入的二值图像binary,卷积核尺寸ksize(例如(5,5)),影响高斯分布的参数,一般设为0。
通过高斯滤波可以减小二值图中的噪声的影响,因为在二值化的过程中由于指定的阈值,可能会导致在一块白中间出现黑点,导致在进行cv2.findCotours()轮廓时,将这些噪音点单独标出。下图为未进行高斯滤波的其中一帧效果。
在进行cv2.findCotours()后,我们需要对检测出来的轮廓进行判定筛选出装甲板灯条的轮廓。
ontours, hierarchy = cv2.findContours(image=draw_img, mode=cv2.RETR_TREE, method=cv2.CHAI_APPROX_OE)
contours = list(contours)
contours.sort(key=lambda c: (c), reverse=True)
这里通过lambda表达式将选中的轮廓按照面积大小进行排序。
width_array = []
height_array = []
point_array = []
for cont in contours[:5]:x, y, w, h = cv2.boundingRect(cont)# cv2.rectangle(img, (x,y), (xw,yh), (0, 255, 0), 2)try:if h / w >= 2 and h / whole_h > 0.1:# if height / h > 0.05:width_array.append(w)height_array.append(h)point_array.append([x, y])except:continue
这里通过外接矩形的思路将这些提取到轮廓信息,然后通过对灯条条件的筛选去除一部分的轮廓。这里的筛选条件为:
- 外接矩形的高度至少是宽度的两倍
- 外接矩形的高度不小于画面大小的1/10
这里可能有小伙伴有疑问通过外接最小矩形在效果上最好吗,其实外接最小矩形的思路就是通过拟合,寻出四个点。首先我们来看下最小矩形的代码
for cont in contours:rect = (cont)# cv2.boxPoints可以将轮廓点转换为四个角点坐标box = cv2.boxPoints(rect)# print(type(box))# 这一步不影响后面的画图,但是可以保证四个角点坐标为顺时针startidx = box.sum(axis=1).argmin()box = np.roll(box, 4 - startidx, 0)# 在原图上画出预测的外接矩形box = box.reshape((-1, 1, 2)).astype(np.int2)cv2.polylines(img, [box], True, (0, 255, 0), 2)
这是一段大家能在网上到比较通用的代码了。在这些代码中,它定义的四个点为顺时针旋转,并且最低点永远为0号点,这就意味着咱们很难得出这个最小矩形的长和宽。这是因为角度不同会导致长宽组成的点也不同。因此选择外接矩形会更加简单也更加方便。
跳过上面的插曲。在我们获得这么多轮廓之后我们需要来通过两个单独灯条轮廓将整个装甲板框起来。此时我用到的方法就是寻两个最接近的轮廓。
point_near = [0, 0]
min = 10000
for i in range(len(width_array) - 1):for j in range(i 1, len(width_array)):value = abs(width_array[i] * height_array[i] - width_array[j] * height_array[j])if value < min:min = valuepoint_near[0] = ipoint_near[1] = j
try:rectangle1 = point_array[point_near[0]]rectangle2 = point_array[point_near[1]]point1 = [rectangle1[0] width_array[point_near[0]] / 2, rectangle1[1]]point2 = [rectangle1[0] width_array[point_near[0]] / 2, rectangle1[1] height_array[point_near[0]]]point = [rectangle2[0] width_array[point_near[1]] / 2, rectangle2[1]]point4 = [rectangle2[0] width_array[point_near[1]] / 2, rectangle2[1] height_array[point_near[1]]]print(point1, point2, point, point4)x = np.array([point1, point2, point4, point], np.int2)box = x.reshape((-1, 1, 2)).astype(np.int2)cv2.polylines(img, [box], True, (0, 255, 0), 2)
point_near数组保存的是最接近的两个轮廓在数组中的index索引值。min变量保存着轮廓面积的最下差值。
完整代码
# 开发作者 :Tian.Z.L
# 开发时间 :2022/2/17 18:11
# 文件名称 :assignment.PY
# 开发工具 :PyCharm
import cv2
import numpy as np
import mathvideo = cv2.VideoCapture(r C:\Users\TianZhonglin\Documents\Tencent Files\765808965\FileRecv\MobileFile\ )# video = cv2.VideoCapture(r C:\Users\TianZhonglin\Documents\Tencent Files\765808965\FileRecv\2456789.avi )def img_show(name, src):cv2.imshow(name, src)cv2.waitKey(0)cv2.destroyAllWindows()while True:ret, img = video.read()blue, g, r = cv2.split(img) # 分离通道,在opencv中图片的存储通道为BGR非RBG# 绘制轮廓 是在原图像上进行画轮廓ret2, binary = (blue, 220, 255, 0)Gaussian = cv2.GaussianBlur(binary, (5, 5), 0) # 高斯滤波# edge = cv2.Canny(binary, 50, 150) # 边缘检测draw_img = ()whole_h, whole_w = binary.shape[:2]# 输出的第一个值为图像,第二个值为轮廓信息,第三个为层级信息contours, hierarchy = cv2.findContours(image=draw_img, mode=cv2.RETR_TREE, method=cv2.CHAI_APPROX_OE)contours = list(contours)contours.sort(key=lambda c: (c), reverse=True)width_array = []height_array = []point_array = []for cont in contours[:5]:x, y, w, h = cv2.boundingRect(cont)try:if h / w >= 2 and h / whole_h > 0.1 and h > w:# if height / h > 0.05:width_array.append(w)height_array.append(h)point_array.append([x, y])except:continuepoint_near = [0, 0]min = 10000for i in range(len(width_array) - 1):for j in range(i 1, len(width_array)):value = abs(width_array[i] * height_array[i] - width_array[j] * height_array[j])if value < min:min = valuepoint_near[0] = ipoint_near[1] = jtry:rectangle1 = point_array[point_near[0]]rectangle2 = point_array[point_near[1]]point1 = [rectangle1[0] width_array[point_near[0]] / 2, rectangle1[1]]point2 = [rectangle1[0] width_array[point_near[0]] / 2, rectangle1[1] height_array[point_near[0]]]point = [rectangle2[0] width_array[point_near[1]] / 2, rectangle2[1]]point4 = [rectangle2[0] width_array[point_near[1]] / 2, rectangle2[1] height_array[point_near[1]]]print(point1, point2, point, point4)x = np.array([point1, point2, point4, point], np.int2)box = x.reshape((-1, 1, 2)).astype(np.int2)cv2.polylines(img, [box], True, (0, 255, 0), 2)except:continuecv2.imshow( name , img)if cv2.waitKey(1) & 0xFF == ord( q ):break
# 释放资源
video.release()
cv2.destroyAllWindows()
// : 此文件包含 main 函数。程序执行将在此处开始并结束。
//
#include stdio.h
#include<iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
ct int kThreashold = 220;
ct int kMaxVal = 255;
ct Size kGaussianBlueSize = Size(5, 5);
int main()
{VideoCapture video;(C:/Users/TianZhonglin/Documents/Tencent Files/765808965/FileRecv/MobileFile/);Mat frame,channels[],binary,Gaussian;vector<vector<Point>> contours;vector<Vec4i> hierarchy;Rect boundRect;RotatedRect box;vector<Point2f> boxPts(4);for (;;) {Rect point_array[20];video >> frame;if (()) {break;}split(frame,channels);threshold(channels[0], binary, kThreashold, kMaxVal, 0);GaussianBlur(binary, Gaussian, kGaussianBlueSize, 0);findContours(Gaussian, contours, hierarchy, RETR_TREE, CHAI_APPROX_OE);int index = 0;for (int i = 0; i < contours.size(); i) {//box = minAreaRect(Mat(contours[i]));//box.points(boxPts.data());boundRect = boundingRect(Mat(contours[i]));//rectangle(frame, (), boundRect.br(), (0, 255, 0), 2,8 ,0);try{if (double(boundRect.height / boundRect.width) >= 1. && boundRect.height > 6 && boundRect.height>20) {point_array[index] = boundRect;index;}}catch (ct char* msg){cout << printf(msg) << endl;//continue;}} int point_near[2];int min = 10000;for (int i = 0; i < index-1; i){for (int j = i 1; j < index; j) {int value = abs(point_array[i].area() - point_array[j].area());if (value < min){min = value;point_near[0] = i;point_near[1] = j;}}} try{Rect rectangle_1 = point_array[point_near[0]];Rect rectangle_2 = point_array[point_near[1]];if (rectangle_2.x == 0 || rectangle_1.x == 0) {throw not enough points;}Point point1 = Point(rectangle_1.x rectangle_1.width / 2, rectangle_1.y);Point point2 = Point(rectangle_1.x rectangle_1.width / 2, rectangle_1.y rectangle_1.height);Point point = Point(rectangle_2.x rectangle_2.width / 2, rectangle_2.y);Point point4 = Point(rectangle_2.x rectangle_2.width / 2, rectangle_2.y rectangle_2.height);Point p[4] = { point1,point2,point4,point };cout << p[0]<<p[1]<<p[2]<<p[] << endl;for (int i = 0; i < 4; i) {line(frame, p[i%4], p[(i1)%4], Scalar(0, 255, 0), 2);} }catch (ct char* msg){cout << msg << endl;//continue;}imshow(video, frame);if (waitKey(10) >= 0) {break;}}video.release();cv::destroyAllWindows();return 0;
}
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 19 条评论) |
本站网友 去黑头最有效的方法 | 19分钟前 发表 |
x | |
本站网友 国家开发银行总行 | 24分钟前 发表 |
[box] | |
本站网友 减肥茶效果 | 9分钟前 发表 |
(c) | |
本站网友 怀孕中期 | 14分钟前 发表 |
ontours | |
本站网友 打工者的心态 | 20分钟前 发表 |
# if height / h > 0.05 | |
本站网友 福建工程学院国脉信息学院 | 20分钟前 发表 |
reverse=True) 这里通过lambda表达式将选中的轮廓按照面积大小进行排序 | |
本站网友 武汉韩语培训班 | 18分钟前 发表 |
0] min = 10000 for i in range(len(width_array) - 1) | |
本站网友 为什么视频打不开 | 4分钟前 发表 |
5] | |
本站网友 今天晚间新闻 | 6分钟前 发表 |
0);try{if (double(boundRect.height / boundRect.width) >= 1. && boundRect.height > 6 && boundRect.height>20) {point_array[index] = boundRect;index;}}catch (ct char* msg){cout << printf(msg) << endl;//continue;}} int point_near[2];int min = 10000;for (int i = 0; i < index-1; i){for (int j = i 1; j < index; j) {int value = abs(point_array[i].area() - point_array[j].area());if (value < min){min = value;point_near[0] = i;point_near[1] = j;}}} try{Rect rectangle_1 = point_array[point_near[0]];Rect rectangle_2 = point_array[point_near[1]];if (rectangle_2.x == 0 || rectangle_1.x == 0) {throw not enough points;}Point point1 = Point(rectangle_1.x rectangle_1.width / 2 | |
本站网友 东方法治网 | 30分钟前 发表 |
cv2.imshow(name | |
本站网友 眼角去皱纹 | 2分钟前 发表 |
220 | |
本站网友 风电行业 | 17分钟前 发表 |
True | |
本站网友 降准和降息的区别 | 29分钟前 发表 |
y | |
本站网友 青筋 | 4分钟前 发表 |
point_near = [0 | |
本站网友 变了 | 18分钟前 发表 |
p[(i1)%4] | |
本站网友 dynamips | 4分钟前 发表 |
此文件包含 main 函数 | |
本站网友 婴儿尸体 | 2分钟前 发表 |
yh) | |
本站网友 木香的功效与作用 | 13分钟前 发表 |
threshold |