123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- // This file is part of OpenCV project.
- // It is subject to the license terms in the LICENSE file found in the top-level directory
- // of this distribution and at http://opencv.org/license.html.
- //
- // Copyright (C) 2020 Intel Corporation
- #ifndef OPENCV_GAPI_PARSERS_TESTS_COMMON_HPP
- #define OPENCV_GAPI_PARSERS_TESTS_COMMON_HPP
- #include "gapi_tests_common.hpp"
- #include "../../include/opencv2/gapi/infer/parsers.hpp"
- namespace opencv_test
- {
- class ParserSSDTest
- {
- public:
- cv::Mat generateSSDoutput(const cv::Size& in_sz)
- {
- constexpr int maxN = 200;
- constexpr int objSize = 7;
- std::vector<int> dims{ 1, 1, maxN, objSize };
- cv::Mat mat(dims, CV_32FC1);
- auto data = mat.ptr<float>();
- for (int i = 0; i < maxN; ++i)
- {
- float* it = data + i * objSize;
- auto ssdIt = generateItem(i, in_sz);
- it[0] = ssdIt.image_id;
- it[1] = ssdIt.label;
- it[2] = ssdIt.confidence;
- it[3] = ssdIt.rc_left;
- it[4] = ssdIt.rc_top;
- it[5] = ssdIt.rc_right;
- it[6] = ssdIt.rc_bottom;
- }
- return mat;
- }
- void parseSSDref(const cv::Mat& in_ssd_result,
- const cv::Size& in_size,
- const float confidence_threshold,
- const bool alignment_to_square,
- const bool filter_out_of_bounds,
- std::vector<cv::Rect>& out_boxes)
- {
- out_boxes.clear();
- const auto &in_ssd_dims = in_ssd_result.size;
- CV_Assert(in_ssd_dims.dims() == 4u);
- const int MAX_PROPOSALS = in_ssd_dims[2];
- const int OBJECT_SIZE = in_ssd_dims[3];
- CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
- const float *data = in_ssd_result.ptr<float>();
- cv::Rect surface({0,0}, in_size), rc;
- float image_id, confidence;
- int label;
- for (int i = 0; i < MAX_PROPOSALS; ++i)
- {
- std::tie(rc, image_id, confidence, label)
- = extract(data + i*OBJECT_SIZE, in_size);
- if (image_id < 0.f)
- {
- break; // marks end-of-detections
- }
- if (confidence < confidence_threshold)
- {
- continue; // skip objects with low confidence
- }
- if (alignment_to_square)
- {
- adjustBoundingBox(rc);
- }
- const auto clipped_rc = rc & surface;
- if (filter_out_of_bounds)
- {
- if (clipped_rc.area() != rc.area())
- {
- continue;
- }
- }
- out_boxes.emplace_back(clipped_rc);
- }
- }
- void parseSSDBLref(const cv::Mat& in_ssd_result,
- const cv::Size& in_size,
- const float confidence_threshold,
- const int filter_label,
- std::vector<cv::Rect>& out_boxes,
- std::vector<int>& out_labels)
- {
- out_boxes.clear();
- out_labels.clear();
- const auto &in_ssd_dims = in_ssd_result.size;
- CV_Assert(in_ssd_dims.dims() == 4u);
- const int MAX_PROPOSALS = in_ssd_dims[2];
- const int OBJECT_SIZE = in_ssd_dims[3];
- CV_Assert(OBJECT_SIZE == 7); // fixed SSD object size
- cv::Rect surface({0,0}, in_size), rc;
- float image_id, confidence;
- int label;
- const float *data = in_ssd_result.ptr<float>();
- for (int i = 0; i < MAX_PROPOSALS; i++)
- {
- std::tie(rc, image_id, confidence, label)
- = extract(data + i*OBJECT_SIZE, in_size);
- if (image_id < 0.f)
- {
- break; // marks end-of-detections
- }
- if (confidence < confidence_threshold ||
- (filter_label != -1 && label != filter_label))
- {
- continue; // filter out object classes if filter is specified
- }
- out_boxes.emplace_back(rc & surface);
- out_labels.emplace_back(label);
- }
- }
- private:
- void adjustBoundingBox(cv::Rect& boundingBox)
- {
- auto w = boundingBox.width;
- auto h = boundingBox.height;
- boundingBox.x -= static_cast<int>(0.067 * w);
- boundingBox.y -= static_cast<int>(0.028 * h);
- boundingBox.width += static_cast<int>(0.15 * w);
- boundingBox.height += static_cast<int>(0.13 * h);
- if (boundingBox.width < boundingBox.height)
- {
- auto dx = (boundingBox.height - boundingBox.width);
- boundingBox.x -= dx / 2;
- boundingBox.width += dx;
- }
- else
- {
- auto dy = (boundingBox.width - boundingBox.height);
- boundingBox.y -= dy / 2;
- boundingBox.height += dy;
- }
- }
- std::tuple<cv::Rect, float, float, int> extract(const float* it,
- const cv::Size& in_size)
- {
- float image_id = it[0];
- int label = static_cast<int>(it[1]);
- float confidence = it[2];
- float rc_left = it[3];
- float rc_top = it[4];
- float rc_right = it[5];
- float rc_bottom = it[6];
- cv::Rect rc; // map relative coordinates to the original image scale
- rc.x = static_cast<int>(rc_left * in_size.width);
- rc.y = static_cast<int>(rc_top * in_size.height);
- rc.width = static_cast<int>(rc_right * in_size.width) - rc.x;
- rc.height = static_cast<int>(rc_bottom * in_size.height) - rc.y;
- return std::make_tuple(rc, image_id, confidence, label);
- }
- int randInRange(const int start, const int end)
- {
- GAPI_Assert(start <= end);
- return theRNG().uniform(start, end);
- }
- cv::Rect generateBox(const cv::Size& in_sz)
- {
- // Generated rectangle can reside outside of the initial image by border pixels
- constexpr int border = 10;
- constexpr int minW = 16;
- constexpr int minH = 16;
- cv::Rect box;
- box.width = randInRange(minW, in_sz.width + 2*border);
- box.height = randInRange(minH, in_sz.height + 2*border);
- box.x = randInRange(-border, in_sz.width + border - box.width);
- box.y = randInRange(-border, in_sz.height + border - box.height);
- return box;
- }
- struct SSDitem
- {
- float image_id = 0.0f;
- float label = 0.0f;
- float confidence = 0.0f;
- float rc_left = 0.0f;
- float rc_top = 0.0f;
- float rc_right = 0.0f;
- float rc_bottom = 0.0f;
- };
- SSDitem generateItem(const int i, const cv::Size& in_sz)
- {
- const auto normalize = [](int v, int range) { return static_cast<float>(v) / range; };
- SSDitem it;
- it.image_id = static_cast<float>(i);
- it.label = static_cast<float>(randInRange(0, 9));
- it.confidence = theRNG().uniform(0.f, 1.f);
- auto box = generateBox(in_sz);
- it.rc_left = normalize(box.x, in_sz.width);
- it.rc_right = normalize(box.x + box.width, in_sz.width);
- it.rc_top = normalize(box.y, in_sz.height);
- it.rc_bottom = normalize(box.y + box.height, in_sz.height);
- return it;
- }
- };
- class ParserYoloTest
- {
- public:
- cv::Mat generateYoloOutput(const int num_classes, std::pair<bool,int> dims_config = {false, 4})
- {
- bool one_dim = false;
- int num_dims = 0;
- std::tie(one_dim, num_dims) = dims_config;
- GAPI_Assert(num_dims <= 4);
- GAPI_Assert((!one_dim && num_dims >= 3) ||
- ( one_dim && num_dims >= 1));
- std::vector<int> dims(num_dims, 1);
- if (one_dim) {
- dims.back() = (num_classes+5)*5*13*13;
- } else {
- dims.back() = (num_classes+5)*5;
- dims[num_dims-2] = 13;
- dims[num_dims-3] = 13;
- }
- cv::Mat mat(dims, CV_32FC1);
- auto data = mat.ptr<float>();
- const size_t range = std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<int>());
- cv::RNG& rng = theRNG();
- for (size_t i = 0; i < range; ++i)
- {
- data[i] = rng.uniform(0.f, 1.f);
- }
- return mat;
- }
- void parseYoloRef(const cv::Mat& in_yolo_result,
- const cv::Size& in_size,
- const float confidence_threshold,
- const float nms_threshold,
- const int num_classes,
- const std::vector<float>& anchors,
- std::vector<cv::Rect>& out_boxes,
- std::vector<int>& out_labels)
- {
- YoloParams params;
- constexpr auto side_square = 13 * 13;
- this->m_out = in_yolo_result.ptr<float>();
- this->m_side = 13;
- this->m_lcoords = params.coords;
- this->m_lclasses = num_classes;
- std::vector<Detection> detections;
- for (int i = 0; i < side_square; ++i)
- {
- for (int b = 0; b < params.num; ++b)
- {
- float scale = this->scale(i, b);
- if (scale < confidence_threshold)
- {
- continue;
- }
- double x = this->x(i, b);
- double y = this->y(i, b);
- double height = this->height(i, b, anchors[2 * b + 1]);
- double width = this->width(i, b, anchors[2 * b]);
- for (int label = 0; label < num_classes; ++label)
- {
- float prob = scale * classConf(i,b,label);
- if (prob < confidence_threshold)
- {
- continue;
- }
- auto box = toBox(x, y, height, width, in_size);
- detections.emplace_back(Detection(box, prob, label));
- }
- }
- }
- std::stable_sort(std::begin(detections), std::end(detections),
- [](const Detection& a, const Detection& b)
- {
- return a.conf > b.conf;
- });
- if (nms_threshold < 1.0f)
- {
- for (const auto& d : detections)
- {
- if (std::end(out_boxes) ==
- std::find_if(std::begin(out_boxes), std::end(out_boxes),
- [&d, nms_threshold](const cv::Rect& r)
- {
- float rectOverlap = 1.f - static_cast<float>(jaccardDistance(r, d.rect));
- return rectOverlap > nms_threshold;
- }))
- {
- out_boxes. emplace_back(d.rect);
- out_labels.emplace_back(d.label);
- }
- }
- }
- else
- {
- for (const auto& d: detections)
- {
- out_boxes. emplace_back(d.rect);
- out_labels.emplace_back(d.label);
- }
- }
- }
- private:
- struct Detection
- {
- Detection(const cv::Rect& in_rect, const float in_conf, const int in_label)
- : rect(in_rect), conf(in_conf), label(in_label)
- {}
- cv::Rect rect;
- float conf = 0.0f;
- int label = 0;
- };
- struct YoloParams
- {
- int num = 5;
- int coords = 4;
- };
- float scale(const int i, const int b)
- {
- int obj_index = index(i, b, m_lcoords);
- return m_out[obj_index];
- }
- double x(const int i, const int b)
- {
- int box_index = index(i, b, 0);
- int col = i % m_side;
- return (col + m_out[box_index]) / m_side;
- }
- double y(const int i, const int b)
- {
- int box_index = index(i, b, 0);
- int row = i / m_side;
- return (row + m_out[box_index + m_side * m_side]) / m_side;
- }
- double width(const int i, const int b, const float anchor)
- {
- int box_index = index(i, b, 0);
- return std::exp(m_out[box_index + 2 * m_side * m_side]) * anchor / m_side;
- }
- double height(const int i, const int b, const float anchor)
- {
- int box_index = index(i, b, 0);
- return std::exp(m_out[box_index + 3 * m_side * m_side]) * anchor / m_side;
- }
- float classConf(const int i, const int b, const int label)
- {
- int class_index = index(i, b, m_lcoords + 1 + label);
- return m_out[class_index];
- }
- cv::Rect toBox(const double x, const double y, const double h, const double w, const cv::Size& in_sz)
- {
- auto h_scale = in_sz.height;
- auto w_scale = in_sz.width;
- cv::Rect r;
- r.x = static_cast<int>((x - w / 2) * w_scale);
- r.y = static_cast<int>((y - h / 2) * h_scale);
- r.width = static_cast<int>(w * w_scale);
- r.height = static_cast<int>(h * h_scale);
- return r;
- }
- int index(const int i, const int b, const int entry)
- {
- return b * m_side * m_side * (m_lcoords + m_lclasses + 1) + entry * m_side * m_side + i;
- }
- const float* m_out = nullptr;
- int m_side = 0, m_lcoords = 0, m_lclasses = 0;
- };
- } // namespace opencv_test
- #endif // OPENCV_GAPI_PARSERS_TESTS_COMMON_HPP
|