Repository: ShiqiYu/libfacedetection
File: opencv_dnn/cpp/detect-image.cpp (C++)

Code before:
int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cout << "Usage: " << argv[0] << " <image_file_name> <net_file_name>\n";
        return -1;
    }

    // Build blob
    cv::Mat img = cv::imread(argv[1], cv::IMREAD_COLOR);
    if (img.empty()) {
        std::cerr << "Cannot load the image file " << argv[1] << ".\n";
        return -1;
    }
    cv::Size img_shape = img.size();
    cv::Mat blob = cv::dnn::blobFromImage(img);

    // Load .onnx model using OpenCV's DNN module
    cv::dnn::Net net = cv::dnn::readNet(argv[2]);
    net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);

    // Inference hyperparameters
    float conf_thresh = 0.6;
    float nms_thresh = 0.3;
    int keep_top_k = 750;
    // Result
    bool vis = true;
    std::string save_fpath = "./result.jpg";

    // Forward
    std::vector<cv::String> output_names = { "loc", "conf", "iou" };
    std::vector<cv::Mat> output_blobs;
    net.setInput(blob);
    net.forward(output_blobs, output_names);

    // Decode bboxes, landmarks and scores
    PriorBox pb(img_shape, img_shape);
    std::vector<Face> dets = pb.decode(output_blobs[0], output_blobs[1], output_blobs[2], conf_thresh);

    // NMS
    std::vector<Face> nms_dets;
    if (dets.size() > 1) {
        std::vector<cv::Rect> face_boxes;
        std::vector<float> face_scores;
        for (auto d: dets) {
            face_boxes.push_back(d.bbox_tlwh);
            face_scores.push_back(d.score);
        }
        std::vector<int> keep_idx;
        cv::dnn::NMSBoxes(face_boxes, face_scores, conf_thresh, nms_thresh, keep_idx, 1.f, keep_top_k);
        for (size_t i = 0; i < keep_idx.size(); i++) {
            size_t idx = keep_idx[i];

Review comment (suggestion):
You can make it read from `argv`. Setting this to true by default is not good for compability since we cannot assume users want to visualize and their environment is ready (GTK is required and X11 needed to be enable over SSH).

Code after:
int main(int argc, char* argv[]) {
    if (argc != 3 && argc !=4) {
        std::cout << "Usage: " << argv[0] << " <image_file_name> <net_file_name> [<visualization_flag> default false] \n";
        return -1;
    }

    // Build blob
    cv::Mat img = cv::imread(argv[1], cv::IMREAD_COLOR);
    if (img.empty()) {
        std::cerr << "Cannot load the image file " << argv[1] << ".\n";
        return -1;
    }
    cv::Size img_shape = img.size();
    cv::Mat blob = cv::dnn::blobFromImage(img);

    // Load .onnx model using OpenCV's DNN module
    cv::dnn::Net net = cv::dnn::readNet(argv[2]);
    net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
    net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);

    // Inference hyperparameters
    float conf_thresh = 0.6;
    float nms_thresh = 0.3;
    int keep_top_k = 750;
    // Result
    bool vis = false;
    if (argc==4 && std::string(argv[3]) == "true") {
        vis = true;
    }
    std::string save_fpath = "./result.jpg";

    // Forward
    std::vector<cv::String> output_names = { "loc", "conf", "iou" };
    std::vector<cv::Mat> output_blobs;
    net.setInput(blob);
    net.forward(output_blobs, output_names);

    // Decode bboxes, landmarks and scores
    PriorBox pb(img_shape, img_shape);
    std::vector<Face> dets = pb.decode(output_blobs[0], output_blobs[1], output_blobs[2], conf_thresh);

    // NMS
    std::vector<Face> nms_dets;
    if (dets.size() > 1) {
        std::vector<cv::Rect> face_boxes;
        std::vector<float> face_scores;
        for (auto d: dets) {
            face_boxes.push_back(d.bbox_tlwh);
            face_scores.push_back(d.score);
        }
        std::vector<int> keep_idx;