使用 C++ 呼叫 YOLOv3 模型進行物體檢測

ttocr、com發表於2024-12-05
  1. 環境準備
    首先,確保你已經安裝了以下工具:

OpenCV:用於影像處理。
Darknet:用於 YOLO 模型的推理。
C++ 編譯器:如 g++。
2. 安裝 Darknet
克隆 Darknet 倉庫並進入目錄:

bash

git clone https://github.com/pjreddie/darknet.git
cd darknet
使用 Makefile 編譯 Darknet(如果使用 GPU 支援,記得修改 Makefile,啟用 GPU 和 CUDNN):

bash

make
下載 YOLOv3 的預訓練權重檔案:

bash

wget https://pjreddie.com/media/files/yolov3.weights
3. 使用 C++ 進行物體檢測
接下來我們編寫一個簡單的 C++ 程式,使用 YOLOv3 模型進行物體檢測。

C++ 程式 (yolo_detect.cpp)
cpp

include

include <opencv2/opencv.hpp>

include <opencv2/dnn.hpp>

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

// 載入 YOLO 模型檔案
const String modelConfiguration = "cfg/yolov3.cfg"; // YOLO 配置檔案路徑
const String modelWeights = "yolov3.weights"; // YOLO 權重檔案路徑
const String classesFile = "cfg/coco.names"; // 類別檔案,包含檢測物體的類別名稱

vector classNames;

// 載入類別檔案
void loadClassNames(const string& filename) {
ifstream classFile(filename);
string line;
while (getline(classFile, line)) {
classNames.push_back(line);
}
}

// 載入 YOLO 模型
Net loadYOLOModel() {
// 載入 YOLO 配置檔案和權重檔案
Net net = readNetFromDarknet(modelConfiguration, modelWeights);
return net;
}

// 物體檢測函式
void detectObjects(Mat& frame, Net& net) {
Mat blob;
// 將影像轉換為 blob(神經網路的輸入格式)
blobFromImage(frame, blob, 1/255.0, Size(416, 416), Scalar(), true, false);

// 將 blob 設定為網路輸入
net.setInput(blob);

// 獲取網路的所有輸出層
vector<String> outNames = net.getUnconnectedOutLayersNames();
vector<Mat> outs;
net.forward(outs, outNames);

// 解析 YOLO 輸出
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) {
        // 獲取每個框的機率
        float confidence = data[4];
        if (confidence > 0.5) {
            // 計算類別
            int classID = -1;
            float maxClassProb = -1;
            for (int k = 5; k < outs[i].cols; ++k) {
                if (data[k] > maxClassProb) {
                    maxClassProb = data[k];
                    classID = k - 5;
                }
            }

            // 如果類別有效,畫出矩形框
            if (classID >= 0) {
                int x = (int)(data[0] * frame.cols);
                int y = (int)(data[1] * frame.rows);
                int w = (int)(data[2] * frame.cols);
                int h = (int)(data[3] * frame.rows);

                // 繪製邊界框
                rectangle(frame, Point(x, y), Point(x + w, y + h), Scalar(0, 255, 0), 2);

                // 在框上寫上類別名
                putText(frame, classNames[classID], Point(x, y - 5), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 2);
            }
        }
    }
}

}

int main() {
// 載入類別名稱
loadClassNames(classesFile);

// 載入 YOLO 模型
Net net = loadYOLOModel();

// 開啟影片或攝像頭
VideoCapture cap("test.jpg");  // 可以換成影片路徑或者攝像頭索引(0 為預設攝像頭)
if (!cap.isOpened()) {
    cerr << "Error: Cannot open video stream or image." << endl;
    return -1;
}

// 迴圈讀取每一幀
while (true) {
    Mat frame;
    cap >> frame;  // 讀取一幀

    if (frame.empty()) {
        break;  // 如果沒有幀則退出
    }

    // 檢測物體
    detectObjects(frame, net);

    // 顯示結果
    imshow("YOLO Object Detection", frame);

    // 按下 'q' 鍵退出
    if (waitKey(1) == 'q') {
        break;
    }
}

return 0;

}
4. 編譯和執行
確保你已經安裝了 OpenCV 和 C++ 編譯器。
編譯 C++ 程式:
bash更多內容訪問ttocr.com或聯絡1436423940

g++ -o yolo_detect yolo_detect.cpp pkg-config --cflags --libs opencv4
執行程式:
bash

./yolo_detect
5. 程式說明
載入 YOLO 模型: 我們使用 cv::dnn::readNetFromDarknet 來載入 YOLOv3 的配置和權重檔案。
物體檢測: 在 detectObjects 函式中,我們將影像轉換為模型可以接受的輸入格式(blob),然後透過 net.forward() 進行推理,得到檢測結果。我們從每個檢測框中提取置信度,並在影像中繪製邊界框。
OpenCV 顯示影像: 使用 imshow 展示檢測結果,按 q 鍵退出。
6. 結果展示
執行程式後,YOLO 模型會自動檢測影像中的物體,並顯示帶有邊界框的影像。

相關文章