基于opencv4和Yolo-Fastest,实现PC和单片机通信,控制步进电机捕获目标

效果视频

基于opencv4和yolo,实现PC和单片机通信,控制步进电机捕获目标

PC端代码

//
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <opencv2/dnn.hpp>

#include <fstream>
#include <iostream>
#include <cstdlib>
#include <string> 
#include <assert.h>

#include "CSerialPort.h"
int port;
CSerialPort mySerialPort;
#define HEAD_FRAME 0XFD
#define secomd_FRAME 0XDE
unsigned char pData[9] = { 0 };



using namespace cv;
using namespace cv::dnn;
using namespace std;

void PortOpen() {
	cout << "Please insert your port number : " << endl;
	cin >> port;

	if (!mySerialPort.InitPort(port, 115200, 'N', 8, 1, EV_RXCHAR))
	{
		std::cout << "initPort fail !" << std::endl;
		PortOpen();
	}
	else
	{
		std::cout << "initPort success !" << std::endl;
	}
}

int main(int argc, char** argv)
{
	//串口的一些配置
	PortOpen();
	if (!mySerialPort.OpenListenThread()) {
		std::cout << "OpenListenThread fail !" << std::endl;
	}
	else {
		std::cout << "OpenListenThread success !" << std::endl;
	}

	pData[0] = 'a';
	pData[1] = 'b';
	
	
	
	string _cfg = "H:/VS/Opencv/program/opencv_yolov4_c++/opencv_yolov4_c++/opencv_yolov4_c++/WZX/wzx.cfg";
	string _model = "H:/VS/Opencv/program/opencv_yolov4_c++/opencv_yolov4_c++/opencv_yolov4_c++/WZX/yolo-fastest_7000.weights";
	string _labels = "H:/VS/Opencv/program/opencv_yolov4_c++/opencv_yolov4_c++/opencv_yolov4_c++/WZX/wzx.names";

	//string _cfg = "H:/VS/Opencv/program/opencv_yolov4_c++/opencv_yolov4_c++/opencv_yolov4_c++/COCO/yolo-fastest.cfg";
	//string _model = "H:/VS/Opencv/program/opencv_yolov4_c++/opencv_yolov4_c++/opencv_yolov4_c++/COCO/yolo-fastest.weights";
	//string _labels = "H:/VS/Opencv/program/opencv_yolov4_c++/opencv_yolov4_c++/opencv_yolov4_c++/COCO/coco.names";

	Net net = readNetFromDarknet(_cfg, _model);

	net.setPreferableBackend(DNN_BACKEND_CUDA);
	net.setPreferableTarget(DNN_TARGET_CUDA);

	vector<string>outputLayerName = net.getUnconnectedOutLayersNames();
	for (int i = 0; i < outputLayerName.size(); i++)
	{
		cout << outputLayerName[i] << endl;
	}

	ifstream labels_file(_labels);		//_labels	labels_txt_file
	if (!labels_file.is_open())
	{
		cout << "can't open labels file" << endl;
		exit(-1);
	}



	string label;
	vector<string>labels;
	while (getline(labels_file, label))
	{
		labels.push_back(label);
	}

	VideoCapture capture;
	capture.open(1, CAP_DSHOW);	//capture.open("http://192.168.43.1:8081");	
	//capture.open("H:/VS/vedio/all.mp4");
	if (!capture.isOpened())
	{
		cout << "can't open camera" << endl;
		exit(-1);
	}
	Mat frame;
	capture.read(frame);

	//配置视频录制
	VideoWriter writer;
	int codec = VideoWriter::fourcc('M', 'J', 'P', 'G');  // 选择编码格式
	double fps = 25.0;  //设置视频帧率 
	string filename = "live.avi";  //保存的视频文件名称
	writer.open(filename, codec, fps, frame.size(), 1);  //创建保存视频文件的视频流

	while (capture.read(frame))
	{
		double start = getTickCount();
		//flip(frame, frame, 1);
		Mat inputBlob = blobFromImage(frame, 1 / 255.F, Size(416, 416), Scalar(), true, false);
		net.setInput(inputBlob);
		vector<Mat> prob;
		net.forward(prob, outputLayerName);

		vector<Rect>boxes;
		vector<int>classID;
		vector<float>confidences;
		for (int i = 0; i < prob.size(); i++)
		{
			for (int row = 0; row < prob[i].rows; row++)
			{
				Mat scores = prob[i].row(row).colRange(5, prob[i].cols);
				double confidence;
				Point maxloc;
				minMaxLoc(scores, NULL, &confidence, NULL, &maxloc);
				if (confidence > 0.5)
				{
					int center_x = prob[i].at<float>(row, 0) * frame.cols;
					int center_y = prob[i].at<float>(row, 1) * frame.rows;
					int width = prob[i].at<float>(row, 2) * frame.cols;
					int height = prob[i].at<float>(row, 3) * frame.rows;
					int x = center_x - width / 2;
					int y = center_y - height / 2;
					Rect box(x, y, width, height);
					boxes.push_back(box);
					classID.push_back(maxloc.x);
					confidences.push_back(float(confidence));
				}
			}
		}

		vector<int>indices;
		NMSBoxes(boxes, confidences, 0.5, 0.2, indices);
		for (int i = 0; i < indices.size(); i++)
		{
			int index = indices[i];
			Rect box = boxes[index];
			unsigned int center_x = (box.tl().x + box.br().x) / 2;
			unsigned int center_y = (box.tl().y + box.br().y) / 2;
			string className = labels[classID[index]];
			if (className == "CAR")
			{
				rectangle(frame, box, Scalar(0, 255, 0), 1, 8);
				putText(frame, className, box.tl(), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
				putText(frame, format("    : (%d , %d)", center_x, center_y), box.tl(), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 0), 1, 8);

				//将识别信息发送出去
				pData[2] = (unsigned char)(center_x >> 0X08);
				pData[3] = (unsigned char)(center_x & 0XFF);
				pData[4] = (unsigned char)(center_y >> 0X08);
				pData[5] = (unsigned char)(center_y & 0XFF);
				mySerialPort.WriteData((unsigned char*)pData, 6);
				printf(" className: (%d,    %d)\n", pData[2], pData[3]);
			}
		}

		double end = getTickCount();
		double run_time = (end - start) / getTickFrequency();
		double fps = 1 / run_time;
		putText(frame, format("FPS: %0.2f", fps), Point(20, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1, 8);
		imshow("Yolo-Fastest", frame);
		//writer.write(frame);  //把图像写入视频流

		char ch = waitKey(1);
		if (ch == 27)break;

	}
}

代码由三大块组成:
基于opencv库的视频流输入和输出视频保存


	VideoCapture capture;
	capture.open(1, CAP_DSHOW);	//capture.open("http://192.168.43.1:8081");	
	//capture.open("H:/VS/vedio/all.mp4");
	if (!capture.isOpened())
	{
		cout << "can't open camera" << endl;
		exit(-1);
	}
	Mat frame;
	capture.read(frame);

	//配置视频录制
	VideoWriter writer;
	int codec = VideoWriter::fourcc('M', 'J', 'P', 'G');  // 选择编码格式
	double fps = 25.0;  //设置视频帧率 
	string filename = "live.avi";  //保存的视频文件名称
	writer.open(filename, codec, fps, frame.size(), 1);  //创建保存视频文件的视频流

yolo模型训练得到的权重(图为1000张图的训练效果)
在这里插入图片描述

获取物体的中心点,并通过串口将数据传给单片机

//将识别信息发送出去
				pData[2] = (unsigned char)(center_x >> 0X08);
				pData[3] = (unsigned char)(center_x & 0XFF);
				pData[4] = (unsigned char)(center_y >> 0X08);
				pData[5] = (unsigned char)(center_y & 0XFF);

单片机端的数据接收代码

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	static u8 Res_1;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res_1 =USART_ReceiveData(USART1);	//读取接收到的数据
    if(USART1_RX_STA>0 || Res_1 == 0X61){
			USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res_1;
			USART1_RX_STA++;   
		}
		if(USART1_RX_STA == 6){
					if(USART1_RX_BUF[1] == 0X62){
						location[0] = (((short)USART1_RX_BUF[2]<<8)| USART1_RX_BUF[3]);
						location[1] = (((short)USART1_RX_BUF[4]<<8)| USART1_RX_BUF[5]);
						//location[2] = (short)USART1_RX_BUF[4];
					}
          USART1_RX_STA=0;
		}		
  } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 

