SavyaSanchi-Sharma
pivoted from onnx to opencv 5
7c098ec
Raw
History Blame
5.18 kB
#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;
}