赞
踩
博主联系方式:
QQ:1540984562
QQ交流群:892023501
群里会有往届的smarters和电赛选手,群里也会不时分享一些有用的资料,有问题可以在群里多问问。
激光枪自动射击装置(E题)
【本科组】
一、任务
设计一个能够控制激光枪击发、自动报靶及自动瞄准等功能的电子系统。该系统由激光枪及瞄准机构、胸环靶、弹着点检测电路组成,其结构示意见图1。
二、要求
1.基本要求
(1) 用激光笔改装激光枪,激光枪可受电路控制发射激光束,激光束照射于胸环靶上弹着点的光斑直径<5mm;激光枪与胸环靶间距离为3m。
图1 激光枪自动射击装置示意图
(2) 激光枪固定在一机构上,可通过键盘控制激光枪的弹着点(用键盘设置激光束在靶纸上上下、左右移动一定距离)。
(3) 制作弹着点检测电路,通过摄像头识别激光枪投射在胸环靶上的弹着点光斑,并显示弹着点的环数与方位信息。其中环数包括:10、9、8、7、6、5、脱靶;方位信息是指弹着点与10环区域的相对位置,包括:中心、正上、正下、正左、正右、左上、左下、右上、右下。详见图2-b。
2.发挥部分
(1) 在图形点阵显示器上显示胸环靶的相应图形,并闪烁显示弹着点。
(2) 自动控制激光枪,在15秒内将激光束光斑从胸环靶上的指定位置迅速瞄准并击中靶心(即10环区域)。
(3) 可根据任意设定的环数,控制激光枪瞄准击中胸环靶上相应位置。
(4) 其他
2-a 胸环靶尺寸 2-b胸环靶 环数及方位信息示意
图2 胸环靶示意图
三、说明
1. 激光枪可以由市场上的激光笔改造,由电路控制击发;每次击发使光斑维持3~5s时间,但此期间不得移动光斑。
2. 可采用步进电机、舵机或直流电机等机构对激光枪进行两维控制,以实现瞄准。激光枪及相关机构可由支架支撑。
3. 胸环靶是在不反光的白纸画有一组相距5cm的同心圆(线宽不超过1mm),最内圆环直径10cm,圆环内为10环区域,从最内环至最外环间分别为9、8、7、6、5环区域,最外环外为脱靶。胸环靶上不允许设置摄像头以外的传感器。
4. 当激光枪的弹着点落在胸环靶的环线上时,报靶时采取就高不就低的原则。例如,弹着点在8环与9环之间的环线上时,则认为是9环。
5. 在不影响靶纸上圆环线的前提下,允许在靶纸上做标记。
6. 在完成发挥部分要求时,在正式击发前允许进行1-2次试射;但试射次数越少越好。
7. 不限制摄像头及弹着点检测电路的安装位置,但应方便搬运与快速安装。
8. 测试时自带胸环靶纸,测试评审现场可提供粘贴胸环靶的支架。
四、评分标准
设
计
报
告 项 目 主要内容 分数
系统方案 比较与选择
方案描述 4
理论分析与计算 激光枪自动控制原理分析、计算
弹着点检测原理分析、计算 6
电路与程序设计 电路设计
程序设计 4
测试方案与测试结果 测试方案及测试条件
测试结果及其完整性
测试结果分析 3
设计报告结构及规范性 摘要
设计报告结构、版面
图表的规范性 3
总分 20
基本
要求 实际制作完成情况 50
发挥
部分 完成第(1)项 5
完成第(2)项 20
完成第(3)项 15
完成第(4)项 10
总分 50
使用opencv写的测试代码
#include <opencv2/opencv.hpp> #include "opencv2/features2d.hpp" #include <iostream> #include "windows.h" #include <stdio.h> #include <time.h> #include <math.h> #include<opencv2/imgproc/types_c.h> using namespace cv; using namespace std; #define PI 3.14159 //获取靶心位置 Point get_target(Mat& rgbMat,Mat& grayMat,Mat& paint) { //分离出r通道,BGR vector<Mat> channels; split(rgbMat, channels); Mat R_Mat,G_Mat,B_Mat; channels.at(2).copyTo(R_Mat); channels.at(1).copyTo(G_Mat); channels.at(0).copyTo(B_Mat); int row_num = R_Mat.rows; //行数 int col_num = R_Mat.cols; //列数 //二值化得到掩膜 Mat mask=Mat::zeros(grayMat.size(), grayMat.type());; //双重循环,遍历右下角像素值 for (int i = 0;i < row_num;i++) //行循环 { for (int j = 0 ;j < col_num;j++) //列循环 { //-------【开始处理每个像素】--------------- if (grayMat.at<uchar>(i, j) >= 90 && grayMat.at<uchar>(i, j) <= 230 && R_Mat.at<uchar>(i, j) >= 240 && G_Mat.at<uchar>(i, j) <= 120 && B_Mat.at<uchar>(i, j) <= 120) { mask.at<uchar>(i, j) = 255; } //-------【处理结束】--------------- } } //连通域计算,限制 Mat lableMat; Mat statsMat; Mat centerMat; int nComp = cv::connectedComponentsWithStats(mask, lableMat, statsMat, centerMat, 8, CV_32S); int pixels = 0; int center_X = 0; int center_Y = 0; for (int i = 0; i < nComp; i++) { pixels = statsMat.at<int>(i, 4); //打印信息 if (pixels <= 300 && pixels >= 20) { center_X = centerMat.at<double>(i, 0); center_Y = centerMat.at<double>(i, 1); cout << "中心X" << center_X << endl; cout << "中心Y" << center_Y << endl; cout << "像素个数" << pixels << endl; //画出中心点 circle(paint, Point(center_X, center_Y), 5, Scalar(0, 255, 0), 2, 8, 0); break; } } //返回靶心坐标,并且画出来 return Point(center_X, center_Y); } //获取激光位置 Point get_gray(Mat& gray,Mat& paint) { Mat mask; //二值化后得到掩膜 threshold(gray, mask, 250, 255, THRESH_BINARY); Mat lableMat; Mat statsMat; Mat centerMat; int nComp = cv::connectedComponentsWithStats(mask, lableMat, statsMat, centerMat, 8, CV_32S); int pixels=0; int center_X=0; int center_Y=0; for (int i = 0; i < nComp; i++) { pixels = statsMat.at<int>(i, 4); //打印信息 if (pixels <= 200 && pixels >= 10) { center_X = centerMat.at<double>(i, 0); center_Y = centerMat.at<double>(i, 1); cout << "中心X" << center_X << endl; cout << "中心Y" << center_Y << endl; cout << "像素个数" << pixels << endl; //画出中心点 circle(paint, Point(center_X, center_Y), 5, Scalar(0, 0, 255), 2, 8, 0); break; } } return Point(center_X, center_Y); } //获取两个点之间的距离 int get_distance(Point point1, Point point2) { int dx = abs(point1.x - point2.x); int dy = abs(point1.y - point2.y); int distance = sqrt(dx * dx + dy * dy); return distance; } //获取两个点之间的角度 int get_angle(Point point1, Point point2) { float dx = point1.x - point2.x; float dy = point1.y - point2.y; int angle = 0; if (dx == 0 && dy >= 0) angle = 0; if (dx == 0 && dy < 0) angle = 180; if (dy == 0 && dx > 0) angle = 90; if (dy == 0 && dx < 0) angle = 270; if (dx > 0 && dy > 0) angle = atan(dx / dy) * 180 / PI; else if (dx < 0 && dy>0) angle = 360 + atan(dx / dy) * 180 / PI; else if (dx < 0 && dy < 0) angle = 180 + atan(dx / dy) * 180 / PI; else if (dx > 0 && dy < 0)angle = 180 + atan(dx / dy) * 180 / PI; return angle; } //计算两点方位,返回point1在point2的哪个方位 int get_direction(Point point1, Point point2) { int direct = 0; float dx = point1.x - point2.x; float dy = point1.y - point2.y; if (dx == 0 && dy == 0) { direct = 1; //重合 } else if (dx == 0 && dy > 0) { direct = 2; //正下方 } else if (dx == 0 && dy < 0) { direct = 3; //正上方 } else if (dx > 0 && dy == 0) { direct = 4; //正右方 } else if (dx > 0 && dy > 0) { direct = 5; //右下方 } else if (dx > 0 && dy < 0) { direct = 6; //右上方 } else if (dx < 0 && dy == 0) { direct = 7; //正左方 } else if (dx < 0 && dy > 0) { direct = 8; //左下方 } else if (dx < 0 && dy < 0) { direct = 9; //左上方 } else { direct = 0; //无方向 } return direct; } void show_direction(int direct) { if (direct == 1) { cout << "重合" << endl; } else if (direct == 2) { cout << "正下方" << endl; } else if (direct == 3) { cout << "正上方" << endl; } else if (direct == 4) { cout << "正右方" << endl; } else if (direct == 5) { cout << "右下方" << endl; } else if (direct == 6) { cout << "右上方" << endl; } else if (direct == 7) { cout << "正左方" << endl; } else if (direct == 8) { cout << "左下方" << endl; } else if (direct == 9) { cout << "左上方" << endl; } else { cout << "无方向" << endl; } } //环间距获取 void get_ring_space(Mat& paintMat,Mat& canny) { Mat mask = Mat::zeros(canny.size(), canny.type());;; int times=0; //双重循环,遍历右下角像素值 for (int i = 1;i < canny.rows-1;i++) //行循环 { for (int j = 1;j < canny.cols-1;j++) //列循环 { //-------【开始处理每个像素】--------------- if (canny.at<uchar>(i, j) == 255 && paintMat.at<Vec3b>(i, j)[0] == 0 && paintMat.at<Vec3b>(i, j)[1] == 0 && paintMat.at<Vec3b>(i, j)[2] == 0) { mask.at<uchar>(i, j) = 255; times++; //判断每个格子八领域是否有白色的,如果有,消除掉 if (mask.at<uchar>(i - 1, j - 1) == 255 || mask.at<uchar>(i - 1, j) == 255 || mask.at<uchar>(i - 1, j + 1) == 255 || mask.at<uchar>(i, j - 1) == 255 || mask.at<uchar>(i, j + 1) == 255 || mask.at<uchar>(i + 1, j - 1) == 255 || mask.at<uchar>(i + 1, j) == 255 || mask.at<uchar>(i + 1, j + 1) == 255) { mask.at<uchar>(i, j) = 0; times--; } } //-------【处理结束】--------------- } } //默认光斑靠环心的边缘与黑线冲突。 cout <<"环数"<< 10-(times) << endl; } /****示例**********/ int main() { //载入原图 Mat secImage = imread("D:\\opencv_picture_test\\电设\\4.jpg");//加载原图 if (secImage.empty()) { printf("Could not find the image!\n"); return -1; } Mat edge, dstImage,paintMat; dstImage.create(secImage.size(), secImage.type()); //创建一个同大小类型的矩阵 secImage.copyTo(paintMat); cvtColor(secImage, dstImage,COLOR_BGR2GRAY); imshow("【原图的灰度图】", dstImage); Point target= Point(0, 0), gray=Point(0,0); //进行均值滤波操作 blur(dstImage, edge, Size(3, 3)); target=get_target(secImage, dstImage,paintMat); //找到激光的位置并且画出来 gray=get_gray(edge,paintMat); //计算两者中心距离(减去中心圆的半径) if (target != Point(0, 0) && gray != Point(0, 0)) { int distance = get_distance(target, gray); int angle = get_angle(target, gray); int direct = get_direction(gray, target); show_direction(direct); cout << "两者距离" << distance << endl; cout << "两者角度" << angle << endl; int canny_thred = 30; //运行canny算子 Canny(edge, edge, canny_thred, canny_thred * 2, 3); line(paintMat, target, gray, (0, 0, 0), 1); get_ring_space(paintMat, edge); imshow("canny算子检测【效果图】", edge); } else { cout << "没有找到靶点或者激光" << endl; cout << "脱靶" << endl; } waitKey(0); return 0; }
效果:
|
|
|
|
|
|
|
|
|
|
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。