当前位置:   article > 正文

【电设控制与图像训练题】【激光打靶】【opencv测试代码以及效果】_【电设控制与图像训练题】【激光打靶】【openmv测试代码以及效果】

【电设控制与图像训练题】【激光打靶】【openmv测试代码以及效果】

博主联系方式:
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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308

效果:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/825684
推荐阅读
相关标签
  

闽ICP备14008679号