在终端中输入以下命令
sudo apt-get update //更新包列表
sudo apt-get install build-essential //安装构建必需工具
sudo apt-get install wget //安装wget
官网:https://docs.conda.io/en/latest/miniconda.html
或者
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
然后给文件添加运行权限
chmod +x Miniconda3-latest-Linux-x86_64.sh
./Miniconda3-latest-Linux-x86_64.sh
照着提示按步骤安装,过程中可以修改安装路径
sudo vim ~/.bashrc //打开.bashrc文件
在文件末尾处添加
export PATH="/home/你的用户名/miniconda/bin:$PATH" //这个是默认路径下的
保存退出后,使配置生效
source ~/.bashrc
可以添加清华的conda源来使用
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --set show_channel_urls yes
conda create -n yolov5 python=3.8 //创建名为yolov5且python版本3.8的虚拟环境
conda activate yolov5 //用来激活环境的
在该环境下可以使用conda install来安装包
官网:https://github.com/ultralytics/yolov5
点击全部发行版,选择自己需要的yolov5版本的源代码和预训练权重文件下载
把预训练模型放入yolov5文件夹后,打开requirements.txt。
#onnx>=1.9.0 # ONNX export
#onnx-simplifier>=0.4.1 # ONNX simplifier
将这两行开头的的#号去掉,保存,然后在之前创建的conda环境中执行
pip install -r requirements.txt
python export.py --weights yolov5m6.pt --include onnx --imgsz 640 640
我用一个json文件存放模型的对应参数信息,调用时将从文件里读取存入到一个封装的struct结构体里。
struct Net5_config
{
std::vector CONFIDENCE_THRESHOLD; // 置信度
std::vector NMS_THRESHOLD; // nms阙值
std::vector SCORE_THRESHOLD; //得分阙值
std::vector INPUT_WIDTH; // 输入图像的宽度
std::vector INPUT_HEIGHT; // 输入图像的长度
std::vector classesFile; //coco.name等物品分类名称文件路径
std::vector modelWeights; //模型权重文件路径
std::vector netname; //模型权重文件名称
int id = 0; //用于判断当前使用哪个模型
};
然后又写了一个类来实现调用
class Recognizerv5
{
public:
Recognizerv5(Net5_config config); //yolo初始化配置
bool IdentifyTarget(cv::Mat &frame, Result &output); //yolo模型推理
bool drawRect(cv::Mat &frame, Result &output); //将识别结果画出来
private:
float confThreshold; //置信度阙值
float nmsThreshold; //nms阙值
float SCORE_THRESHOLD; //得分阙值
int inpWidth; //图片输入宽度
int inpHeight; //图片输入高度
char netname[20]; //使用的模型的名字
std::vector classes; //物品类别目录
cv::dnn::Net net; //用于模型推理
};
//存放识别的定位信息
struct Result
{
std::vector x;
std::vector y;
std::vector width;
std::vector height;
std::vector name;
};
//清空定位信息
void Result_clear(struct Result &p)
{
p.name.clear();
p.x.clear();
p.y.clear();
p.height.clear();
p.width.clear();
}
//用于存放识别出来的物品框的信息
struct Detection
{
int class_id; //物品类别下标
float confidence; //置信度
cv::Rect box; //方框信息
};
//用于复制图像
cv::Mat format_yolov5(const cv::Mat &source)
{
int col = source.cols;
int row = source.rows;
int _max = MAX(col, row);
cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
source.copyTo(result(cv::Rect(0, 0, col, row)));
return result;
}
//yolo初始化配置
Recognizerv5::Recognizerv5(Net5_config config)
{
//将数据从struct结构体里传入class里
std::cout << "Net use " << config.netname[config.id] << std::endl;
this->confThreshold = config.CONFIDENCE_THRESHOLD[config.id];
this->nmsThreshold = config.NMS_THRESHOLD[config.id];
this->inpWidth = config.INPUT_WIDTH[config.id];
this->inpHeight = config.INPUT_HEIGHT[config.id];
this->SCORE_THRESHOLD = config.SCORE_THRESHOLD[config.id];
strcpy(this->netname, config.netname[config.id].c_str());
std::ifstream ifs(config.classesFile[config.id].c_str());
std::string line;
while (getline(ifs, line))
this->classes.push_back(line);
//使用opencv的dnn模块读取模型文件
auto result = cv::dnn::readNet(config.modelWeights[config.id]);
//设置运行方式
std::cout << "Running on CPU\n";
result.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
result.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
//将读取结果存入net
this->net = result;
}
//yolo模型推理
bool Recognizerv5::IdentifyTarget(cv::Mat &frame, Result &output)
{
std::vector p;
cv::Mat blob;
auto input_image = format_yolov5(frame);
//为推理模型设置参数
cv::dnn::blobFromImage(input_image, blob, 1. / 255., cv::Size(this->inpWidth, this->inpHeight), cv::Scalar(), true, false);
this->net.setInput(blob);
//网络推理
std::vector outputs;
this->net.forward(outputs, net.getUnconnectedOutLayersNames());
float x_factor = input_image.cols / this->inpWidth;
float y_factor = input_image.rows / this->inpHeight;
float *data = (float *)outputs[0].data;
const int dimensions = 85;
const int rows = 25200;
std::vector class_ids;
std::vector confidences;
std::vector boxes;
//对推理的结果进行检测
for (int i = 0; i < rows; ++i)
{
float confidence = data[4];
if (confidence >= this->confThreshold) //如果置信度大于设置的阙值说明是可信的
{
float *classes_scores = data + 5;
cv::Mat scores(1, this->classes.size(), CV_32FC1, classes_scores);
cv::Point class_id;
double max_class_score;
minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
if (max_class_score > SCORE_THRESHOLD) //如果检测的分数大于阙值,则是可信的
{
confidences.push_back(confidence);
class_ids.push_back(class_id.x);
float x = data[0];
float y = data[1];
float w = data[2];
float h = data[3];
int left = int((x - 0.5 * w) * x_factor);
int top = int((y - 0.5 * h) * y_factor);
int width = int(w * x_factor);
int height = int(h * y_factor);
boxes.push_back(cv::Rect(left, top, width, height));
}
}
data += 85;
}
std::vector nms_result;
//进行极大值抑制nms算法
cv::dnn::NMSBoxes(boxes, confidences,SCORE_THRESHOLD,this->nmsThreshold, nms_result,0.8);//eta这个参数默认1.0,范围0.1-1.0,设置代表启用soft-nms算法,top_k表示保留框的个数
//将结果存入output
for (int i = 0; i < nms_result.size(); i++)
{
int idx = nms_result[i];
Detection result;
result.class_id = class_ids[idx];
result.confidence = confidences[idx];
result.box = boxes[idx];
p.push_back(result);
}
int detections = p.size();
for (int i = 0; i < detections; ++i)
{
auto detection = p[i];
auto box = detection.box;
auto classId = detection.class_id;
output.name.push_back(this->classes[classId]);
output.x.push_back(box.x);
output.y.push_back(box.y);
output.width.push_back(box.width);
output.height.push_back(box.height);
}
return true;
}
//将识别结果画出来
bool Recognizerv5::drawRect(cv::Mat &frame, Result &output)
{
for (int i = 0; i < output.name.size(); i++)
{
cv::Rect box(output.x[i], output.y[i], output.width[i], output.height[i]);
cv::rectangle(frame, box, cv::Scalar(0, 255, 0), 3);
cv::rectangle(frame, cv::Point(box.x, box.y - 20), cv::Point(box.x + box.width, box.y), cv::Scalar(0, 255, 0), cv::FILLED);
cv::putText(frame, output.name[i].c_str(), cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
}
return true;
}
以上可以分装在namespcae里便于使用
main函数
int main(int argc, char const *argv[]){
cv::VideoCapture camera=cv::VideoCapture(0);
if (camera.isOpened() == false)
{
std::cout<< "camera couldn't open" <> image;
if (image.empty() == true)
{
break;
}
cv::namedWindow("test",cv::WINDOW_NORMAL);
YOLO::Result_clear(yolo_result);
recognizer.IdentifyTarget(image, yolo_result);
recognizer.drawRect(image, yolo_result);
cv::imshow("test", image);
if (cv::waitKey(1) > 0)
{
break;
}
}
camera.release();
cv::destroyAllWindows();
return 0;
}