使用 C 语言实现物体检测(YOLO)

物体检测是计算机视觉中的核心任务之一。在这篇文章中,我们将使用 C 语言结合 OpenCV 和 YOLO 模型,展示如何在图像中检测物体的位置。YOLO(You Only Look Once)是一种高效的深度学习模型,广泛应用于物体检测任务。虽然 C 语言本身不具备深度学习库,但 OpenCV 提供了足够的支持来加载、处理和推理图像。

环境准备

  1. 安装 OpenCV
    首先,我们需要安装 OpenCV 库,以便能够加载图像并处理其内容。在 Ubuntu 系统上,你可以使用以下命令安装 OpenCV:

bash
更多内容访问ttocr.com或联系1436423940
sudo apt-get update
sudo apt-get install libopencv-dev
2. 获取 YOLO 模型文件
下载 YOLOv3 的配置文件和预训练权重文件(yolov3.cfg 和 yolov3.weights)。此外,还需要一个标签文件(coco.names),该文件包含 YOLO 能够检测的物体类别。

你可以从 YOLO 的官方网站下载这些文件:

YOLOv3 cfg 文件
YOLOv3 预训练权重
COCO 标签文件
编写 C 语言代码

  1. 初始化 OpenCV 和 YOLO 模型
    我们将加载 YOLO 模型,并使用 OpenCV 进行物体检测。以下是使用 C 语言调用 YOLO 模型进行物体检测的示例代码:

c

include <opencv2/opencv.hpp>

include <opencv2/dnn.hpp>

include

include

include

using namespace cv;
using namespace std;

// 函数:读取 COCO 标签文件
vector loadClassNames(const string &filename) {
vector classNames;
ifstream ifs(filename);
string line;
while (getline(ifs, line)) {
classNames.push_back(line);
}
return classNames;
}

// 函数:绘制检测框
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat &frame, const vector &classNames) {
rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 255, 0), 2);
string label = format("%.2f", conf);
if (!classNames.empty()) {
label = classNames[classId] + ":" + label;
}
putText(frame, label, Point(left, top - 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 2);
}

int main(int argc, char** argv) {
// 检查输入参数
if (argc != 2) {
cerr << "Usage: ./yolo_detector <image_file>" << endl;
return -1;
}

// 加载 YOLO 模型
String modelConfiguration = "yolov3.cfg";
String modelWeights = "yolov3.weights";
String classFile = "coco.names";

// 加载网络和类名
vector<string> classNames = loadClassNames(classFile);
Net net = readNetFromDarknet(modelConfiguration, modelWeights);

// 加载图片
Mat frame = imread(argv[1]);
if (frame.empty()) {
    cerr << "Image not found!" << endl;
    return -1;
}

// 处理图片,创建 Blob
Mat blob;
blobFromImage(frame, blob, 1.0 / 255.0, Size(416, 416), Scalar(0, 0, 0), true, false);
net.setInput(blob);

// 获取 YOLO 网络的输出层
vector<Mat> outs;
vector<String> outNames = net.getUnconnectedOutLayersNames();
net.forward(outs, outNames);

// 分析网络输出,进行物体检测
vector<int> classIds;
vector<float> confidences;
vector<Rect> boxes;
for (size_t i = 0; i < outs.size(); ++i) {
    float* data = (float*)outs[i].data;
    for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols) {
        Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
        Point classIdPoint;
        double confidence;
        minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
        if (confidence > 0.5) {
            int centerX = (int)(data[0] * frame.cols);
            int centerY = (int)(data[1] * frame.rows);
            int width = (int)(data[2] * frame.cols);
            int height = (int)(data[3] * frame.rows);
            int left = centerX - width / 2;
            int top = centerY - height / 2;
            classIds.push_back(classIdPoint.x);
            confidences.push_back((float)confidence);
            boxes.push_back(Rect(left, top, width, height));
        }
    }
}

// 非最大值抑制
vector<int> indices;
NMSBoxes(boxes, confidences, 0.5, 0.4, indices);

// 绘制结果
for (size_t i = 0; i < indices.size(); ++i) {
    int idx = indices[i];
    drawPred(classIds[idx], confidences[idx], boxes[idx].x, boxes[idx].y,
             boxes[idx].x + boxes[idx].width, boxes[idx].y + boxes[idx].height, frame, classNames);
}

// 显示结果
imshow("Detected Objects", frame);
waitKey(0);

return 0;

}
2. 编译并运行程序
编译命令
确保你已安装 OpenCV 并配置好 CMake 或者直接使用命令行进行编译。

bash

g++ -o yolo_detector yolo_detector.cpp pkg-config --cflags --libs opencv4
运行程序

./yolo_detector test.jpg
3. 代码解释
加载 YOLO 模型:

使用 cv::dnn::readNetFromDarknet() 函数加载 YOLO 配置文件和权重文件,构建网络。
图像预处理:

使用 blobFromImage() 函数将输入图像转换为网络所需的输入格式。
推理:

使用 net.forward() 函数进行前向推理,获取检测结果。
解析输出:

解析 YOLO 输出的 bounding box 信息,包括物体的类别、置信度、位置等。
非最大抑制(NMS):

使用 cv::dnn::NMSBoxes() 函数去除多余的重叠框,确保检测结果清晰。
绘制结果:

使用 rectangle() 和 putText() 函数在图像上绘制物体框,并标注物体类别和置信度。

posted @   ttocr、com  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示