Skip to content

Commit

Permalink
add new cpp dataset resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
MiXaiLL76 committed Jun 23, 2024
1 parent 05f3cca commit 31a6a4c
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 92 deletions.
135 changes: 135 additions & 0 deletions csrc/faster_eval_api/coco_eval/cocoeval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,141 @@ namespace coco_eval
std::vector<ImageEvaluation> result = EvaluateImages(area_ranges, max_detections.back(), iou_thresholds, image_category_ious, image_category_ground_truth_instances, image_category_detection_instances);
return Accumulate(params, result);
}

py::object deepcopy(const py::object &pyobj)
{
auto _pyobj = pyobj;
return _pyobj;
}

void Dataset::append(int64_t img_id, int64_t cat_id, py::dict ann)
{
std::string key = std::to_string(img_id) + "_" + std::to_string(cat_id);
this->data[key].push_back(ann);
}
std::vector<py::dict> Dataset::get(int64_t img_id, int64_t cat_id)
{
std::string key = std::to_string(img_id) + "_" + std::to_string(cat_id);
return this->data[key];
}

InstanceAnnotation parseInstanceAnnotation(const py::dict &ann)
{
uint64_t id = 0;
double score = 0.;
double area = 0.;
bool is_crowd = false;
bool ignore = false;
bool lvis_mark = false;

for (auto it : ann)
{
std::string key = it.first.cast<std::string>();

if (key == "id")
{
id = it.second.cast<uint64_t>();
}
else if (key == "score")
{
score = it.second.cast<double>();
}
else if (key == "area")
{
area = it.second.cast<double>();
}
else if (key == "is_crowd")
{
is_crowd = it.second.cast<bool>();
}
else if (key == "ignore")
{
ignore = it.second.cast<bool>();
}
else if (key == "lvis_mark")
{
lvis_mark = it.second.cast<bool>();
}
}
return InstanceAnnotation(id, score, area, is_crowd, ignore, lvis_mark);
}

std::vector<InstanceAnnotation> Dataset::get_cpp_annotations(
int64_t img_id, int64_t cat_id)
{
std::string key = std::to_string(img_id) + "_" + std::to_string(cat_id);
std::vector<InstanceAnnotation> result;
std::vector<py::dict> anns = get(img_id, cat_id);
for (size_t i = 0; i < anns.size(); i++)
{
result.push_back(parseInstanceAnnotation(anns[i]));
}
return result;
}

std::vector<std::vector<std::vector<InstanceAnnotation>>> Dataset::get_cpp_instances(
std::vector<int64_t> img_ids, std::vector<int64_t> cat_ids, bool useCats)
{
std::vector<std::vector<std::vector<InstanceAnnotation>>> result;
for (size_t i = 0; i < img_ids.size(); i++)
{
int64_t img_id = img_ids[i];
result.push_back(std::vector<std::vector<InstanceAnnotation>>());
if (!useCats)
{
result[i].push_back(std::vector<InstanceAnnotation>());
}

for (size_t j = 0; j < cat_ids.size(); j++)
{
int64_t cat_id = cat_ids[j];

std::vector<InstanceAnnotation> anns = this->get_cpp_annotations(img_id, cat_id);

if (useCats)
{
result[i].push_back(anns);
}
else
{
result[i][0].insert(result[i][0].end(), anns.begin(), anns.end());
}
}
}
return result;
}

std::vector<std::vector<std::vector<py::dict>>> Dataset::get_instances(
std::vector<int64_t> img_ids, std::vector<int64_t> cat_ids, bool useCats)
{
std::vector<std::vector<std::vector<py::dict>>> result;
for (size_t i = 0; i < img_ids.size(); i++)
{
int64_t img_id = img_ids[i];
result.push_back(std::vector<std::vector<py::dict>>());
if (!useCats)
{
result[i].push_back(std::vector<py::dict>());
}

for (size_t j = 0; j < cat_ids.size(); j++)
{
int64_t cat_id = cat_ids[j];

std::vector<py::dict> anns = this->get(img_id, cat_id);

if (useCats)
{
result[i].push_back(anns);
}
else
{
result[i][0].insert(result[i][0].end(), anns.begin(), anns.end());
}
}
}
return result;
}
} // namespace COCOeval

} // namespace coco_eval
20 changes: 20 additions & 0 deletions csrc/faster_eval_api/coco_eval/cocoeval.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ namespace coco_eval
std::vector<bool> detection_ignores;
};