单片机对步进电机云台进行控制的代码

if(location[0] < 200)
	{
		holder_conter(-1, 0);
	}
	
	else if(location[0] > 300)
	{
		holder_conter(1, 0);
	}
	else if(200 <= location[0] && location[0] <= 300)
	{
		holder_conter(0, 0);		
	}
	

	if(location[1] < 200)
	{
		holder_conter(0, -1);
	}
	
	else if(location[1] > 300)
	{
		holder_conter(0, 1);
	}
	else if(200 <= location[1] && location[0] <= 300)
	{
		holder_conter(0, 0);		
	}	

单片机的云台控制代码,主要为控制步进电机的运动

void holder_conter(int x, int y)
{
	if(x > 0)
	{
		X_Pin = 1;
		pulse_putput_x(1000, 1);
	}
	else if(x < 0)
	{
		X_Pin = 0;
		pulse_putput_x(1000, 1);
	}
	else if(x == 0)
	{
		X_Pin = 1;
		pulse_putput_x(1000, 0);
	}
	
	
		if(y > 0)
	{
		Y_Pin = 1;
		pulse_putput_y(1000, 1);
	}
	else if(y < 0)
	{
		Y_Pin = 0;
		pulse_putput_y(1000, 1);
	}
	else if(y == 0)
	{
		Y_Pin = 1;
		pulse_putput_y(1000, 0);
	}
	
}



对步进电机的控制可以参考:https://blog.csdn.net/ORANGEbb/article/details/109287780?spm=1001.2014.3001.5501

以上仅为个人拙见,有错误请指正,谢谢!
有问题或者需要相关资料,请私信博主
请看官哥哥三连支持一下谢谢

  • 2
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Orange--Lin

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值