File size: 5,176 Bytes
7c098ec e9eb33d 7c098ec e9eb33d 7c098ec e9eb33d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | #include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <algorithm>
#include <array>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
using namespace cv;
static std::string argVal(int argc, char** argv, const std::string& key, const std::string& def)
{
for (int i = 1; i + 1 < argc; ++i)
if (key == argv[i]) return argv[i + 1];
return def;
}
struct Layer { float mn, mx; std::vector<int> ars; int step, fm; };
int main(int argc, char** argv)
{
std::string model = argVal(argc, argv, "--model", "opencv_face_detector_uint8_2026jul.onnx");
std::string image = argVal(argc, argv, "--image", "example_outputs/input_image.png");
std::string output = argVal(argc, argv, "--output", "example_outputs/output_image.png");
float thr = std::stof(argVal(argc, argv, "--conf", "0.4"));
const int sz = 300;
Mat img = imread(image);
if (img.empty())
{
std::cerr << "could not read image: " << image << std::endl;
return 1;
}
Mat inp;
resize(img, inp, Size(sz, sz));
inp.convertTo(inp, CV_32F);
subtract(inp, Scalar(104, 177, 123), inp);
if (!inp.isContinuous()) inp = inp.clone();
int blobShape[] = {1, sz, sz, 3};
Mat blob(4, blobShape, CV_32F, inp.data);
dnn::Net net = dnn::readNetFromONNX(model);
net.setInput(blob);
std::vector<Mat> outs;
net.forward(outs, net.getUnconnectedOutLayersNames());
const float* loc = nullptr;
const float* conf = nullptr;
for (size_t i = 0; i < outs.size(); ++i)
{
const Mat& o = outs[i];
size_t tot = o.total();
const float* p = (const float*)o.data;
if (tot == 35568) loc = p;
else if (tot == 17784) conf = p;
}
std::vector<Layer> layers = {
{30, 60, {2}, 8, 38},
{60, 111, {2, 3}, 16, 19},
{111, 162, {2, 3}, 32, 10},
{162, 213, {2, 3}, 64, 5},
{213, 264, {2}, 100, 5},
{264, 315, {2}, 300, 5},
};
std::vector<Vec4f> priors;
for (const Layer& L : layers)
{
std::vector<float> ratios = {1.0f};
for (int a : L.ars) { ratios.push_back((float)a); ratios.push_back(1.0f / a); }
for (int y = 0; y < L.fm; ++y)
for (int x = 0; x < L.fm; ++x)
{
float cx = (x + 0.5f) * L.step;
float cy = (y + 0.5f) * L.step;
std::vector<Vec2f> boxes = {{L.mn, L.mn}, {std::sqrt(L.mn * L.mx), std::sqrt(L.mn * L.mx)}};
for (size_t k = 1; k < ratios.size(); ++k)
{
float a = ratios[k];
boxes.push_back({L.mn * std::sqrt(a), L.mn / std::sqrt(a)});
}
for (const Vec2f& b : boxes)
priors.push_back({cx, cy, b[0], b[1]});
}
}
const float var[4] = {0.1f, 0.1f, 0.2f, 0.2f};
int n = (int)priors.size();
std::vector<Rect2f> boxes;
std::vector<float> scores;
for (int i = 0; i < n; ++i)
{
float c0 = conf[i * 2], c1 = conf[i * 2 + 1];
float m = std::max(c0, c1);
float e0 = std::exp(c0 - m), e1 = std::exp(c1 - m);
float s = e1 / (e0 + e1);
if (s <= thr) continue;
float pcx = priors[i][0] / sz, pcy = priors[i][1] / sz;
float pw = priors[i][2] / sz, ph = priors[i][3] / sz;
float cx = pcx + loc[i * 4] * var[0] * pw;
float cy = pcy + loc[i * 4 + 1] * var[1] * ph;
float bw = pw * std::exp(loc[i * 4 + 2] * var[2]);
float bh = ph * std::exp(loc[i * 4 + 3] * var[3]);
boxes.push_back(Rect2f(cx - bw / 2, cy - bh / 2, bw, bh));
scores.push_back(s);
}
std::vector<int> order(scores.size());
for (size_t i = 0; i < order.size(); ++i) order[i] = (int)i;
std::sort(order.begin(), order.end(), [&](int a, int b){ return scores[a] > scores[b]; });
std::vector<char> removed(order.size(), 0);
std::vector<int> pick;
for (size_t oi = 0; oi < order.size(); ++oi)
{
if (removed[oi]) continue;
int i = order[oi];
pick.push_back(i);
for (size_t oj = oi + 1; oj < order.size(); ++oj)
{
if (removed[oj]) continue;
int j = order[oj];
const Rect2f& a = boxes[i];
const Rect2f& b = boxes[j];
float xx1 = std::max(a.x, b.x), yy1 = std::max(a.y, b.y);
float xx2 = std::min(a.x + a.width, b.x + b.width);
float yy2 = std::min(a.y + a.height, b.y + b.height);
float inter = std::max(0.f, xx2 - xx1) * std::max(0.f, yy2 - yy1);
float iou = inter / (a.area() + b.area() - inter + 1e-9f);
if (iou > 0.3f) removed[oj] = 1;
}
}
int W = img.cols, H = img.rows;
for (int i : pick)
{
const Rect2f& b = boxes[i];
rectangle(img, Point(int(b.x * W), int(b.y * H)),
Point(int((b.x + b.width) * W), int((b.y + b.height) * H)), Scalar(0, 255, 0), 2);
}
imwrite(output, img);
std::cout << "opencv_face_detector_uint8 " << pick.size() << " faces" << std::endl;
return 0;
}
|