class Dataset
{
public:
Dataset() {}
void append(int64_t img_id, int64_t cat_id, py::dict ann);
std::vector<py::dict> get(int64_t img_id, int64_t cat_id);
std::vector<InstanceAnnotation> get_cpp_annotations(
int64_t img_id, int64_t cat_id);

std::vector<std::vector<std::vector<InstanceAnnotation>>> get_cpp_instances(
std::vector<int64_t> img_ids, std::vector<int64_t> cat_ids, bool useCats);

std::vector<std::vector<std::vector<py::dict>>> get_instances(
std::vector<int64_t> img_ids, std::vector<int64_t> cat_ids, bool useCats);

private:
std::unordered_map<std::string, std::vector<py::dict>> data;
};

template <class T>
using ImageCategoryInstances = std::vector<std::vector<std::vector<T>>>;

Expand Down Expand Up @@ -100,5 +119,6 @@ namespace coco_eval
const ImageCategoryInstances<InstanceAnnotation> &
image_category_detection_instances);

py::object deepcopy(const py::object &pyobj);
} // namespace COCOeval
} // namespace coco_eval
9 changes: 9 additions & 0 deletions csrc/faster_eval_api/faster_eval_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ namespace coco_eval
pybind11::class_<COCOeval::InstanceAnnotation>(m, "InstanceAnnotation").def(pybind11::init<uint64_t, double, double, bool, bool, bool>());
pybind11::class_<COCOeval::ImageEvaluation>(m, "ImageEvaluation").def(pybind11::init<>());

m.def("deepcopy", &COCOeval::deepcopy, "COCOeval::deepcopy");

pybind11::class_<COCOeval::Dataset>(m, "Dataset").def(pybind11::init<>())
.def("append", &COCOeval::Dataset::append)
.def("get", &COCOeval::Dataset::get)
.def("get_instances", &COCOeval::Dataset::get_instances)
.def("get_cpp_annotations", &COCOeval::Dataset::get_cpp_annotations)
.def("get_cpp_instances", &COCOeval::Dataset::get_cpp_instances);

#ifdef VERSION_INFO
m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
#else
Expand Down
2 changes: 0 additions & 2 deletions csrc/mask_api/mask_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ namespace mask_api
m.def("iou", &Mask::iou, "Mask::iou");

m.def("toBbox", &Mask::toBbox, "Mask::toBbox");
// m.def("merge", &Mask::merge, "Mask::merge");
m.def("merge", py::overload_cast<const std::vector<py::dict>&, const uint64_t&>(&Mask::merge), "Mask::merge");
m.def("merge", py::overload_cast<const std::vector<py::dict>&>(&Mask::merge), "Mask::merge");

Expand All @@ -87,7 +86,6 @@ namespace mask_api
m.def("frUncompressedRLE", &Mask::frUncompressedRLE, "Mask::frUncompressedRLE");
m.def("frPyObjects", &Mask::frPyObjects, "Mask::frPyObjects");

