效果视频
基于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
以上仅为个人拙见,有错误请指正,谢谢!
有问题或者需要相关资料,请私信博主
请看官哥哥三连支持一下谢谢