物体检测是计算机视觉中的核心任务之一。在这篇文章中,我们将使用 C 语言结合 OpenCV 和 YOLO 模型,展示如何在图像中检测物体的位置。YOLO(You Only Look Once)是一种高效的深度学习模型,广泛应用于物体检测任务。虽然 C 语言本身不具备深度学习库,但 OpenCV 提供了足够的支持来加载、处理和推理图像。
环境准备
- 安装 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 语言代码
- 初始化 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
vector
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
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() 函数在图像上绘制物体框,并标注物体类别和置信度。