m.def("deepcopy", &Mask::deepcopy, "Mask::deepcopy");
#ifdef VERSION_INFO
m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
#else
Expand Down
15 changes: 5 additions & 10 deletions csrc/mask_api/src/mask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,13 @@ namespace mask_api
size_t n = R.size();
if (n > 0)
{

uint64_t s = R[0].h * R[0].w * n;
for (uint64_t i = 0; i < R.size(); i++)
{
uint v = 0;
std::vector<std::vector<uint>> mask(R[i].h, std::vector<uint>(R[i].w));
size_t x=0,y=0,c=0;
size_t x = 0, y = 0, c = 0;
for (uint64_t j = 0; j < R[i].m; j++)
{
for (uint64_t k = 0; k < R[i].cnts[j]; k++)
Expand All @@ -396,7 +396,7 @@ namespace mask_api
{
throw std::range_error("Invalid RLE mask representation");
}
y+=1;
y += 1;

if (y >= R[i].h)
{
Expand Down Expand Up @@ -858,17 +858,13 @@ namespace mask_api
printf("crowd_length=%zu, n=%zu\n", crowd_length, n);
throw std::out_of_range("iscrowd must have the same length as gt");
}
if (m == 0 || n == 0){
if (m == 0 || n == 0)
{
return std::vector<double>(0);
}
return py::array(iou.size(), iou.data()).reshape({m, n});
}

py::object deepcopy(const py::object &pyobj){
auto _pyobj = pyobj;
return _pyobj;
}

std::variant<pybind11::dict, std::vector<pybind11::dict>> frPyObjects(const py::object &pyobj, const uint64_t &h, const uint64_t &w)
{
std::vector<RLE> rles;
Expand Down Expand Up @@ -930,7 +926,6 @@ namespace mask_api

return _toString(rles);
}

} // namespace Mask

}
6 changes: 1 addition & 5 deletions csrc/mask_api/src/mask.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ namespace mask_api

namespace Mask
{
typedef std::list<double> bbox;

struct RLE
{
RLE(
Expand Down Expand Up @@ -50,7 +48,7 @@ namespace mask_api
// pyx functions
py::array_t<uint, py::array::f_style> decode(const std::vector<py::dict> &R);
std::vector<py::dict> encode(const py::array_t<uint, py::array::f_style> &M);

py::array_t<double> toBbox(const std::vector<py::dict> &R);
py::dict merge(const std::vector<py::dict> &rleObjs, const uint64_t &intersect);
py::dict merge(const std::vector<py::dict> &rleObjs);
Expand All @@ -66,7 +64,5 @@ namespace mask_api
std::vector<py::dict> rleToUncompressedRLE(const std::vector<RLE> &R);
py::array_t<double> rleToBbox(const std::vector<RLE> R, const uint64_t &n);
std::variant<pybind11::dict, std::vector<pybind11::dict>> frPyObjects(const py::object &pyobj, const uint64_t &h, const uint64_t &w);

py::object deepcopy(const py::object &pyobj);
} // namespace Mask
} // namespace mask_api
18 changes: 7 additions & 11 deletions faster_coco_eval/core/coco.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

import numpy as np

import faster_coco_eval.faster_eval_api_cpp as _C

from . import mask as maskUtils

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -88,7 +90,7 @@ def __init__(self, annotation_file=None):
if type(annotation_file) is str:
self.dataset = self.load_json(annotation_file)
elif type(annotation_file) is dict:
self.dataset = maskUtils.deepcopy(annotation_file)
self.dataset = _C.deepcopy(annotation_file)
else:
self.dataset = None

Expand Down Expand Up @@ -338,7 +340,7 @@ def loadRes(self, resFile, min_score=0):
elif type(resFile) is np.ndarray:
anns = self.loadNumpyAnnotations(resFile)
else:
anns = maskUtils.deepcopy(resFile)
anns = _C.deepcopy(resFile)

assert type(anns) is list, "results in not an array of objects"

Expand All @@ -358,9 +360,7 @@ def loadRes(self, resFile, min_score=0):
for id, ann in enumerate(anns):
ann["id"] = id + 1
elif "bbox" in anns[0] and not anns[0]["bbox"] == []:
res.dataset["categories"] = maskUtils.deepcopy(
self.dataset["categories"]
)
res.dataset["categories"] = _C.deepcopy(self.dataset["categories"])
for id, ann in enumerate(anns):
bb = ann["bbox"]
x1, x2, y1, y2 = [bb[0], bb[0] + bb[2], bb[1], bb[1] + bb[3]]
Expand All @@ -370,9 +370,7 @@ def loadRes(self, resFile, min_score=0):
ann["id"] = id + 1
ann["iscrowd"] = 0
elif "segmentation" in anns[0]:
res.dataset["categories"] = maskUtils.deepcopy(
self.dataset["categories"]
)
res.dataset["categories"] = _C.deepcopy(self.dataset["categories"])
for id, ann in enumerate(anns):
# now only support compressed RLE format as segmentation results
ann["area"] = maskUtils.area(ann["segmentation"])
Expand All @@ -381,9 +379,7 @@ def loadRes(self, resFile, min_score=0):
ann["id"] = id + 1
ann["iscrowd"] = 0
elif "keypoints" in anns[0]:
res.dataset["categories"] = maskUtils.deepcopy(
self.dataset["categories"]
)
res.dataset["categories"] = _C.deepcopy(self.dataset["categories"])
for id, ann in enumerate(anns):
s = ann["keypoints"]
x = s[0::3]
Expand Down
Loading

0 comments on commit 31a6a4c

Please sign in to comment.