#include <algorithm>
#include <csignal>
#include <ctime>
#include <functional>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "boost/iterator/counting_iterator.hpp"
#include "caffe/util/bbox_util.hpp"
namespace caffe {
bool SortBBoxAscend(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2) {
return bbox1.score() < bbox2.score();
}
bool SortBBoxDescend(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2) {
return bbox1.score() > bbox2.score();
}
template <typename T>
bool SortScorePairAscend(const pair<float, T>& pair1,
const pair<float, T>& pair2) {
return pair1.first < pair2.first;
}
// Explicit initialization.
template bool SortScorePairAscend(const pair<float, int>& pair1,
const pair<float, int>& pair2);
template bool SortScorePairAscend(const pair<float, pair<int, int> >& pair1,
const pair<float, pair<int, int> >& pair2);
template <typename T>
bool SortScorePairDescend(const pair<float, T>& pair1,
const pair<float, T>& pair2) {
return pair1.first > pair2.first;
}
// Explicit initialization.
template bool SortScorePairDescend(const pair<float, int>& pair1,
const pair<float, int>& pair2);
template bool SortScorePairDescend(const pair<float, pair<int, int> >& pair1,
const pair<float, pair<int, int> >& pair2);
NormalizedBBox UnitBBox() {
NormalizedBBox unit_bbox;
unit_bbox.set_xmin(0.);
unit_bbox.set_ymin(0.);
unit_bbox.set_xmax(1.);
unit_bbox.set_ymax(1.);
return unit_bbox;
}
bool IsCrossBoundaryBBox(const NormalizedBBox& bbox) {
return bbox.xmin() < 0 || bbox.xmin() > 1 ||
bbox.ymin() < 0 || bbox.ymin() > 1 ||
bbox.xmax() < 0 || bbox.xmax() > 1 ||
bbox.ymax() < 0 || bbox.ymax() > 1;
}
void IntersectBBox(const NormalizedBBox& bbox1, const NormalizedBBox& bbox2,
NormalizedBBox* intersect_bbox) {
if (bbox2.xmin() > bbox1.xmax() || bbox2.xmax() < bbox1.xmin() ||
bbox2.ymin() > bbox1.ymax() || bbox2.ymax() < bbox1.ymin()) {
// Return [0, 0, 0, 0] if there is no intersection.
intersect_bbox->set_xmin(0);
intersect_bbox->set_ymin(0);
intersect_bbox->set_xmax(0);
intersect_bbox->set_ymax(0);
} else {
intersect_bbox->set_xmin(std::max(bbox1.xmin(), bbox2.xmin()));
intersect_bbox->set_ymin(std::max(bbox1.ymin(), bbox2.ymin()));
intersect_bbox->set_xmax(std::min(bbox1.xmax(), bbox2.xmax()));
intersect_bbox->set_ymax(std::min(bbox1.ymax(), bbox2.ymax()));
}
}
float BBoxSize(const NormalizedBBox& bbox, const bool normalized) {
if (bbox.xmax() < bbox.xmin() || bbox.ymax() < bbox.ymin()) {
// If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0.
return 0;
} else {
if (bbox.has_size()) {
return bbox.size();
} else {
float width = bbox.xmax() - bbox.xmin();
float height = bbox.ymax() - bbox.ymin();
if (normalized) {
return width * height;
} else {
// If bbox is not within range [0, 1].
return (width + 1) * (height + 1);
}
}
}
}
template <typename Dtype>
Dtype BBoxSize(const Dtype* bbox, const bool normalized) {
if (bbox[2] < bbox[0] || bbox[3] < bbox[1]) {
// If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0.
return Dtype(0.);
} else {
const Dtype width = bbox[2] - bbox[0];
const Dtype height = bbox[3] - bbox[1];
if (normalized) {
return width * height;
} else {
// If bbox is not within range [0, 1].
return (width + 1) * (height + 1);
}
}
}
template float BBoxSize(const float* bbox, const bool normalized);
template double BBoxSize(const double* bbox, const bool normalized);
void ClipBBox(const NormalizedBBox& bbox, NormalizedBBox* clip_bbox) {
clip_bbox->set_xmin(std::max(std::min(bbox.xmin(), 1.f), 0.f));
clip_bbox->set_ymin(std::max(std::min(bbox.ymin(), 1.f), 0.f));
clip_bbox->set_xmax(std::max(std::min(bbox.xmax(), 1.f), 0.f));
clip_bbox->set_ymax(std::max(std::min(bbox.ymax(), 1.f), 0.f));
clip_bbox->clear_size();
clip_bbox->set_size(BBoxSize(*clip_bbox));
clip_bbox->set_difficult(bbox.difficult());
}
void ClipBBox(const NormalizedBBox& bbox, const float height, const float width,
NormalizedBBox* clip_bbox) {
clip_bbox->set_xmin(std::max(std::min(bbox.xmin(), width), 0.f));
clip_bbox->set_ymin(std::max(std::min(bbox.ymin(), height), 0.f));
clip_bbox->set_xmax(std::max(std::min(bbox.xmax(), width), 0.f));
clip_bbox->set_ymax(std::max(std::min(bbox.ymax(), height), 0.f));
clip_bbox->clear_size();
clip_bbox->set_size(BBoxSize(*clip_bbox));
clip_bbox->set_difficult(bbox.difficult());
}
void ScaleBBox(const NormalizedBBox& bbox, const int height, const int width,
NormalizedBBox* scale_bbox) {
scale_bbox->set_xmin(bbox.xmin() * width);
scale_bbox->set_ymin(bbox.ymin() * height);
scale_bbox->set_xmax(bbox.xmax() * width);
scale_bbox->set_ymax(bbox.ymax() * height);
scale_bbox->clear_size();
bool normalized = !(width > 1 || height > 1);
scale_bbox->set_size(BBoxSize(*scale_bbox, normalized));
scale_bbox->set_difficult(bbox.difficult());
}
void OutputBBox(const NormalizedBBox& bbox, const pair<int, int>& img_size,
const bool has_resize, const ResizeParameter& resize_param,
NormalizedBBox* out_bbox) {
const int height = img_size.first;
const int width = img_size.second;
NormalizedBBox temp_bbox = bbox;
if (has_resize && resize_param.resize_mode()) {
float resize_height = resize_param.height();
CHECK_GT(resize_height, 0);
float resize_width = resize_param.width();
CHECK_GT(resize_width, 0);
float resize_aspect = resize_width / resize_height;
int height_scale = resize_param.height_scale();
int width_scale = resize_param.width_scale();
float aspect = static_cast<float>(width) / height;
float padding;
NormalizedBBox source_bbox;
switch (resize_param.resize_mode()) {
case ResizeParameter_Resize_mode_WARP:
ClipBBox(temp_bbox, &temp_bbox);
ScaleBBox(temp_bbox, height, width, out_bbox);
break;
case ResizeParameter_Resize_mode_FIT_LARGE_SIZE_AND_PAD:
if (aspect > resize_aspect) {
padding = (resize_height - resize_width / aspect) / 2;
source_bbox.set_xmin(0.);
source_bbox.set_ymin(padding / resize_height);
source_bbox.set_xmax(1.);
source_bbox.set_ymax(1. - padding / resize_height);
} else {
padding = (resize_width - resize_height * aspect) / 2;
source_bbox.set_xmin(padding / resize_width);
source_bbox.set_ymin(0.);
source_bbox.set_xmax(1. - padding / resize_width);
source_bbox.set_ymax(1.);
}
ProjectBBox(source_bbox, bbox, &temp_bbox);
ClipBBox(temp_bbox, &temp_bbox);
ScaleBBox(temp_bbox, height, width, out_bbox);
break;
case ResizeParameter_Resize_mode_FIT_SMALL_SIZE:
if (height_scale == 0 || width_scale == 0) {
ClipBBox(temp_bbox, &temp_bbox);
ScaleBBox(temp_bbox, height, width, out_bbox);
} else {
ScaleBBox(temp_bbox, height_scale, width_scale, out_bbox);
ClipBBox(*out_bbox, height, width, out_bbox);
}
break;
default:
LOG(FATAL) << "Unknown resize mode.";
}
} else {
// Clip the normalized bbox first.
ClipBBox(temp_bbox, &temp_bbox);
// Scale the bbox according to the original image size.
ScaleBBox(temp_bbox, height, width, out_bbox);
}
}
void LocateBBox(const NormalizedBBox& src_bbox, const NormalizedBBox& bbox,
NormalizedBBox* loc_bbox) {
float src_width = src_bbox.xmax() - src_bbox.xmin();
float src_height = src_bbox.ymax() - src_bbox.ymin();
loc_bbox->set_xmin(src_bbox